2 from datetime import date
4 from ckeditor.fields import RichTextField
5 from combo.data.library import register_cell_class
6 from combo.data.models import CellBase
7 from django import template
8 from django.db import models
9 from django.db.models.functions import Lower
10 from django.utils.encoding import force_text, python_2_unicode_compatible
11 from django.utils.translation import ugettext_lazy as _
12 from emissions.models import Episode, NewsItem, SoundFile
13 from taggit.managers import TaggableManager
14 from taggit.models import Tag
15 from taggit.utils import parse_tags
19 class SoundCell(CellBase):
20 soundfile = models.ForeignKey('emissions.SoundFile', null=True, on_delete=models.CASCADE)
23 verbose_name = _('Sound')
25 def render(self, context):
26 tmpl = template.loader.get_template('panikombo/audio.html')
27 context['soundfile'] = self.soundfile
28 return tmpl.render(context)
30 def get_default_form_class(self):
31 from .forms import SoundCellForm
35 def get_included_items(self):
36 if not self.soundfile:
38 return [self.soundfile.episode]
40 def get_additional_label(self):
42 if self.soundfile.fragment:
43 return '%s - %s - %s' % (
44 self.soundfile.episode.emission.title,
45 self.soundfile.episode.title,
49 return '%s - %s' % (self.soundfile.episode.emission.title, self.soundfile.episode.title)
55 class EpisodeCell(CellBase):
56 episode = models.ForeignKey('emissions.Episode', null=True, on_delete=models.CASCADE)
59 verbose_name = _('Episode')
61 def render(self, context):
62 tmpl = template.loader.get_template('panikombo/episode.html')
63 context['episode'] = self.episode
65 context['soundfile'] = self.episode.main_sound
66 return tmpl.render(context)
68 def get_included_items(self):
73 def get_default_form_class(self):
74 from .forms import EpisodeCellForm
76 return EpisodeCellForm
78 def get_additional_label(self):
80 return '%s - %s' % (self.episode.emission.title, self.episode.title)
84 def get_parsed_tags(tagstring):
85 tags = parse_tags(tagstring)
86 return [x for x in Tag.objects.filter(name__in=tags)]
90 class EpisodeAutoSelectionCell(CellBase):
91 title = models.CharField(_('Title'), max_length=50, blank=True)
92 tags = TaggableManager(_('Tags'), blank=True)
93 and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
94 category = models.ForeignKey('emissions.Category', null=True, blank=True, on_delete=models.CASCADE)
95 period = models.PositiveSmallIntegerField(
96 _('Period'), default=0, choices=((0, _('All')), (1, _('Future')), (2, _('Past')))
99 default_template_name = 'panikombo/episode_auto_selection.html'
102 verbose_name = _('Automatic Episode Selection')
104 def get_included_items(self):
105 episodes_queryset = Episode.objects.select_related()
107 episodes_queryset = episodes_queryset.filter(emission__categories__in=[self.category.id])
108 if self.tags.count():
109 episodes_queryset = episodes_queryset.filter(tags__in=self.tags.all())
111 and_tags = get_parsed_tags(self.and_tags)
112 episodes_queryset = episodes_queryset.filter(tags__in=and_tags)
115 episodes_queryset = episodes_queryset.extra(
117 'first_diffusion': 'emissions_diffusion.datetime',
119 select_params=(False, True),
121 '''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
122 WHERE episode_id = emissions_episode.id)'''
124 tables=['emissions_diffusion'],
126 episodes_queryset = episodes_queryset.order_by('first_diffusion').distinct()
127 elif self.period == 1:
128 episodes_queryset = episodes_queryset.extra(
130 'first_diffusion': 'emissions_diffusion.datetime',
132 select_params=(False, True),
134 '''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
135 WHERE episode_id = emissions_episode.id) AND
136 datetime >= CURRENT_TIMESTAMP'''
138 tables=['emissions_diffusion'],
140 episodes_queryset = episodes_queryset.order_by('-first_diffusion').distinct()
141 elif self.period == 2:
142 episodes_queryset = episodes_queryset.extra(
144 'first_diffusion': 'emissions_diffusion.datetime',
146 select_params=(False, True),
148 '''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
149 WHERE episode_id = emissions_episode.id) AND
150 datetime < CURRENT_TIMESTAMP'''
152 tables=['emissions_diffusion'],
154 episodes_queryset = episodes_queryset.order_by('-first_diffusion').distinct()
156 return episodes_queryset
158 def get_cell_extra_context(self, context):
159 ctx = super().get_cell_extra_context(context)
160 ctx['title'] = self.title
162 if self.category or self.period or self.tags.count():
163 ctx['episodes'] = self.get_included_items()
169 def get_default_form_class(self):
170 from .forms import EpisodeAutoSelectionCellForm
172 return EpisodeAutoSelectionCellForm
174 def get_additional_label(self):
181 class NewsItemAutoSelectionCell(CellBase):
182 title = models.CharField(_('Title'), max_length=50, blank=True)
183 tags = TaggableManager(_('Tags'), blank=True)
184 and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
185 future = models.BooleanField(_('Future Events Only'), default=True)
186 category = models.ForeignKey(
187 'emissions.NewsCategory', verbose_name=_('Category'), null=True, blank=True, on_delete=models.SET_NULL
190 default_template_name = 'panikombo/newsitem_auto_selection.html'
193 verbose_name = _('Automatic Newsitem Selection')
195 def get_included_items(self):
196 newsitems_queryset = NewsItem.objects.select_related()
197 if self.tags.count():
198 newsitems_queryset = newsitems_queryset.filter(tags__in=self.tags.all())
200 and_tags = get_parsed_tags(self.and_tags)
201 newsitems_queryset = newsitems_queryset.filter(tags__in=and_tags)
203 newsitems_queryset = newsitems_queryset.filter(event_date__gte=date.today())
205 newsitems_queryset = newsitems_queryset.filter(category=self.category)
206 newsitems_queryset = newsitems_queryset.order_by('-event_date', '-creation_timestamp')
207 return newsitems_queryset
209 def get_cell_extra_context(self, context):
210 ctx = super().get_cell_extra_context(context)
211 ctx['title'] = self.title
213 if self.tags.count() or self.future or self.category:
214 ctx['newsitems'] = self.get_included_items()
216 ctx['newsitems'] = []
220 def get_default_form_class(self):
221 from .forms import NewsItemAutoSelectionCellForm
223 return NewsItemAutoSelectionCellForm
225 def get_additional_label(self):
231 class ItemTopik(models.Model):
232 newsitem = models.ForeignKey(
233 'emissions.NewsItem', verbose_name=_('News Item'), null=True, blank=True, on_delete=models.SET_NULL
235 episode = models.ForeignKey(
236 'emissions.Episode', verbose_name=_('Episode'), null=True, blank=True, on_delete=models.SET_NULL
238 page = models.ForeignKey('data.Page', null=True, blank=True, on_delete=models.SET_NULL)
242 class SoundsCell(CellBase):
243 title = models.CharField(_('Title'), max_length=150, blank=True)
244 include_search_input = models.BooleanField(_('Include search input'), default=True)
245 include_fragments = models.BooleanField(_('Include fragments'), default=True)
246 limit_to_focus = models.BooleanField(_('Limit to focused elements'), default=False)
247 sound_format = models.ForeignKey(
248 'emissions.Format', verbose_name=_('Limit to format'), null=True, blank=True, on_delete=models.CASCADE
250 tags = TaggableManager(_('Tags'), blank=True)
251 minimal_duration = models.PositiveIntegerField(
252 _('Minimal duration (in minutes)'), default=None, blank=True, null=True
254 maximal_duration = models.PositiveIntegerField(
255 _('Maximal duration (in minutes)'), default=None, blank=True, null=True
257 count = models.PositiveSmallIntegerField(_('Count'), default=20)
258 sort_order = models.CharField(
260 default='-creation_timestamp',
263 ('-creation_timestamp', _('Reverse chronological (creation)')),
264 ('-first_diffusion', _('Reverse chronological (diffusion)')),
265 ('creation_timestamp', _('Chronological (creation)')),
266 ('first_diffusion', _('Chronological (diffusion)')),
272 verbose_name = _('Sounds')
274 def get_default_form_fields(self):
275 fields = super().get_default_form_fields()
276 fields.insert(fields.index('minimal_duration'), 'tags')
279 def get_cell_extra_context(self, context):
280 soundfiles = SoundFile.objects.prefetch_related('episode__emission__categories')
281 soundfiles = soundfiles.filter(podcastable=True)
282 if not self.include_fragments:
283 soundfiles = soundfiles.filter(fragment=False)
284 if self.limit_to_focus:
285 soundfiles = soundfiles.filter(got_focus__isnull=False)
286 if self.sound_format:
287 soundfiles = soundfiles.filter(format_id=self.sound_format_id)
288 if self.minimal_duration:
289 soundfiles = soundfiles.filter(duration__gte=self.minimal_duration * 60)
290 if self.maximal_duration:
291 soundfiles = soundfiles.filter(duration__lte=self.maximal_duration * 60)
292 if self.tags.exists():
293 soundfiles = soundfiles.filter(episode__tags__in=self.tags.all())
295 soundfiles.select_related()
298 'first_diffusion': 'emissions_diffusion.datetime',
300 select_params=(False, True),
302 '''datetime = (SELECT MIN(datetime)
303 FROM emissions_diffusion
304 WHERE episode_id = emissions_episode.id)'''
306 tables=['emissions_diffusion'],
308 .order_by(self.sort_order)
312 'include_search_input': self.include_search_input,
313 'soundfiles': soundfiles[: self.count],