]> git.0d.be Git - django-panik-emissions.git/blob - emissions/forms.py
don't display chat_open field
[django-panik-emissions.git] / emissions / forms.py
1 import datetime
2 import re
3 import unicodedata
4 import os
5 import uuid
6
7 from django import forms
8 from django.forms import fields
9
10 from django.core.files.storage import DefaultStorage
11 from django.core.urlresolvers import reverse
12 from django.utils.safestring import mark_safe
13 from django.utils.translation import ugettext_lazy as _
14 from django.conf import settings
15 from django.template.loader import render_to_string
16
17 from taggit.forms import TagWidget
18 import datetimewidget.widgets
19
20 from .models import (Emission, Episode, Diffusion, Schedule, SoundFile,
21         NewsItem, Absence, PlaylistElement)
22
23
24 DATETIME_OPTIONS = {
25         'format': 'dd/mm/yyyy hh:ii',
26         'language': 'fr',
27         'weekStart': '1',
28         'autoclose': 'true',
29         }
30
31 DATE_OPTIONS = {
32         'format': 'dd/mm/yyyy',
33         'language': 'fr',
34         'weekStart': '1',
35         'autoclose': 'true',
36         'minView': '"month"',
37         }
38
39
40 class DateTimeWidget(datetimewidget.widgets.DateTimeWidget):
41     def __init__(self, *args, **kwargs):
42         super(DateTimeWidget, self).__init__(*args, options=DATETIME_OPTIONS, **kwargs)
43
44     def format_output(self, rendered_widgets):
45         rendered_widgets[0] += '<span class="add-on"><i class="icon-remove"></i></span>'
46         return super(DateTimeWidget, self).format_output(rendered_widgets)
47
48
49 class DateWidget(datetimewidget.widgets.DateTimeWidget):
50     def __init__(self, *args, **kwargs):
51         super(DateWidget, self).__init__(*args, options=DATE_OPTIONS, **kwargs)
52
53     def format_output(self, rendered_widgets):
54         rendered_widgets[0] += '<span class="add-on"><i class="icon-remove"></i></span>'
55         return super(DateWidget, self).format_output(rendered_widgets)
56
57     def value_from_datadict(self, data, files, name):
58         t = super(DateWidget, self).value_from_datadict(data, files, name)
59         if t:
60             t = t.split()[0] # date only
61         return t
62
63
64 def slugify(s):
65     s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').lower()
66     return re.sub(r'\W+', '-', s)
67
68
69 class DayAndHourWidget(forms.MultiWidget):
70     def __init__(self, attrs=None):
71         WEEKDAYS = [_('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'),
72                 _('Friday'), _('Saturday'), _('Sunday')]
73         widgets = (
74             forms.Select(attrs=attrs, choices=([(weekday, WEEKDAYS[weekday]) for weekday in range(7)])),
75             forms.Select(attrs=attrs, choices=([(hour, hour) for hour in range(24)])),
76             forms.Select(attrs=attrs, choices=([(minute, str(minute).zfill(2)) for minute in range(60)])),
77         )
78         super(DayAndHourWidget, self).__init__(widgets, attrs)
79
80     def decompress(self, value):
81         if value:
82             return [value.weekday(), value.hour, value.minute]
83         return [None, None, None]
84
85     def value_from_datadict(self, data, files, name):
86         # we only care about day/hour/minutes, but we conveniently use a
87         # datetime value to store that; we pick 2007 as reference year as
88         # it had its January 1st on a Monday.
89         data_list = [
90             widget.value_from_datadict(data, files, name + '_%s' % i)
91             for i, widget in enumerate(self.widgets)]
92
93         if data_list:
94             return datetime.datetime(2007, 1, int(data_list[0])+1, int(data_list[1]), int(data_list[2]))
95         return None
96
97
98 class JqueryFileUploadFileInput(forms.FileInput):
99     def render(self, name, value, attrs=None):
100         output = render_to_string('emissions/upload.html', {
101             'upload_url': self.url,
102             'files': self.files,
103             'name': name,
104             'STATIC_URL': settings.STATIC_URL})
105         return mark_safe(output)
106
107
108 class JqueryFileUploadInput(forms.MultiWidget):
109     needs_multipart_form = True
110     upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
111     upload_id = None
112
113     def __init__(self, attrs=None, choices=[], max_filename_length=None):
114         self.max_filename_length = max_filename_length
115         widget_list = (forms.HiddenInput(attrs=attrs),
116                 JqueryFileUploadFileInput(attrs=attrs))
117         super(JqueryFileUploadInput, self).__init__(widget_list, attrs)
118
119     def decompress(self, value):
120         # map python value to widget contents
121         if self.upload_id:
122             pass
123         elif isinstance(value, (list, tuple)) and value and value[0] is not None:
124             self.upload_id = str(value[0])
125         else:
126             self.upload_id = str(uuid.uuid4())
127         return [self.upload_id, None]
128
129     def get_files_for_id(self, upload_id):
130         storage = DefaultStorage()
131         path = os.path.join('upload', upload_id)
132         if not storage.exists(path):
133             return
134         for filepath in storage.listdir(path)[1]:
135             name = os.path.basename(filepath)
136             yield storage.open(os.path.join(path, name))
137
138     def value_from_datadict(self, data, files, name):
139         '''
140            If some file was submitted, that's the value,
141            If a regular hidden_id is present, use it to find uploaded files,
142            otherwise return an empty list
143         '''
144         upload_id, file_input = super(JqueryFileUploadInput, self).value_from_datadict(data, files, name)
145         if file_input:
146             pass
147         elif JqueryFileUploadInput.upload_id_re.match(upload_id):
148             file_input = list(self.get_files_for_id(upload_id))
149         else:
150             file_input = []
151         try:
152             return file_input[0]
153         except IndexError:
154             return None
155
156     def render(self, name, value, attrs=None):
157         self.decompress(value)
158         self.widgets[1].url = '/upload/%s/' % self.upload_id
159         self.widgets[1].url = reverse('upload', kwargs={'transaction_id': self.upload_id})
160         if self.max_filename_length:
161             self.widgets[1].url += '?max_filename_length=%d' % self.max_filename_length
162         self.widgets[1].files = '/upload/%s/' % self.get_files_for_id(self.upload_id)
163         output = super(JqueryFileUploadInput, self).render(name, value,
164                 attrs)
165         fileinput_id = '%s_%s' % (attrs['id'], '1')
166         return output
167
168
169 class EmissionForm(forms.ModelForm):
170     class Meta:
171         model = Emission
172         exclude = ('slug', 'colours', 'has_focus', 'got_focus', 'chat_open')
173
174     def save(self, commit=True):
175         if not self.instance.slug:
176             self.instance.slug = slugify(self.instance.title)
177         return super(EmissionForm, self).save(commit=commit)
178
179
180 class EpisodeForm(forms.ModelForm):
181     class Meta:
182         model = Episode
183         exclude = ('slug', 'has_focus', 'got_focus', 'effective_start', 'effective_end')
184         widgets = {'emission': forms.HiddenInput(),
185                    'tags': TagWidget()}
186
187     def save(self, commit=True):
188         if not self.instance.slug:
189             base_slug = slugify(self.instance.title)
190             slug = base_slug
191             i = 1
192             while True:
193                 try:
194                     Episode.objects.get(slug=slug)
195                 except Episode.DoesNotExist:
196                     break
197                 i += 1
198                 slug = '%s-%s' % (base_slug, i)
199
200             self.instance.slug = slug
201         return super(EpisodeForm, self).save(commit=commit)
202
203
204 class EpisodeNewForm(EpisodeForm):
205     first_diffusion = forms.DateTimeField(label=_('First Diffusion'),
206             widget=DateTimeWidget)
207     second_diffusion = forms.DateTimeField(label=_('Second Diffusion'),
208             widget=DateTimeWidget)
209     third_diffusion = forms.DateTimeField(label=_('Third Diffusion'),
210             widget=DateTimeWidget)
211     fourth_diffusion = forms.DateTimeField(label=_('Fourth Diffusion'),
212             widget=DateTimeWidget)
213
214     def get_diffusion_fields(self, emission):
215         if emission:
216             schedules = Schedule.objects.filter(emission=emission, rerun=True).count() + 1
217         else:
218             schedules = 1
219         fields = ['first_diffusion']
220         if schedules > 1:
221             fields.append('second_diffusion')
222         if schedules > 2:
223             fields.append('third_diffusion')
224         if schedules > 3:
225             fields.append('fourth_diffusion')
226         return fields
227
228     def __init__(self, *args, **kwargs):
229         super(EpisodeNewForm, self).__init__(*args, **kwargs)
230         emission = kwargs.get('initial', {}).get('emission')
231         diffusion_fields = self.get_diffusion_fields(emission)
232         for field_name in self.fields.keys():
233             if field_name.endswith('_diffusion') and not field_name in diffusion_fields:
234                 del self.fields[field_name]
235
236     def save(self, commit=True):
237         episode = super(EpisodeNewForm, self).save(commit=commit)
238         for field_name in self.get_diffusion_fields(episode.emission):
239             diffusion = Diffusion()
240             diffusion.episode_id = episode.id
241             diffusion.datetime = self.cleaned_data.get(field_name)
242             diffusion.save()
243         return episode
244
245
246 class ScheduleForm(forms.ModelForm):
247     class Meta:
248         model = Schedule
249         widgets = {
250                 'emission': forms.HiddenInput(),
251                 'datetime': DayAndHourWidget(),
252         }
253
254
255 class SoundFileForm(forms.ModelForm):
256     class Meta:
257         model = SoundFile
258         exclude = ('has_focus', 'got_focus', 'duration')
259         widgets = {
260                 'episode': forms.HiddenInput(),
261                 'file': JqueryFileUploadInput(),
262         }
263
264
265 class SoundFileEditForm(forms.ModelForm):
266     class Meta:
267         model = SoundFile
268         exclude = ('has_focus', 'got_focus', 'file', 'duration')
269         widgets = {
270                 'episode': forms.HiddenInput(),
271         }
272
273     def __init__(self, *args, **kwargs):
274         super(SoundFileEditForm, self).__init__(*args, **kwargs)
275         self.fields.keyOrder = ['title', 'format', 'podcastable', 'fragment']
276
277
278 class DiffusionForm(forms.ModelForm):
279     class Meta:
280         model = Diffusion
281         widgets = {
282                 'episode': forms.HiddenInput(),
283                 'datetime': DateTimeWidget(),
284         }
285
286
287 class NewsItemForm(forms.ModelForm):
288     class Meta:
289         model = NewsItem
290         exclude = ('slug', 'has_focus', 'got_focus')
291         widgets = {'tags': TagWidget(),
292                    'date': DateWidget(),
293                    'expiration_date': DateWidget(),
294                    'event_date': DateWidget(),
295                   }
296
297     def __init__(self, *args, **kwargs):
298         super(NewsItemForm, self).__init__(*args, **kwargs)
299         user = kwargs.get('initial', {}).get('user')
300         if not user.is_staff:
301             self.fields['emission'].widget = forms.HiddenInput()
302
303     def save(self, commit=True):
304         if not self.instance.slug:
305             base_slug = slugify(self.instance.title)
306             slug = base_slug
307             i = 1
308             while True:
309                 try:
310                     NewsItem.objects.get(slug=slug)
311                 except NewsItem.DoesNotExist:
312                     break
313                 i += 1
314                 slug = '%s-%s' % (base_slug, i)
315
316             self.instance.slug = slug
317         return super(NewsItemForm, self).save(commit=commit)
318
319
320 class AbsenceDateTimeWidget(forms.Select):
321     def render_options(self, choices, selected_choices):
322         self.choices = []
323         dates = []
324         for i in range(4):
325             if dates:
326                 since = dates[-1] + datetime.timedelta(minutes=10)
327             else:
328                 since = None
329             dates.append(self.emission.get_next_planned_date(since))
330         choices = [(x, x.strftime('%d/%m/%Y %H:%M')) for x in dates]
331         return super(AbsenceDateTimeWidget, self).render_options(choices, selected_choices)
332
333
334 class AbsenceForm(forms.ModelForm):
335     class Meta:
336         model = Absence
337         widgets = {
338                 'emission': forms.HiddenInput(),
339                 'datetime': AbsenceDateTimeWidget(),
340         }
341
342     def __init__(self, *args, **kwargs):
343         super(AbsenceForm, self).__init__(*args, **kwargs)
344         emission = kwargs.get('initial', {}).get('emission')
345         user = kwargs.get('initial', {}).get('user')
346         self.fields['datetime'].widget.emission = emission
347         if user and user.is_staff:
348             date = emission.get_next_planned_date()
349             self.fields['datetime'].initial = date
350             self.fields['datetime'].widget = DateTimeWidget()
351
352     def save(self, commit=True):
353         t = super(AbsenceForm, self).save(commit=commit)
354         for i, schedule in enumerate(
355                 Schedule.objects.filter(emission=self.instance.emission,
356                     rerun=True).order_by('datetime')):
357             rerun_date = schedule.get_next_planned_date(self.instance.datetime)
358             rerun_absence = Absence()
359             rerun_absence.emission = self.instance.emission
360             rerun_absence.datetime = rerun_date
361             rerun_absence.save()
362         return t
363
364
365 class PlaylistElementForm(forms.ModelForm):
366     class Meta:
367         model = PlaylistElement
368         exclude = ('title', 'notes', 'order')
369         widgets = {
370                 'episode': forms.HiddenInput(),
371                 'sound': JqueryFileUploadInput(),
372         }