This repository has been archived by the owner on Mar 5, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27
/
models.py
442 lines (385 loc) · 15.1 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
from django.utils.translation import ugettext_lazy as _
from datetime import datetime
from datetime import date as pythondate
from django.db import models
from django.db.models import Q
from django.db.models.signals import post_save
from django.template.defaultfilters import date, time, slugify
import mptt
from cms.models import CMSPlugin
from contacts_and_people.models import Person, Building
from arkestra_utilities.output_libraries.dates import nice_date
from arkestra_utilities.generic_models import ArkestraGenericPluginOptions, ArkestraGenericModel
from arkestra_utilities.mixins import URLModelMixin, LocationModelMixin
from arkestra_utilities.settings import COLLECT_TOP_ALL_FORTHCOMING_EVENTS, ARKESTRA_DATE_FORMATS, AGE_AT_WHICH_ITEMS_EXPIRE
from managers import NewsArticleManager, EventManager
class NewsAndEvents(ArkestraGenericModel, URLModelMixin):
content = models.TextField(null=True, blank=True,
help_text="Not used or required for external items")
class Meta:
abstract = True
def save(self, *args, **kwargs):
super(NewsAndEvents, self).save(*args, **kwargs)
auto_page_view_name = "news-and-events"
class NewsArticle(NewsAndEvents):
objects = NewsArticleManager()
view_name = "news"
date = models.DateTimeField(
default=datetime.now,
help_text=u"""
Dateline for the item (the item will not be published until then
"""
)
display_indefinitely = models.BooleanField(
help_text=u"Important news; it won't expire from news lists"
)
external_news_source = models.ForeignKey(
'NewsSource',
null=True,
blank=True,
help_text=u"If this news item is from an external source"
)
sticky_until = models.DateField(
u"Featured until",
null=True,
blank=True,
default=pythondate.today,
help_text=u"Will remain a featured item until this date"
)
is_sticky_everywhere = models.BooleanField(
u"Featured everywhere",
default=False,
help_text=u"Will be featured in other entities's news lists"
)
class Meta:
ordering = ['-date']
@property
def has_expired(self):
# the item is too old to appear in current lists, and should only be
# listed in archives
age = datetime.now() - self.date
if AGE_AT_WHICH_ITEMS_EXPIRE and age.days > AGE_AT_WHICH_ITEMS_EXPIRE:
return True
@property
def get_when(self):
"""
get_when provides a human-readable attribute under which items can be
grouped. Usually, this is an easily-readble rendering of the date (e.g.
"April 2010") but it can also be "Top news", for items to be given
special prominence.
"""
if getattr(self, "sticky", None):
return "Top news"
get_when = nice_date(self.date, ARKESTRA_DATE_FORMATS["date_groups"])
return get_when
class Event(NewsAndEvents, LocationModelMixin):
objects = EventManager()
view_name = "event"
type = models.ForeignKey(
'EventType',
on_delete=models.PROTECT
)
featuring = models.ManyToManyField(
Person,
related_name='%(class)s_featuring',
null=True,
blank=True,
help_text="The speakers, lecturers, instructors or other people featured in this event"
)
parent = models.ForeignKey(
'self',
blank=True,
null=True,
on_delete=models.PROTECT,
related_name='children'
)
SERIES = (
(False, u"an actual event"),
(True, u"a series of events"),
)
series = models.BooleanField("This is", default=False, choices=SERIES)
SHOW_TITLES = (
("series children", u"show title of series followed by title of children"),
("series", u"show title of series only"),
("children", u"show title of children only"),
)
show_titles = models.CharField(
u"Titles",
max_length = 25,
default="children",
choices=SHOW_TITLES,
)
DISPLAY_SERIES_SUMMARY = (
(False, u"display children's summaries"),
(True, u"display the summary for the series"),
)
display_series_summary = models.BooleanField(u"Summaries",
default=False,
choices=DISPLAY_SERIES_SUMMARY,
)
child_list_heading = models.CharField(
max_length=50,
blank=True,
help_text= u"e.g. Conference sessions; Lectures in this series")
date = models.DateField(
"Start date",
null=True,
blank=True,
help_text=u"Not required for a series of events"
)
start_time = models.TimeField(null=True, blank=True)
end_date = models.DateField(null=True, blank=True)
end_time = models.TimeField(null=True, blank=True)
single_day_event = models.BooleanField(default=False)
building = models.ForeignKey(
Building,
null=True, blank=True,
on_delete=models.SET_NULL
)
jumps_queue_on = models.DateField(
null=True,
blank=True,
help_text=u"Will become a featured item on this date"
)
jumps_queue_everywhere = models.BooleanField(default=False)
registration_enquiries = models.ManyToManyField(
Person,
related_name = '%(class)s_registration',
null = True, blank = True,
help_text=u"The people who responsible for registration, if different from those in <em>Please contact</em>"
)
class Meta:
ordering = ['date', 'start_time']
@property
def informative_url(self):
"""
An event has an 'informative_url' if it itself is uninformative, but it
is a child of a series
"""
# print
# print "========================================"
# print "checking", self
# print "is_uninformative", self.is_uninformative
# print "self.parent", self.parent
#
if self.is_uninformative and self.parent and self.parent.series:
# print self, "parent!"
return self.parent.get_absolute_url()
else:
# print self, "self!"
return self.get_absolute_url()
@property
def show_parent_series(self):
"""
checks whether we should show the parent series too in lists
"""
if self.parent and self.parent.series:
return self.parent.show_titles
@property
def is_uninformative(self):
# print
# print "============================"
# print self.body
# if self.body:
# print 1, self.body.cmsplugin_set.all()
# print 2, self.external_url
# print 3, self.please_contact.all()
# print 4, self.registration_enquiries.all()
# print "----------------------------"
if self.body and self.body.cmsplugin_set.all() or self.external_url or self.please_contact.all() or self.registration_enquiries.all(): # or self.links_set.all():
# print "uninformative"
return False
else:
# print "informative"
return True
def save(self):
def slug_is_bad(self):
if self.slug in [slug.values()[0] for slug in Event.objects.exclude(id=self.id).values("slug")]:
return True
if self.slug == "" or slug_is_bad(self):
self.slug=slugify(self.short_title)
if slug_is_bad(self):
suffix = slugify(date(self.date, "Y"))
if not suffix in self.slug:
self.slug = self.slug + "-" + suffix
# print "adding suffix:", suffix, self.slug
if slug_is_bad(self):
suffix = slugify(date(self.date, "F"))
if not suffix in self.slug:
self.slug = self.slug + "-" + suffix
# print "adding suffix:", suffix, self.slug
if slug_is_bad(self):
suffix = slugify(date(self.date, "d"))
if not suffix in self.slug:
self.slug = self.slug + "-" + suffix
# print "adding suffix:", suffix, self.slug
while slug_is_bad(self):
self.slug=self.slug + "-x"
# print "adding suffix:", "-x"
super(Event, self).save()
def get_children_forthcoming(self):
if self.series:
return self.children.filter(
Q(date__gte = datetime.now()) |
Q(end_date__gte = datetime.now()) |
Q(series = True)
).order_by('date')
else:
return self.children.all()
def get_children_previous(self):
if self.series:
return self.children.filter(
Q(date__lt = datetime.now()) |
Q(end_date__lt = datetime.now()) |
Q(series = True)
).order_by('-date'
)
def get_featuring(self, featuring = None):
featuring = set(self.featuring.all()) or set()
if not self.series:
for child_event in self.children.all():
featuring.update(child_event.get_featuring(featuring))
return featuring
def get_date_if_needed_and_time_heading(self):
date_time_heading = []
if not self.series:
if not self.parent.single_day_event:
date_time_heading.append("date")
if self.get_times():
date_time_heading.append("time")
return date_time_heading
def get_date_if_needed_and_time(self):
date_and_time = []
date = self.get_dates()
time = self.get_times()
if self.parent and self.parent.single_day_event and not time:
date_and_time.append(date)
if time:
date_and_time.append(time)
return date_and_time
def get_dates(self):
if not self.series:
date = self.date
end_date = self.end_date
if not end_date or self.single_day_event:
end_date = date
date_format = end_date_format = ARKESTRA_DATE_FORMATS["not_this_year"]
now = datetime.now()
if date.year == end_date.year: # start and end in the same year, so:
date_format = ARKESTRA_DATE_FORMATS["not_this_month"] # start format example: "3rd May"
if date.month == end_date.month: # start and end in the same month, so:
date_format = ARKESTRA_DATE_FORMATS["this_month"] # start format example: "21st"
if end_date.year == now.year: # they're both this year, so:
end_date_format = ARKESTRA_DATE_FORMATS["not_this_month"] # end format example: "23rd May"
if self.single_day_event:
dates = nice_date(date, end_date_format)
else:
dates = nice_date(date, date_format) + unicode(_(u" to ")) + nice_date(end_date, end_date_format)
return dates
else:
return "Series"
def get_times(self):
start_time = self.start_time
if self.single_day_event and start_time:
end_time = self.end_time
if end_time:
times = time(start_time) + "‑" + time(end_time)
else:
times = time(start_time)
return times
def get_image(self):
return self.image or (self.parent.get_image() if self.parent else None)
def check_date(self):
# we need somehow to send a message to the user about this
if not self.children.all():
return
else:
for child in self.children.all():
need_to_save = False
child.check_date()
if child.date and not self.series:
child.check_date()
# we start at the leaves and work backwards, so we can
# assume all descendants are OK
if (not self.date) or (self.date > child.date):
self.date = child.date
need_to_save = True
if not self.end_date:
self.end_date = self.date
child_end_date = child.end_date
if not child_end_date:
child_end_date = child.date
if self.end_date < child_end_date:
self.end_date = child_end_date
need_to_save = True
if need_to_save:
self.single_day_event = False
self.save()
return
def apply_parent_attributes(self): # is this required?
print "we're in event.apply_parent_attributes - the question is why"
if self.parent:
self.enquiries = set(self.parent.enquiries.all())
self.save()
return
@property
def calculated_summary(self):
if self.parent and self.parent.display_series_summary:
return self.parent.summary
else:
return self.summary
@property
def get_when(self):
if self.date:
if getattr(self, "sticky", None):
return "Top events"
#return self.date
#now = datetime.now()
date_format = "F Y" # Aikido Cardiff version
# date_format = "F Y" # standard version
#if self.date.year == now.year: # they're both this year, so:
# date_format = "F" # end format example: "23rd May"
return date(self.date, date_format)
#This is the old method of grouping items
#diff = self.date - datetime.now().date()
#tddict = {999999999: 'Next month & beyond', 31:'This month', 7: 'This week', }
#tdlist = sorted(tddict.keys())
#when_heading = tddict[tdlist[bisect.bisect(tdlist, diff.days)]]
#return when_heading
elif self.series:
return "Regular events"
def get_admin_title(self):
return self.title + " (" + self.get_dates() + ")"
class EventType(models.Model):
event_type = models.CharField(max_length=50)
class Meta:
ordering = ['event_type']
def __unicode__(self):
return self.event_type
class NewsSource(models.Model):
external_news_source = models.CharField(max_length=50)
def __unicode__(self):
return self.external_news_source
def receiver_function(sender, **kwargs):
event = kwargs['instance']
event.get_root().check_date()
post_save.connect(receiver_function, sender = Event)
class NewsAndEventsPlugin(CMSPlugin, ArkestraGenericPluginOptions):
DISPLAY = (
("news & events", u"News and events"),
("news", u"News only"),
("events", u"Events only"),
)
display = models.CharField(
"Show",
max_length=25,
choices=DISPLAY,
default="news & events"
)
show_previous_events = models.BooleanField()
news_heading_text = models.CharField(max_length=25, default=_(u"News"))
events_heading_text = models.CharField(max_length=25, default=_(u"Events"))
try:
mptt.register(Event)
except mptt.AlreadyRegistered:
pass