modules.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. import json
  2. from django import forms
  3. from django.contrib.admin.models import LogEntry
  4. from django.db.models import Q
  5. from django.template.loader import render_to_string
  6. from django.utils.translation import ugettext_lazy as _
  7. from jet.utils import get_app_list, DateTimeEncoder
  8. import datetime
  9. class DashboardModule(object):
  10. template = 'jet/dashboard/module.html'
  11. enabled = True
  12. draggable = True
  13. collapsible = True
  14. deletable = True
  15. show_title = True
  16. title = ''
  17. title_url = None
  18. css_classes = None
  19. pre_content = None
  20. post_content = None
  21. children = None
  22. settings_form = None
  23. child_form = None
  24. child_name = None
  25. child_name_plural = None
  26. settings = None
  27. column = None
  28. order = None
  29. ajax_load = False
  30. contrast = False
  31. class Media:
  32. css = ()
  33. js = ()
  34. def __init__(self, title=None, model=None, context=None, **kwargs):
  35. if title is not None:
  36. self.title = title
  37. self.model = model
  38. self.context = context or {}
  39. for key in kwargs:
  40. if hasattr(self.__class__, key):
  41. setattr(self, key, kwargs[key])
  42. self.children = self.children or []
  43. if self.model:
  44. self.load_from_model()
  45. def fullname(self):
  46. return self.__module__ + "." + self.__class__.__name__
  47. def load_settings(self, settings):
  48. pass
  49. def load_children(self, children):
  50. self.children = children
  51. def store_children(self):
  52. return False
  53. def settings_dict(self):
  54. pass
  55. def dump_settings(self, settings=None):
  56. settings = settings or self.settings_dict()
  57. if settings:
  58. return json.dumps(settings, cls=DateTimeEncoder)
  59. else:
  60. return ''
  61. def dump_children(self):
  62. if self.store_children():
  63. return json.dumps(self.children, cls=DateTimeEncoder)
  64. else:
  65. return ''
  66. def load_from_model(self):
  67. self.title = self.model.title
  68. if self.model.settings:
  69. try:
  70. self.settings = json.loads(self.model.settings)
  71. self.load_settings(self.settings)
  72. except ValueError:
  73. pass
  74. if self.store_children() and self.model.children:
  75. try:
  76. children = json.loads(self.model.children)
  77. self.load_children(children)
  78. except ValueError:
  79. pass
  80. def init_with_context(self, context):
  81. pass
  82. def get_context_data(self):
  83. context = self.context
  84. context.update({
  85. 'module': self
  86. })
  87. return context
  88. def render(self):
  89. self.init_with_context(self.context)
  90. return render_to_string(self.template, self.get_context_data())
  91. class LinkListItemForm(forms.Form):
  92. url = forms.CharField(label=_('URL'))
  93. title = forms.CharField(label=_('Title'))
  94. external = forms.BooleanField(label=_('External link'), required=False)
  95. class LinkListSettingsForm(forms.Form):
  96. layout = forms.ChoiceField(label=_('Layout'), choices=(('stacked', _('Stacked')), ('inline', _('Inline'))))
  97. class LinkList(DashboardModule):
  98. title = _('Links')
  99. template = 'jet/dashboard/modules/link_list.html'
  100. layout = 'stacked'
  101. settings_form = LinkListSettingsForm
  102. child_form = LinkListItemForm
  103. child_name = _('Link')
  104. child_name_plural = _('Links')
  105. def __init__(self, title=None, children=list(), **kwargs):
  106. children = list(map(self.parse_link, children))
  107. kwargs.update({'children': children})
  108. super(LinkList, self).__init__(title, **kwargs)
  109. def settings_dict(self):
  110. return {
  111. 'layout': self.layout
  112. }
  113. def load_settings(self, settings):
  114. self.layout = settings.get('layout', self.layout)
  115. def store_children(self):
  116. return True
  117. def parse_link(self, link):
  118. if isinstance(link, (tuple, list)):
  119. link_dict = {'title': link[0], 'url': link[1]}
  120. if len(link) >= 3:
  121. link_dict['external'] = link[2]
  122. return link_dict
  123. elif isinstance(link, (dict,)):
  124. return link
  125. class AppList(DashboardModule):
  126. title = _('Applications')
  127. template = 'jet/dashboard/modules/app_list.html'
  128. models = None
  129. exclude = None
  130. hide_empty = True
  131. def settings_dict(self):
  132. return {
  133. 'models': self.models,
  134. 'exclude': self.exclude
  135. }
  136. def load_settings(self, settings):
  137. self.models = settings.get('models')
  138. self.exclude = settings.get('exclude')
  139. def init_with_context(self, context):
  140. app_list = get_app_list(context)
  141. app_to_remove = []
  142. for app in app_list:
  143. app['models'] = filter(
  144. lambda model: self.models is None or model['object_name'] in self.models or app.get('app_label', app.get('name')) + '.*' in self.models,
  145. app['models']
  146. )
  147. app['models'] = filter(
  148. lambda model: self.exclude is None or model['object_name'] not in self.exclude and app.get('app_label', app.get('name')) + '.*' not in self.exclude,
  149. app['models']
  150. )
  151. app['models'] = list(app['models'])
  152. if self.hide_empty and len(list(app['models'])) == 0:
  153. app_to_remove.append(app)
  154. for app in app_to_remove:
  155. app_list.remove(app)
  156. self.children = app_list
  157. class ModelList(DashboardModule):
  158. title = _('Models')
  159. template = 'jet/dashboard/modules/model_list.html'
  160. models = None
  161. exclude = None
  162. hide_empty = True
  163. def settings_dict(self):
  164. return {
  165. 'models': self.models,
  166. 'exclude': self.exclude
  167. }
  168. def load_settings(self, settings):
  169. self.models = settings.get('models')
  170. self.exclude = settings.get('exclude')
  171. def init_with_context(self, context):
  172. app_list = get_app_list(context)
  173. models = []
  174. for app in app_list:
  175. app['models'] = filter(
  176. lambda model: self.models is None or model['object_name'] in self.models or app.get('app_label', app.get('name')) + '.*' in self.models,
  177. app['models']
  178. )
  179. app['models'] = filter(
  180. lambda model: self.exclude is None or model['object_name'] not in self.exclude and app.get('app_label', app.get('name')) + '.*' not in self.exclude,
  181. app['models']
  182. )
  183. app['models'] = list(app['models'])
  184. models.extend(app['models'])
  185. self.children = models
  186. class RecentActionsSettingsForm(forms.Form):
  187. limit = forms.IntegerField(label=_('Items limit'), min_value=1)
  188. class RecentActions(DashboardModule):
  189. title = _('Recent Actions')
  190. template = 'jet/dashboard/modules/recent_actions.html'
  191. limit = 10
  192. include_list = None
  193. exclude_list = None
  194. settings_form = RecentActionsSettingsForm
  195. user = None
  196. def __init__(self, title=None, limit=10, **kwargs):
  197. kwargs.update({'limit': limit})
  198. super(RecentActions, self).__init__(title, **kwargs)
  199. def settings_dict(self):
  200. return {
  201. 'limit': self.limit,
  202. 'include_list': self.include_list,
  203. 'exclude_list': self.exclude_list,
  204. 'user': self.user
  205. }
  206. def load_settings(self, settings):
  207. self.limit = settings.get('limit', self.limit)
  208. self.include_list = settings.get('include_list')
  209. self.exclude_list = settings.get('exclude_list')
  210. self.user = settings.get('user', None)
  211. def init_with_context(self, context):
  212. def get_qset(list):
  213. qset = None
  214. for contenttype in list:
  215. try:
  216. app_label, model = contenttype.split('.')
  217. if model == '*':
  218. current_qset = Q(
  219. content_type__app_label=app_label
  220. )
  221. else:
  222. current_qset = Q(
  223. content_type__app_label=app_label,
  224. content_type__model=model
  225. )
  226. except:
  227. raise ValueError('Invalid contenttype: "%s"' % contenttype)
  228. if qset is None:
  229. qset = current_qset
  230. else:
  231. qset = qset | current_qset
  232. return qset
  233. qs = LogEntry.objects
  234. if self.user:
  235. qs = qs.filter(
  236. user__pk=int(self.user)
  237. )
  238. if self.include_list:
  239. qs = qs.filter(get_qset(self.include_list))
  240. if self.exclude_list:
  241. qs = qs.exclude(get_qset(self.exclude_list))
  242. self.children = qs.select_related('content_type', 'user')[:int(self.limit)]
  243. class FeedSettingsForm(forms.Form):
  244. limit = forms.IntegerField(label=_('Items limit'), min_value=1)
  245. feed_url = forms.URLField(label=_('Feed URL'))
  246. class Feed(DashboardModule):
  247. title = _('RSS Feed')
  248. template = 'jet/dashboard/modules/feed.html'
  249. feed_url = None
  250. limit = None
  251. settings_form = FeedSettingsForm
  252. ajax_load = True
  253. def __init__(self, title=None, feed_url=None, limit=None, **kwargs):
  254. kwargs.update({'feed_url': feed_url, 'limit': limit})
  255. super(Feed, self).__init__(title, **kwargs)
  256. def settings_dict(self):
  257. return {
  258. 'feed_url': self.feed_url,
  259. 'limit': self.limit
  260. }
  261. def load_settings(self, settings):
  262. self.feed_url = settings.get('feed_url')
  263. self.limit = settings.get('limit')
  264. def init_with_context(self, context):
  265. if self.feed_url is not None:
  266. try:
  267. import feedparser
  268. feed = feedparser.parse(self.feed_url)
  269. if self.limit is not None:
  270. entries = feed['entries'][:self.limit]
  271. else:
  272. entries = feed['entries']
  273. for entry in entries:
  274. try:
  275. entry.date = datetime.date(*entry.published_parsed[0:3])
  276. except:
  277. pass
  278. self.children.append(entry)
  279. except ImportError:
  280. self.children.append({
  281. 'title': _('You must install the FeedParser python module'),
  282. 'warning': True,
  283. })
  284. else:
  285. self.children.append({
  286. 'title': _('You must provide a valid feed URL'),
  287. 'warning': True,
  288. })