]> git.0d.be Git - django-panik-combo.git/blob - panikombo/models.py
add introduction to fullwidth page placeholders
[django-panik-combo.git] / panikombo / models.py
1 from datetime import date
2 import os
3
4 from django import template
5 from django.db import models
6 from django.db.models.functions import Lower
7 from django.utils.encoding import force_text, python_2_unicode_compatible
8 from django.utils.translation import ugettext_lazy as _
9
10 from ckeditor.fields import RichTextField
11 from taggit.models import Tag
12 from taggit.managers import TaggableManager
13 from taggit.utils import parse_tags
14
15 from combo.data.models import CellBase
16 from combo.data.library import register_cell_class
17
18 from emissions.models import Episode, NewsItem, SoundFile
19
20 @register_cell_class
21 class SoundCell(CellBase):
22     soundfile = models.ForeignKey('emissions.SoundFile', null=True)
23
24     class Meta:
25         verbose_name = _('Sound')
26
27     def render(self, context):
28         tmpl = template.loader.get_template('panikombo/audio.html')
29         context['soundfile'] = self.soundfile
30         return tmpl.render(context)
31
32     def get_default_form_class(self):
33         from .forms import SoundCellForm
34         return SoundCellForm
35
36     def get_included_items(self):
37         if not self.soundfile:
38             return []
39         return [self.soundfile.episode]
40
41     def get_additional_label(self):
42         if self.soundfile:
43             if self.soundfile.fragment:
44                 return u'%s - %s - %s' % (
45                         self.soundfile.episode.emission.title,
46                         self.soundfile.episode.title,
47                         self.soundfile.title)
48             else:
49                 return u'%s - %s' % (
50                         self.soundfile.episode.emission.title,
51                         self.soundfile.episode.title)
52
53         return ''
54
55
56 @register_cell_class
57 class EpisodeCell(CellBase):
58     episode = models.ForeignKey('emissions.Episode', null=True)
59
60     class Meta:
61         verbose_name = _('Episode')
62
63     def render(self, context):
64         tmpl = template.loader.get_template('panikombo/episode.html')
65         context['episode'] = self.episode
66         if self.episode:
67             context['soundfile'] = self.episode.main_sound
68         return tmpl.render(context)
69
70     def get_included_items(self):
71         if not self.episode:
72             return []
73         return [self.episode]
74
75     def get_default_form_class(self):
76         from .forms import EpisodeCellForm
77         return EpisodeCellForm
78
79     def get_additional_label(self):
80         if self.episode:
81             return u'%s - %s' % (
82                         self.episode.emission.title,
83                         self.episode.title)
84         return ''
85
86
87 def get_parsed_tags(tagstring):
88     tags = parse_tags(tagstring)
89     return [x for x in Tag.objects.filter(name__in=tags)]
90
91
92 @register_cell_class
93 class EpisodeAutoSelectionCell(CellBase):
94     title = models.CharField(_('Title'), max_length=50, blank=True)
95     tags = TaggableManager(_('Tags'), blank=True)
96     and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
97     category = models.ForeignKey('emissions.Category', null=True, blank=True)
98     period = models.PositiveSmallIntegerField(
99             _('Period'), default=0,
100             choices=((0, _('All')),
101                      (1, _('Future')),
102                      (2, _('Past'))))
103
104     template_name = 'panikombo/episode_auto_selection.html'
105
106
107     class Meta:
108         verbose_name = _('Automatic Episode Selection')
109
110     def get_included_items(self):
111         episodes_queryset = Episode.objects.select_related()
112         if self.category:
113             episodes_queryset = episodes_queryset.filter(emission__categories__in=[self.category.id])
114         if self.tags.count():
115             episodes_queryset = episodes_queryset.filter(tags__in=self.tags.all())
116             if self.and_tags:
117                 and_tags = get_parsed_tags(self.and_tags)
118                 episodes_queryset = episodes_queryset.filter(tags__in=and_tags)
119
120         if self.period == 0:
121             episodes_queryset = episodes_queryset.extra(
122                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
123                     select_params=(False, True),
124                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
125                                            WHERE episode_id = emissions_episode.id)'''],
126                     tables=['emissions_diffusion'])
127             episodes_queryset = episodes_queryset.order_by('first_diffusion').distinct()
128         elif self.period == 1:
129             episodes_queryset = episodes_queryset.extra(
130                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
131                     select_params=(False, True),
132                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
133                                            WHERE episode_id = emissions_episode.id) AND
134                                                  datetime >= CURRENT_TIMESTAMP'''],
135                     tables=['emissions_diffusion'])
136             episodes_queryset = episodes_queryset.order_by('-first_diffusion').distinct()
137         elif self.period == 2:
138             episodes_queryset = episodes_queryset.extra(
139                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
140                     select_params=(False, True),
141                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
142                                            WHERE episode_id = emissions_episode.id) AND
143                                                  datetime < CURRENT_TIMESTAMP'''],
144                     tables=['emissions_diffusion'])
145             episodes_queryset = episodes_queryset.order_by('-first_diffusion').distinct()
146
147         return episodes_queryset
148
149     def get_cell_extra_context(self, context):
150         ctx = super(EpisodeAutoSelectionCell, self).get_cell_extra_context(context)
151         ctx['title'] = self.title
152
153         if (self.category or self.period or self.tags.count()):
154             ctx['episodes'] = self.get_included_items()
155         else:
156             ctx['episodes'] = []
157
158         return ctx
159
160     def get_default_form_class(self):
161         from .forms import EpisodeAutoSelectionCellForm
162         return EpisodeAutoSelectionCellForm
163
164     def get_additional_label(self):
165         if self.title:
166             return self.title
167         return ''
168
169 @register_cell_class
170 class NewsItemAutoSelectionCell(CellBase):
171     title = models.CharField(_('Title'), max_length=50, blank=True)
172     tags = TaggableManager(_('Tags'), blank=True)
173     and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
174     future = models.BooleanField(_('Future Events Only'), default=True)
175     category = models.ForeignKey('emissions.NewsCategory',
176             verbose_name=_('Category'), null=True, blank=True)
177
178     template_name = 'panikombo/newsitem_auto_selection.html'
179
180     class Meta:
181         verbose_name = _('Automatic Newsitem Selection')
182
183     def get_included_items(self):
184         newsitems_queryset = NewsItem.objects.select_related()
185         if self.tags.count():
186             newsitems_queryset = newsitems_queryset.filter(tags__in=self.tags.all())
187             if self.and_tags:
188                 and_tags = get_parsed_tags(self.and_tags)
189                 newsitems_queryset = newsitems_queryset.filter(tags__in=and_tags)
190         if self.future:
191             newsitems_queryset = newsitems_queryset.filter(event_date__gte=date.today())
192         if self.category:
193             newsitems_queryset = newsitems_queryset.filter(category=self.category)
194         newsitems_queryset = newsitems_queryset.order_by('-event_date', '-creation_timestamp')
195         return newsitems_queryset
196
197     def get_cell_extra_context(self, context):
198         ctx = super(NewsItemAutoSelectionCell, self).get_cell_extra_context(context)
199         ctx['title'] = self.title
200
201         if self.tags.count() or self.future or self.category:
202             ctx['newsitems'] = self.get_included_items()
203         else:
204             ctx['newsitems'] = []
205
206         return ctx
207
208     def get_default_form_class(self):
209         from .forms import NewsItemAutoSelectionCellForm
210         return NewsItemAutoSelectionCellForm
211
212     def get_additional_label(self):
213         if self.title:
214             return self.title
215         return ''
216
217
218 class ItemTopik(models.Model):
219     newsitem = models.ForeignKey('emissions.NewsItem', verbose_name=_('News Item'),
220             null=True, blank=True)
221     episode = models.ForeignKey('emissions.Episode', verbose_name=_('Episode'),
222             null=True, blank=True)
223     page = models.ForeignKey('data.Page', null=True, blank=True)
224
225
226 @register_cell_class
227 class SoundsCell(CellBase):
228     title = models.CharField(_('Title'), max_length=150, blank=True)
229     include_search_input = models.BooleanField(_('Include search input'), default=True)
230     include_fragments = models.BooleanField(_('Include fragments'), default=True)
231     limit_to_focus = models.BooleanField(_('Limit to focused elements'), default=False)
232     sound_format = models.ForeignKey('emissions.Format',
233             verbose_name=_('Limit to format'), null=True, blank=True)
234     tags = TaggableManager(_('Tags'), blank=True)
235     minimal_duration = models.PositiveIntegerField(
236             _('Minimal duration (in minutes)'),
237             default=None, blank=True, null=True)
238     maximal_duration = models.PositiveIntegerField(
239             _('Maximal duration (in minutes)'),
240             default=None, blank=True, null=True)
241     count = models.PositiveSmallIntegerField(_('Count'), default=20)
242     sort_order = models.CharField(_('Sort order'), default='-creation_timestamp',
243             max_length=30,
244             choices=[
245                 ('-creation_timestamp', _('Reverse chronological (creation)')),
246                 ('-first_diffusion', _('Reverse chronological (diffusion)')),
247                 ('creation_timestamp', _('Chronological (creation)')),
248                 ('first_diffusion', _('Chronological (diffusion)')),
249                 ('?', _('Random')),
250             ]
251             )
252
253     class Meta:
254         verbose_name = _('Sounds')
255
256     def get_default_form_fields(self):
257         fields = super().get_default_form_fields()
258         fields.insert(fields.index('minimal_duration'), 'tags')
259         return fields
260
261     def get_cell_extra_context(self, context):
262         soundfiles = SoundFile.objects.prefetch_related('episode__emission__categories')
263         soundfiles = soundfiles.filter(podcastable=True)
264         if not self.include_fragments:
265             soundfiles = soundfiles.filter(fragment=False)
266         if self.limit_to_focus:
267             soundfiles = soundfiles.filter(got_focus__isnull=False)
268         if self.sound_format:
269             soundfiles = soundfiles.filter(format_id=self.sound_format_id)
270         if self.minimal_duration:
271             soundfiles = soundfiles.filter(duration__gte=self.minimal_duration * 60)
272         if self.maximal_duration:
273             soundfiles = soundfiles.filter(duration__lte=self.maximal_duration * 60)
274         if self.tags.exists():
275             soundfiles = soundfiles.filter(episode__tags__in=self.tags.all())
276         soundfiles = soundfiles.select_related().extra(
277                     select={'first_diffusion': 'emissions_diffusion.datetime', },
278                     select_params=(False, True),
279                     where=['''datetime = (SELECT MIN(datetime)
280                                             FROM emissions_diffusion
281                                         WHERE episode_id = emissions_episode.id)'''],
282                     tables=['emissions_diffusion'],).order_by(self.sort_order).distinct()
283         return {
284             'include_search_input': self.include_search_input,
285             'soundfiles': soundfiles[:self.count],
286         }