add additional "and_tags" field to auto selection, for ANDing criterias
[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.utils.translation import ugettext_lazy as _
7
8 from ckeditor.fields import RichTextField
9 from taggit.models import Tag
10 from taggit.managers import TaggableManager
11 from taggit.utils import parse_tags
12
13 from combo.data.models import CellBase
14 from combo.data.library import register_cell_class
15
16 from emissions.models import Episode, NewsItem
17
18 @register_cell_class
19 class SoundCell(CellBase):
20     soundfile = models.ForeignKey('emissions.SoundFile', null=True)
21
22     class Meta:
23         verbose_name = _('Sound')
24
25     def render(self, context):
26         tmpl = template.loader.get_template('panikombo/audio.html')
27         context['soundfile'] = self.soundfile
28         return tmpl.render(context)
29
30     def get_default_form_class(self):
31         from .forms import SoundCellForm
32         return SoundCellForm
33
34     def get_included_items(self):
35         if not self.soundfile:
36             return []
37         return [self.soundfile.episode]
38
39     def get_additional_label(self):
40         if self.soundfile:
41             if self.soundfile.fragment:
42                 return u'%s - %s - %s' % (
43                         self.soundfile.episode.emission.title,
44                         self.soundfile.episode.title,
45                         self.soundfile.title)
46             else:
47                 return u'%s - %s' % (
48                         self.soundfile.episode.emission.title,
49                         self.soundfile.episode.title)
50
51         return ''
52
53
54 @register_cell_class
55 class EpisodeCell(CellBase):
56     episode = models.ForeignKey('emissions.Episode', null=True)
57
58     class Meta:
59         verbose_name = _('Episode')
60
61     def render(self, context):
62         tmpl = template.loader.get_template('panikombo/episode.html')
63         context['episode'] = self.episode
64         if self.episode:
65             context['soundfile'] = self.episode.main_sound
66         return tmpl.render(context)
67
68     def get_included_items(self):
69         if not self.episode:
70             return []
71         return [self.episode]
72
73     def get_default_form_class(self):
74         from .forms import EpisodeCellForm
75         return EpisodeCellForm
76
77     def get_additional_label(self):
78         if self.episode:
79             return u'%s - %s' % (
80                         self.episode.emission.title,
81                         self.episode.title)
82         return ''
83
84
85 def get_parsed_tags(tagstring):
86     tags = parse_tags(tagstring)
87     return [x for x in Tag.objects.filter(name__in=tags)]
88
89
90 @register_cell_class
91 class EpisodeAutoSelectionCell(CellBase):
92     title = models.CharField(_('Title'), max_length=50, blank=True)
93     tags = TaggableManager(_('Tags'), blank=True)
94     and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
95     category = models.ForeignKey('emissions.Category', null=True, blank=True)
96     period = models.PositiveSmallIntegerField(
97             _('Period'), default=0,
98             choices=((0, _('All')),
99                      (1, _('Future')),
100                      (2, _('Past'))))
101
102
103     class Meta:
104         verbose_name = _('Automatic Episode Selection')
105
106     def get_included_items(self):
107         episodes_queryset = Episode.objects.select_related()
108         if self.category:
109             episodes_queryset = episodes_queryset.filter(emission__categories__in=[self.category.id])
110         if self.tags.count():
111             episodes_queryset = episodes_queryset.filter(tags__in=self.tags.all())
112             if self.and_tags:
113                 and_tags = get_parsed_tags(self.and_tags)
114                 episodes_queryset = episodes_queryset.filter(tags__in=and_tags)
115
116         if self.period == 0:
117             episodes_queryset = episodes_queryset.extra(
118                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
119                     select_params=(False, True),
120                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
121                                            WHERE episode_id = emissions_episode.id)'''],
122                     tables=['emissions_diffusion'])
123         elif self.period == 1:
124             episodes_queryset = episodes_queryset.extra(
125                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
126                     select_params=(False, True),
127                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
128                                            WHERE episode_id = emissions_episode.id) AND
129                                                  datetime >= CURRENT_TIMESTAMP'''],
130                     tables=['emissions_diffusion'])
131         elif self.period == 2:
132             episodes_queryset = episodes_queryset.extra(
133                     select={ 'first_diffusion': 'emissions_diffusion.datetime', },
134                     select_params=(False, True),
135                     where=['''datetime = (SELECT MIN(datetime) FROM emissions_diffusion
136                                            WHERE episode_id = emissions_episode.id) AND
137                                                  datetime < CURRENT_TIMESTAMP'''],
138                     tables=['emissions_diffusion'])
139
140         return episodes_queryset
141
142     def render(self, context):
143         tmpl = template.loader.get_template('panikombo/episode_auto_selection.html')
144         context['title'] = self.title
145
146         if (self.category or self.period or self.tags.count()):
147             episodes_queryset = self.get_included_items()
148             episodes_queryset = episodes_queryset.order_by('-first_diffusion').distinct()
149             context['episodes'] = episodes_queryset
150         else:
151             context['episodes'] = []
152         return tmpl.render(context)
153
154     def get_default_form_class(self):
155         from .forms import EpisodeAutoSelectionCellForm
156         return EpisodeAutoSelectionCellForm
157
158     def get_additional_label(self):
159         if self.title:
160             return self.title
161         return ''
162
163 @register_cell_class
164 class NewsItemAutoSelectionCell(CellBase):
165     title = models.CharField(_('Title'), max_length=50, blank=True)
166     tags = TaggableManager(_('Tags'), blank=True)
167     and_tags = models.CharField(_('And Tags'), max_length=100, blank=True)
168     future = models.BooleanField(_('Future Events Only'), default=True)
169     category = models.ForeignKey('emissions.NewsCategory',
170             verbose_name=_('Category'), null=True, blank=True)
171
172     class Meta:
173         verbose_name = _('Automatic Newsitem Selection')
174
175     def get_included_items(self):
176         newsitems_queryset = NewsItem.objects.select_related()
177         if self.tags.count():
178             newsitems_queryset = newsitems_queryset.filter(tags__in=self.tags.all())
179             if self.and_tags:
180                 and_tags = get_parsed_tags(self.and_tags)
181                 newsitems_queryset = newsitems_queryset.filter(tags__in=and_tags)
182         if self.future:
183             newsitems_queryset = newsitems_queryset.filter(event_date__gte=date.today())
184         if self.category:
185             newsitems_queryset = newsitems_queryset.filter(category=self.category)
186         newsitems_queryset = newsitems_queryset.order_by('-event_date', '-creation_timestamp')
187         return newsitems_queryset
188
189     def render(self, context):
190         tmpl = template.loader.get_template('panikombo/newsitem_auto_selection.html')
191         context['title'] = self.title
192         if self.tags.count() or self.future or self.category:
193             context['newsitems'] = self.get_included_items()
194         else:
195             context['newsitems'] = []
196         return tmpl.render(context)
197
198     def get_default_form_class(self):
199         from .forms import NewsItemAutoSelectionCellForm
200         return NewsItemAutoSelectionCellForm
201
202     def get_additional_label(self):
203         if self.title:
204             return self.title
205         return ''
206
207
208 def get_topik_image_path(instance, filename):
209     return os.path.join('images', 'topik', instance.page.slug,
210             os.path.basename(filename))
211
212 class Topik(models.Model):
213     page = models.ForeignKey('data.Page')
214     image = models.ImageField(_('Image'),
215             upload_to=get_topik_image_path, max_length=250, null=True, blank=True)
216
217     # denormalized from Focus
218     got_focus = models.DateTimeField(default=None, null=True, blank=True)
219     has_focus = models.BooleanField(default=False)
220
221     def __unicode__(self):
222         if not self.page:
223             return super(Topik, self).__unicode__()
224         return unicode(self.page)
225
226
227 class ItemTopik(models.Model):
228     newsitem = models.ForeignKey('emissions.NewsItem', verbose_name=_('News Item'),
229             null=True, blank=True)
230     episode = models.ForeignKey('emissions.Episode', verbose_name=_('Episode'),
231             null=True, blank=True)
232     topik = models.ForeignKey('Topik', verbose_name='Topik',
233             null=True, blank=True)
234
235
236 @register_cell_class
237 class TopikCell(CellBase):
238     topik = models.ForeignKey(Topik, null=True)
239     text = RichTextField(_('Text'), blank=True, null=True)
240
241     template_name = 'panikombo/topik-cell.html'
242
243     class Meta:
244         verbose_name = _('Topik')
245
246     def get_additional_label(self):
247         if not self.topik:
248             return ''
249         return self.topik.page.title