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