]> git.0d.be Git - panikdb.git/blob - panikdb/emissions/forms.py
edit: add a (bootstrap based, <sigh/>) widget for datetime selection
[panikdb.git] / panikdb / 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.conf import settings
14 from django.template.loader import render_to_string
15
16 from taggit.forms import TagWidget
17 import datetimewidget.widgets
18
19 from .models import Emission, Episode, Diffusion, Schedule, SoundFile
20
21
22 DATETIME_OPTIONS = {
23         'format': 'dd/mm/yyyy hh:ii',
24         'language': 'fr',
25         'weekStart': '1',
26         'autoclose': 'true',
27         }
28
29 class DateTimeWidget(datetimewidget.widgets.DateTimeWidget):
30     def __init__(self, *args, **kwargs):
31         super(DateTimeWidget, self).__init__(*args, options=DATETIME_OPTIONS, **kwargs)
32
33
34 def slugify(s):
35     s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').lower()
36     return re.sub(r'\W+', '-', s)
37
38
39 class DayAndHourWidget(forms.MultiWidget):
40     def __init__(self, attrs=None):
41         WEEKDAYS = [u'Lundi', u'Mardi', u'Mercredi', u'Jeudi', u'Vendredi', u'Samedi', u'Dimanche']
42         widgets = (
43             forms.Select(attrs=attrs, choices=([(weekday, WEEKDAYS[weekday]) for weekday in range(7)])),
44             forms.Select(attrs=attrs, choices=([(hour, hour) for hour in range(24)])),
45             forms.Select(attrs=attrs, choices=([(minute, str(minute).zfill(2)) for minute in range(60)])),
46         )
47         super(DayAndHourWidget, self).__init__(widgets, attrs)
48
49     def decompress(self, value):
50         if value:
51             return [value.weekday(), value.hour, value.minute]
52         return [None, None, None]
53
54     def value_from_datadict(self, data, files, name):
55         # we only care about day/hour/minutes, but we conveniently use a
56         # datetime value to store that; we pick 2007 as reference year as
57         # it had its January 1st on a Monday.
58         data_list = [
59             widget.value_from_datadict(data, files, name + '_%s' % i)
60             for i, widget in enumerate(self.widgets)]
61
62         if data_list:
63             return datetime.datetime(2007, 1, int(data_list[0])+1, int(data_list[1]), int(data_list[2]))
64         return None
65
66
67 class JqueryFileUploadFileInput(forms.FileInput):
68     def render(self, name, value, attrs=None):
69         output = render_to_string('emissions/upload.html', {
70             'upload_url': self.url,
71             'files': self.files,
72             'name': name,
73             'STATIC_URL': settings.STATIC_URL})
74         return mark_safe(output)
75
76
77 class JqueryFileUploadInput(forms.MultiWidget):
78     needs_multipart_form = True
79     upload_id_re = re.compile(r'^[a-z0-9A-Z-]+$')
80     upload_id = None
81
82     def __init__(self, attrs=None, choices=[], max_filename_length=None):
83         self.max_filename_length = max_filename_length
84         widget_list = (forms.HiddenInput(attrs=attrs),
85                 JqueryFileUploadFileInput(attrs=attrs))
86         super(JqueryFileUploadInput, self).__init__(widget_list, attrs)
87
88     def decompress(self, value):
89         # map python value to widget contents
90         if self.upload_id:
91             pass
92         elif isinstance(value, (list, tuple)) and value and value[0] is not None:
93             self.upload_id = str(value[0])
94         else:
95             self.upload_id = str(uuid.uuid4())
96         return [self.upload_id, None]
97
98     def get_files_for_id(self, upload_id):
99         storage = DefaultStorage()
100         path = os.path.join('upload', upload_id)
101         if not storage.exists(path):
102             return
103         for filepath in storage.listdir(path)[1]:
104             name = os.path.basename(filepath)
105             yield storage.open(os.path.join(path, name))
106
107     def value_from_datadict(self, data, files, name):
108         '''
109            If some file was submitted, that's the value,
110            If a regular hidden_id is present, use it to find uploaded files,
111            otherwise return an empty list
112         '''
113         upload_id, file_input = super(JqueryFileUploadInput, self).value_from_datadict(data, files, name)
114         if file_input:
115             pass
116         elif JqueryFileUploadInput.upload_id_re.match(upload_id):
117             file_input = list(self.get_files_for_id(upload_id))
118         else:
119             file_input = []
120         return file_input[0]
121
122     def render(self, name, value, attrs=None):
123         self.decompress(value)
124         self.widgets[1].url = '/upload/%s/' % self.upload_id
125         self.widgets[1].url = reverse('upload', kwargs={'transaction_id': self.upload_id})
126         if self.max_filename_length:
127             self.widgets[1].url += '?max_filename_length=%d' % self.max_filename_length
128         self.widgets[1].files = '/upload/%s/' % self.get_files_for_id(self.upload_id)
129         output = super(JqueryFileUploadInput, self).render(name, value,
130                 attrs)
131         fileinput_id = '%s_%s' % (attrs['id'], '1')
132         return output
133
134
135 class EmissionForm(forms.ModelForm):
136     class Meta:
137         model = Emission
138         exclude = ('slug',)
139
140     def save(self, commit=True):
141         if not self.instance.slug:
142             self.instance.slug = slugify(self.instance.title)
143         return super(EmissionForm, self).save(commit=commit)
144
145
146 class EpisodeForm(forms.ModelForm):
147     class Meta:
148         model = Episode
149         exclude = ('slug',)
150         widgets = {'emission': forms.HiddenInput(),
151                    'tags': TagWidget()}
152
153     def save(self, commit=True):
154         if not self.instance.slug:
155             self.instance.slug = slugify(self.instance.title)
156         return super(EpisodeForm, self).save(commit=commit)
157
158
159 class EpisodeNewForm(EpisodeForm):
160     diffusion = forms.DateTimeField(label='First Diffusion',
161             widget=DateTimeWidget)
162
163     def save(self, commit=True):
164         episode = super(EpisodeNewForm, self).save(commit=commit)
165         diffusion = Diffusion()
166         diffusion.episode_id = episode.id
167         diffusion.datetime = self.cleaned_data.get('diffusion')
168         diffusion.save()
169         return episode
170
171
172 class ScheduleForm(forms.ModelForm):
173     class Meta:
174         model = Schedule
175         widgets = {
176                 'emission': forms.HiddenInput(),
177                 'datetime': DayAndHourWidget(),
178         }
179
180
181 class SoundFileForm(forms.ModelForm):
182     class Meta:
183         model = SoundFile
184         widgets = {
185                 'episode': forms.HiddenInput(),
186                 'file': JqueryFileUploadInput(),
187         }
188
189
190 class DiffusionForm(forms.ModelForm):
191     class Meta:
192         model = Diffusion
193         widgets = {
194                 'episode': forms.HiddenInput(),
195                 'datetime': DateTimeWidget(),
196         }