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 26
/
generic_models.py
325 lines (283 loc) · 14.5 KB
/
generic_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
from datetime import datetime
from django.utils.translation import ugettext_lazy as _
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.conf import settings
from cms.models.fields import PlaceholderField
from filer.fields.image import FilerImageField
from arkestra_utilities.settings import PLUGIN_HEADING_LEVELS, PLUGIN_HEADING_LEVEL_DEFAULT
from links.models import ObjectLink
from contacts_and_people.models import Entity, Person
from contacts_and_people.templatetags.entity_tags import work_out_entity
class ArkestraGenericModel(models.Model):
class Meta:
abstract = True
# core fields
title = models.CharField(max_length=255,
help_text="e.g. Outrage as man bites dog in unprovoked attack")
short_title = models.CharField(max_length=255, null=True, blank=True,
help_text= u"e.g. Man bites dog (if left blank, will be copied from Title)")
summary = models.TextField(verbose_name="Summary",
null=False, blank=False,
help_text="e.g. Cardiff man arrested in latest wave of man-on-dog violence (maximum two lines)")
published = models.BooleanField(default=False, verbose_name=_(u"Is published"), db_index=True,
help_text=_(u"Select when ready to be published"))
in_lists = models.BooleanField(_(u"Display in lists"), default=True, db_index=True,
help_text=_(u"If deselected, this item will not appear in lists"))
body = PlaceholderField('body', help_text="Not used or required for external items")
image = FilerImageField(on_delete=models.SET_NULL, null=True, blank=True)
# universal plugin fields
hosted_by = models.ForeignKey(Entity,
on_delete=models.SET_DEFAULT,
default=Entity.objects.default_entity_id(),
related_name='%(class)s_hosted_events', null=True, blank=True,
help_text=u"The entity responsible for publishing this item")
publish_to = models.ManyToManyField(
Entity, verbose_name="Also publish to",
null=True, blank=True,
related_name="%(class)s_publish_to",
help_text=u"Use these sensibly - don't send minor items to the home page, for example.",
)
please_contact = models.ManyToManyField(Person, related_name='%(class)s_person',
help_text=u"The person to whom enquiries about this should be directed",
null=True, blank=True)
IMPORTANCES = (
(0, u"Normal"),
(1, u"More important"),
(10, u"Most important"),
)
importance = models.PositiveIntegerField(null=True, blank=False,
default=0, choices=IMPORTANCES,
help_text=u"Important items will be featured in lists")
@property
def has_expired(self):
# the item is too old to appear in current lists, and should only be listed in archives
return False
@property
def get_importance(self):
if self.importance: # if they are not being gathered together, mark them as important
return "important"
else:
return ""
@property
def get_hosted_by(self):
return self.hosted_by or Entity.objects.base_entity()
@property
def get_template(self):
if self.get_hosted_by:
return self.get_hosted_by.get_template()
else:
return settings.CMS_TEMPLATES[0][0]
@property
def get_entity(self):
"""
Real-world information, can be None
"""
return self.hosted_by or Entity.objects.get(id=Entity.objects.base_entity())
@property
def links(self):
model = ContentType.objects.get_for_model(self)
# print model, self.id
links = ObjectLink.objects.filter(content_type__pk=model.id, object_id = self.id).order_by('destination_content_type')
# print "links", links
return links
@property
def external_url(self):
# if the inheriting model doesn't have an external_url attribute, we'll give it a None one just in case this is needed
return None
@property
def is_uninformative(self):
if self.external_url or self.body.cmsplugin_set.all() or self.please_contact.all() or self.links:
return False
else:
return True
class ArkestraGenericPluginOptions(models.Model):
class Meta:
abstract = True
entity = models.ForeignKey(Entity,
on_delete=models.SET_NULL,
null=True, blank=True,
help_text="Leave blank for autoselect",
related_name="%(class)s_plugin")
LAYOUTS = (
("sidebyside", u"Side-by-side"),
("stacked", u"Stacked"),
)
layout = models.CharField("Plugin layout", max_length=25, choices = LAYOUTS, default = "sidebyside")
FORMATS = (
("title", u"Title only"),
("details image", u"Details"),
)
format = models.CharField("Item format", max_length=25,choices = FORMATS, default = "details image")
heading_level = models.PositiveSmallIntegerField(choices = PLUGIN_HEADING_LEVELS, default = PLUGIN_HEADING_LEVEL_DEFAULT)
ORDERING = (
("date", u"Date alone"),
("importance/date", u"Importance & date"),
)
order_by = models.CharField(max_length = 25, choices=ORDERING, default="importance/date")
LIST_FORMATS = (
("vertical", u"Vertical"),
("horizontal", u"Horizontal"),
)
list_format = models.CharField("List format", max_length = 25, choices=LIST_FORMATS, default="vertical")
group_dates = models.BooleanField("Show date groups", default = True)
limit_to = models.PositiveSmallIntegerField("Maximum number of items", default = 5, null = True, blank = True,
help_text = u"Leave blank for no limit")
def sub_heading_level(self): # requires that we change 0 to None in the database
if self.heading_level == None: # this means the user has chosen "No heading"
return 6 # we need to give sub_heading_level a value
else:
return self.heading_level + 1 # so if headings are h3, sub-headings are h4
class ArkestraGenericPluginForm(object):
def clean(self):
super(ArkestraGenericPluginForm, self).clean()
if "horizontal" in self.cleaned_data["list_format"]:
self.cleaned_data["order_by"] = "importance/date"
self.cleaned_data["format"] = "details image"
self.cleaned_data["layout"] = "stacked"
self.cleaned_data["group_dates"] = False
if self.cleaned_data["limit_to"] >3:
self.cleaned_data["limit_to"] = 3
if self.cleaned_data["limit_to"] < 2:
self.cleaned_data["limit_to"] = 2
if self.cleaned_data["limit_to"] == 0: # that's a silly number, and interferes with the way we calculate later
self.cleaned_data["limit_to"] = None
return self.cleaned_data
class ArkestraGenericPlugin(object):
text_enabled = True
admin_preview = False
# default render_template - change it in your ArkestraGenericPlugin if required
render_template = "arkestra/universal_plugin_lister.html"
# def __init__(self, model = None, admin_site = None):
# super(ArkestraGenericPlugin, self).__init__(model, admin_site)
def set_defaults(self, instance):
# set defaults
# ** important ** - these are set only when the render() function is called
# this means that when the plugin is invoked (as in contacts_and_people.Building.evets()
# it is necessary to set these values manually)
instance.display = getattr(instance, "display", "")
instance.view = getattr(instance, "view", "current")
instance.list_format = getattr(instance, "list_format", "vertical")
instance.layout = getattr(instance, "layout", "")
instance.limit_to = getattr(instance, "limit_to", None)
instance.group_dates = getattr(instance, "group_dates", True)
instance.format = getattr(instance, "format", "details image")
instance.type = getattr(instance, "type", "plugin") # assume it's a plugin unless otherwise stated
instance.order_by = getattr(instance, "order_by", "")
instance.heading_level = getattr(instance, "heading_level", PLUGIN_HEADING_LEVEL_DEFAULT)
instance.type = getattr(instance, "type", "plugin")
# print "---- plugin settings ----"
# print "self.display", instance.display
# print "self.view", instance.view
# print "self.group_dates", instance.group_dates
# print "self.format", instance.format
# print "self.list_format", instance.list_format
# print "self.order_by", instance.order_by
# print "self.limit_to", instance.limit_to
# print "self.layout", instance.layout
# print "self.heading_level", instance.heading_level
return
def add_link_to_main_page(self, instance):
# only plugins and sub_pages need a link to the main page
if instance.type == "plugin" or instance.type == "sub_page":
# do any of models referred to by this instance have items and is entity.menu_cues["auto_page_attribute"] (e.g. entity.auto_news_page) True?
# menu_cues is this application's menu_dict
if (any(d['items'] for d in self.lists)) and \
getattr(instance.entity, getattr(self, "menu_cues", {}).get("auto_page_attribute", ""), False):
# set the url attribute of the link to the main page
instance.link_to_main_page = instance.entity.get_related_info_page_url(self.menu_cues["url_attribute"])
# set the title of the link
instance.main_page_name = getattr(instance.entity, self.menu_cues["title_attribute"])
# def print_settings(self):
# print "---- plugin settings ----"
# print "self.display", self.display
# print "self.view", self.view
# print "self.order_by", self.order_by
# print "self.group_dates", self.group_dates
# print "self.format", self.format
# print "self.list_format", self.list_format
# print "self.limit_to", self.limit_to
# print "self.layout", self.layout
def add_links_to_other_items(self, instance):
if instance.type == "main_page" or instance.type == "sub_page" or instance.type == "menu":
for this_list in self.lists:
# does this list have a function specified that will add the links we need to other items?
if this_list.get("links_to_other_items"):
# call that function
this_list["links_to_other_items"](instance, this_list)
def set_limits_and_indexes(self, instance):
for this_list in self.lists:
# if a plugin or a main page or menu, eliminate expired items
if instance.view == "current" and instance.type in ["plugin", "main_page", "menu"]:
this_list["items"] = [item for item in this_list["items"] if not item.has_expired]
# cut the list down to size if necessary
if this_list["items"] and len(this_list["items"]) > instance.limit_to:
this_list["items"] = this_list["items"][:instance.limit_to]
# gather non-top items into a list to be indexed
this_list["index_items"] = [item for item in this_list["items"] if not getattr(item, 'sticky', False)]
# extract a list of dates for the index
this_list["no_of_get_whens"] = len(set(getattr(item, "get_when", None) for item in this_list["items"]))
# more than one date in the list: show an index
if instance.type == "sub_page" and this_list["no_of_get_whens"] > 1:
this_list["index"] = True
# we only show date groups when warranted
this_list["show_when"] = instance.group_dates and not ("horizontal" in instance.list_format or this_list["no_of_get_whens"] < 2)
def determine_layout_settings(self, instance):
"""
Sets:
list_format
"""
# set columns for horizontal lists
if "horizontal" in instance.list_format:
instance.list_format = "row columns" + str(instance.limit_to) + " " + instance.list_format
for this_list in self.lists:
this_list["items"] = list(this_list["items"])
if this_list["items"]:
for item in this_list["items"]:
item.column_class = "column"
if this_list["items"]:
this_list["items"][0].column_class = this_list["items"][0].column_class + " firstcolumn"
if len(this_list["items"]) > 1:
this_list["items"][-1].column_class = this_list["items"][-1].column_class + " lastcolumn"
elif "vertical" in instance.list_format:
instance.list_format = "vertical"
def set_layout_classes(self, instance):
"""
Lays out the plugin's divs
"""
instance.row_class="row"
# if divs will be side-by-side
if instance.layout == "sidebyside":
if len(self.lists) > 1:
instance.row_class=instance.row_class+" columns" + str(len(self.lists))
self.lists[0]["div_class"] = "column firstcolumn"
self.lists[-1]["div_class"] = "column lastcolumn"
# if just one, and it needs an index
else:
for this_list in self.lists:
if this_list.get("index"):
instance.row_class=instance.row_class+" columns3"
instance.index_div_class = "column lastcolumn"
this_list["div_class"] = "column firstcolumn doublecolumn"
# and if it doesn't need an index
else:
instance.row_class=instance.row_class+" columns1"
def get_items(self, instance):
self.lists = []
def render(self, context, instance, placeholder):
instance.entity = getattr(instance, "entity", None) or work_out_entity(context, None)
self.set_defaults(instance)
self.get_items(instance)
self.add_link_to_main_page(instance)
self.add_links_to_other_items(instance)
self.set_limits_and_indexes(instance)
self.determine_layout_settings(instance)
self.set_layout_classes(instance)
instance.lists = self.lists
context.update({
'everything': instance,
'placeholder': placeholder,
})
return context
def icon_src(self, instance):
return "/static/plugin_icons/generic.png"