]> git.0d.be Git - django-panik-emissions.git/blob - emissions/views.py
74d31a1a3cbb7e8225cf91f3fc0ba098b4fc151e
[django-panik-emissions.git] / emissions / views.py
1 import datetime
2 import json
3 import os
4 import time
5
6 from django.conf import settings
7 from django.core.exceptions import PermissionDenied
8 from django.core.files.storage import DefaultStorage
9 from django.core.urlresolvers import reverse_lazy
10 from django.http import HttpResponse, Http404, HttpResponseRedirect
11 from django.core.urlresolvers import reverse, reverse_lazy
12 from django.shortcuts import redirect
13 from django.utils.translation import ugettext as _, ugettext_lazy
14
15 from django.views.decorators.csrf import csrf_exempt
16 from django.views.generic.base import View, TemplateView, RedirectView
17 from django.views.generic.edit import CreateView, UpdateView, DeleteView
18 from django.views.generic.list import ListView
19 from django.views.generic.detail import DetailView
20
21 from django.contrib import messages
22
23 import haystack.views
24
25 from .models import Emission, Episode, Diffusion, Category, Schedule, \
26                     SoundFile, NewsItem, NewsCategory, Absence, \
27                     PlaylistElement
28 from .forms import EmissionForm, EpisodeForm, EpisodeNewForm, ScheduleForm, \
29                    DiffusionForm, SoundFileForm, NewsItemForm, \
30                    SoundFileEditForm, AbsenceForm, PlaylistElementForm
31
32
33 __all__ = ['EmissionListView', 'EmissionDetailView', 'EmissionCreateView',
34            'EmissionUpdateView', 'EmissionDeleteView',
35            'EpisodeCreateView', 'EpisodeDetailView', 'EpisodeUpdateView',
36            'EpisodeDeleteView', 'EmissionAddScheduleView',
37            'ScheduleDeleteView', 'CategoryListView', 'DaysView',
38            'UploadView', 'EpisodeAddSoundFileView',
39            'EpisodeAddDiffusionView', 'DiffusionDeleteView',
40            'EmissionNewsItemAdd', 'NewsItemDetailView',
41            'NewsItemUpdateView', 'CategoryNewsItemAddView',
42            'NewsItemDeleteView', 'NewsItemAddView',
43            'SoundFileDeleteView', 'SoundFileUpdateView',
44            'EmissionAddAbsenceView', 'AbsenceDeleteView',
45            'EmissionOpenChatView', 'EmissionCloseChatView',
46            'EpisodeRegieView',
47            'EpisodeRegieUpdateOrderView',
48            'EpisodeRegieMarks',
49            ]
50
51
52 SUCCESS_MESSAGE = ugettext_lazy('Your changes will appear online in a few minutes.')
53
54
55 class EmissionListView(ListView):
56     model = Emission
57
58     def get_queryset(self):
59         return Emission.objects.order_by('title')
60
61
62 class CategoryListView(ListView):
63     model = Category
64
65     def get_queryset(self):
66         return Category.objects.order_by('title')
67
68
69 class EmissionDetailView(DetailView):
70     model = Emission
71
72     def get_context_data(self, **kwargs):
73         context = super(EmissionDetailView, self).get_context_data(**kwargs)
74         context['add_schedule_form'] = ScheduleForm(initial={'emission': self.object})
75         context['add_absence_form'] = AbsenceForm(
76                 initial={'emission': self.object, 'user': self.request.user})
77         context['schedules'] = Schedule.objects.select_related().filter(
78                 emission=self.object).order_by('datetime')
79
80         # get all episodes, with an additional attribute to get the date of
81         # their first diffusion
82         context['episodes'] = \
83                 Episode.objects.select_related().filter(emission=self.object
84                     ).extra(select={
85                         'first_diffusion': 'emissions_diffusion.datetime',
86                         },
87                         select_params=(False, True),
88                         where=['''datetime = (SELECT MIN(datetime)
89                                                 FROM emissions_diffusion
90                                                WHERE episode_id = emissions_episode.id)'''],
91                         tables=['emissions_diffusion'],
92                     ).order_by('-first_diffusion').distinct()
93
94         # get all related soundfiles in a single query
95         soundfiles = {}
96         for soundfile in SoundFile.objects.filter(podcastable=True,
97                 fragment=False, episode__emission=self.object):
98             soundfiles[soundfile.episode_id] = soundfile
99
100         Episode.set_prefetched_soundfiles(soundfiles)
101
102         context['newsitems'] = self.object.get_sorted_newsitems()
103         context['absences'] = self.object.absence_set.select_related(
104                 ).filter(datetime__gte=datetime.date.today()).order_by('datetime')
105
106         if not 'all' in self.request.GET:
107             context['episodes'] = context['episodes'][:10]
108             if context['absences']:
109                 context['newsitems'] = context['newsitems'][:5]
110             else:
111                 context['newsitems'] = context['newsitems'][:10]
112
113         try:
114             context['can_manage'] = self.request.user.can_manage(self.object)
115         except AttributeError:
116             pass
117
118         return context
119
120
121 class EmissionCreateView(CreateView):
122     form_class = EmissionForm
123     model = Emission
124
125     success_url = reverse_lazy('emission-list')
126
127     def get_form(self, *args, **kwargs):
128         if not self.request.user.has_perm('emissions.add_emission'):
129             raise PermissionDenied()
130         return super(EmissionCreateView, self).get_form(*args, **kwargs)
131
132     def get_success_url(self):
133         messages.success(self.request, SUCCESS_MESSAGE)
134         return super(EmissionCreateView, self).get_success_url()
135
136
137 class EmissionUpdateView(UpdateView):
138     form_class = EmissionForm
139     model = Emission
140
141     def get_form(self, *args, **kwargs):
142         if not self.request.user.can_manage(self.object):
143             raise PermissionDenied()
144         return super(EmissionUpdateView, self).get_form(*args, **kwargs)
145
146     def get_success_url(self):
147         messages.success(self.request, SUCCESS_MESSAGE)
148         return super(EmissionUpdateView, self).get_success_url()
149
150
151 class EmissionDeleteView(DeleteView):
152     model = Emission
153     success_url = reverse_lazy('home')
154
155     def get_form(self, *args, **kwargs):
156         if not self.request.user.can_manage(self.object):
157             raise PermissionDenied()
158         return super(EmissionDeleteView, self).get_form(*args, **kwargs)
159
160     def get_success_url(self):
161         messages.success(self.request, SUCCESS_MESSAGE)
162         return super(EmissionDeleteView, self).get_success_url()
163
164
165 class EpisodeCreateView(CreateView):
166     model = Episode
167     form_class = EpisodeNewForm
168
169     def get_form(self, *args, **kwargs):
170         emission = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
171         if not self.request.user.can_manage(emission):
172             raise PermissionDenied()
173         return super(EpisodeCreateView, self).get_form(*args, **kwargs)
174
175     def get_initial(self):
176         initial = super(EpisodeCreateView, self).get_initial()
177         initial['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
178         initial['duration'] = initial['emission'].duration
179         initial['first_diffusion'] = initial['emission'].get_next_planned_date()
180         for i, schedule in enumerate(
181                 Schedule.objects.filter(emission=initial['emission'],
182                     rerun=True).order_by('datetime')):
183             rerun_date = schedule.get_next_planned_date(initial['first_diffusion'])
184             if i == 0:
185                 initial['second_diffusion'] = rerun_date
186             elif i == 1:
187                 initial['third_diffusion'] = rerun_date
188             elif i == 2:
189                 initial['fourth_diffusion'] = rerun_date
190         return initial
191
192     def get_context_data(self, **kwargs):
193         context = super(EpisodeCreateView, self).get_context_data(**kwargs)
194         context['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
195         return context
196
197     def get_success_url(self):
198         messages.success(self.request, SUCCESS_MESSAGE)
199         return self.object.get_absolute_url()
200
201
202 class EpisodeDetailView(DetailView):
203     model = Episode
204
205     def get_context_data(self, **kwargs):
206         context = super(EpisodeDetailView, self).get_context_data(**kwargs)
207         context['diffusions'] = Diffusion.objects.filter(episode=self.object.id)
208         context['soundfiles'] = SoundFile.objects.filter(episode=self.object.id)
209         context['add_soundfile_form'] = SoundFileForm(initial={
210             'episode': self.object, 'title': _('Record')})
211         context['add_diffusion_form'] = DiffusionForm(initial={'episode': self.object})
212
213         try:
214             context['can_manage'] = self.request.user.can_manage(self.object.emission)
215         except AttributeError:
216             pass
217
218         return context
219
220
221 class EpisodeUpdateView(UpdateView):
222     form_class = EpisodeForm
223     model = Episode
224
225     def get_form(self, *args, **kwargs):
226         if not self.request.user.can_manage(self.object.emission):
227             raise PermissionDenied()
228         return super(EpisodeUpdateView, self).get_form(*args, **kwargs)
229
230     def get_success_url(self):
231         messages.success(self.request, SUCCESS_MESSAGE)
232         return super(EpisodeUpdateView, self).get_success_url()
233
234
235 class EpisodeDeleteView(DeleteView):
236     model = Episode
237
238     def get_form(self, *args, **kwargs):
239         if not self.request.user.can_manage(self.object.emission):
240             raise PermissionDenied()
241         return super(EpisodeDeleteView, self).get_form(*args, **kwargs)
242
243     def get_success_url(self):
244         messages.success(self.request, SUCCESS_MESSAGE)
245         return reverse('emission-view', kwargs={
246             'slug': self.object.emission.slug})
247
248
249 class EmissionAddScheduleView(CreateView):
250     form_class = ScheduleForm
251     model = Schedule
252
253     def get_form(self, *args, **kwargs):
254         if not self.request.user.has_perm('emissions.add_schedule'):
255             raise PermissionDenied()
256         return super(EmissionAddScheduleView, self).get_form(*args, **kwargs)
257
258     def get_success_url(self):
259         messages.success(self.request, SUCCESS_MESSAGE)
260         return self.object.emission.get_absolute_url()
261
262
263 class ScheduleDeleteView(RedirectView):
264     def get_redirect_url(self, emission_slug, pk):
265         if not self.request.user.has_perm('emissions.delete_schedule'):
266             raise PermissionDenied()
267         Schedule.objects.filter(id=pk).delete()
268         messages.success(self.request, SUCCESS_MESSAGE)
269         return reverse('emission-view', kwargs={'slug': str(emission_slug)})
270
271
272 class EmissionAddAbsenceView(CreateView):
273     form_class = AbsenceForm
274     model = Absence
275
276     def get_initial(self):
277         initial = super(EmissionAddAbsenceView, self).get_initial()
278         initial['emission'] = Emission.objects.get(slug=self.kwargs.get('slug'))
279         initial['user'] = self.request.user
280         return initial
281
282     def get_success_url(self):
283         messages.success(self.request, SUCCESS_MESSAGE)
284         return self.object.emission.get_absolute_url()
285
286     def get_form(self, *args, **kwargs):
287         emission = Emission.objects.get(slug=self.kwargs.get('slug'))
288         if not self.request.user.can_manage(emission):
289             raise PermissionDenied()
290         return super(EmissionAddAbsenceView, self).get_form(*args, **kwargs)
291
292
293 class AbsenceDeleteView(RedirectView):
294     def get_redirect_url(self, emission_slug, pk):
295         if not self.request.user.has_perm('emissions.delete_absence'):
296             raise PermissionDenied()
297         Absence.objects.filter(id=pk).delete()
298         messages.success(self.request, SUCCESS_MESSAGE)
299         return reverse('emission-view', kwargs={'slug': str(emission_slug)})
300
301
302 class DaysView(TemplateView):
303     template_name = 'emissions/days.html'
304
305     def get_context_data(self, **kwargs):
306         context = super(DaysView, self).get_context_data(**kwargs)
307         schedules = Schedule.objects.all().order_by('datetime')
308         days = []
309         for day in range(7):
310             days.append({'schedules': [x for x in schedules if x.is_on_weekday(day+1)],
311                          'datetime': datetime.datetime(2007, 1, day+1)})
312         context['days'] = days
313         return context
314
315 class JSONResponse(HttpResponse):
316     """JSON response class."""
317     def __init__(self, obj='', json_opts={}, mimetype='application/json', *args, **kwargs):
318         content = json.dumps(obj, **json_opts)
319         super(JSONResponse,self).__init__(content, mimetype, *args, **kwargs)
320
321
322 class UploadView(View):
323
324     def response_mimetype(self, request):
325         if 'application/json' in request.META['HTTP_ACCEPT']:
326             return 'application/json'
327         else:
328             return 'text/plain'
329
330     @csrf_exempt
331     def post(self, request, transaction_id):
332         storage = DefaultStorage()
333         max_filename_length = 256
334         url = reverse('upload', kwargs={'transaction_id': transaction_id})
335         if request.FILES is None:
336             response = JSONResponse({}, {}, self.response_mimetype(request))
337             response['Content-Disposition'] = 'inline; filename=files.json'
338             return response
339         data = []
340         for uploaded_file in request.FILES.values():
341             path = os.path.join('upload', str(transaction_id), uploaded_file.name)
342             filename = storage.save(path, uploaded_file)
343             url = '%s%s' % (url, os.path.basename(filename))
344             data.append({'name': uploaded_file.name, 'size': uploaded_file.size, 'url': url})
345         response = JSONResponse(data, {}, self.response_mimetype(request))
346         response['Content-Disposition'] = 'inline; filename=files.json'
347         return response
348
349
350 class EpisodeAddSoundFileView(CreateView):
351     form_class = SoundFileForm
352     model = SoundFile
353
354     def get_form(self, *args, **kwargs):
355         emission = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
356         if not self.request.user.can_manage(emission):
357             raise PermissionDenied()
358         return super(EpisodeAddSoundFileView, self).get_form(*args, **kwargs)
359
360     def get_success_url(self):
361         messages.success(self.request, SUCCESS_MESSAGE)
362         return self.object.episode.get_absolute_url()
363
364
365 class EpisodeAddDiffusionView(CreateView):
366     form_class = DiffusionForm
367     model = Diffusion
368
369     def get_form(self, *args, **kwargs):
370         if not self.request.user.has_perm('emissions.add_diffusion'):
371             raise PermissionDenied()
372         episode = Episode.objects.get(slug=self.kwargs.get('slug'),
373                 emission__slug=self.kwargs.get('emission_slug'))
374         if not self.request.user.can_manage(episode):
375             raise PermissionDenied()
376         return super(EpisodeAddDiffusionView, self).get_form(*args, **kwargs)
377
378     def get_success_url(self):
379         messages.success(self.request, SUCCESS_MESSAGE)
380         return self.object.episode.get_absolute_url()
381
382
383 class DiffusionDeleteView(RedirectView):
384     def get_redirect_url(self, emission_slug, slug, pk):
385         if not self.request.user.has_perm('emissions.delete_diffusion'):
386             raise PermissionDenied()
387         episode = Episode.objects.get(slug=slug, emission__slug=emission_slug)
388         if not self.request.user.can_manage(episode):
389             raise PermissionDenied()
390         Diffusion.objects.filter(id=pk).delete()
391         messages.success(self.request, SUCCESS_MESSAGE)
392         return reverse('episode-view', kwargs={'emission_slug': str(emission_slug),
393                                                'slug': str(slug)})
394
395
396 class FacetedSearchView(haystack.views.FacetedSearchView):
397     def extra_context(self):
398         context = super(FacetedSearchView, self).extra_context()
399         context['selected_categories'] = [
400                 x.split(':', 1)[1] for x in self.request.GET.getlist('selected_facets')
401                 if x.startswith('categories_exact')]
402         context['selected_tags'] = [
403                 x.split(':', 1)[1] for x in self.request.GET.getlist('selected_facets')
404                 if x.startswith('tags_exact')]
405         return context
406
407
408 class EmissionNewsItemAdd(CreateView):
409     model = NewsItem
410     form_class = NewsItemForm
411
412     def get_form(self, *args, **kwargs):
413         emission = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
414         if not self.request.user.can_manage(emission):
415             raise PermissionDenied()
416         return super(EmissionNewsItemAdd, self).get_form(*args, **kwargs)
417
418     def get_initial(self):
419         initial = super(EmissionNewsItemAdd, self).get_initial()
420         initial['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
421         initial['date'] = datetime.datetime.today()
422         initial['user'] = self.request.user
423         return initial
424
425     def get_context_data(self, **kwargs):
426         context = super(EmissionNewsItemAdd, self).get_context_data(**kwargs)
427         context['emission'] = Emission.objects.get(slug=self.kwargs.get('emission_slug'))
428         return context
429
430     def get_success_url(self):
431         messages.success(self.request, SUCCESS_MESSAGE)
432         return self.object.get_absolute_url()
433
434
435 class NewsItemDetailView(DetailView):
436     model = NewsItem
437
438     def get_context_data(self, **kwargs):
439         context = super(NewsItemDetailView, self).get_context_data(**kwargs)
440         context['can_manage'] = self.request.user.can_manage(self.object)
441         return context
442
443
444 class NewsItemUpdateView(UpdateView):
445     form_class = NewsItemForm
446     model = NewsItem
447
448     def get_form(self, *args, **kwargs):
449         if not self.request.user.can_manage(self.object):
450             raise PermissionDenied()
451         return super(NewsItemUpdateView, self).get_form(*args, **kwargs)
452
453     def get_initial(self):
454         initial = super(NewsItemUpdateView, self).get_initial()
455         initial['user'] = self.request.user
456         return initial
457
458     def get_success_url(self):
459         messages.success(self.request, SUCCESS_MESSAGE)
460         return super(NewsItemUpdateView, self).get_success_url()
461
462
463 class CategoryNewsItemAddView(CreateView):
464     model = NewsItem
465     form_class = NewsItemForm
466
467     def get_form(self, *args, **kwargs):
468         if not self.request.user.has_perm('emissions.add_newsitem'):
469             raise PermissionDenied()
470         return super(CategoryNewsItemAddView, self).get_form(*args, **kwargs)
471
472     def get_initial(self):
473         initial = super(CategoryNewsItemAddView, self).get_initial()
474         initial['category'] = NewsCategory.objects.get(slug=self.kwargs.get('slug'))
475         initial['date'] = datetime.datetime.today()
476         initial['user'] = self.request.user
477         return initial
478
479     def get_success_url(self):
480         messages.success(self.request, SUCCESS_MESSAGE)
481         return self.object.get_absolute_url()
482
483
484 class NewsItemAddView(CreateView):
485     model = NewsItem
486     form_class = NewsItemForm
487
488     def get_form(self, *args, **kwargs):
489         if not self.request.user.has_perm('emissions.add_newsitem'):
490             raise PermissionDenied()
491         return super(NewsItemAddView, self).get_form(*args, **kwargs)
492
493     def get_initial(self):
494         initial = super(NewsItemAddView, self).get_initial()
495         initial['date'] = datetime.datetime.today()
496         initial['user'] = self.request.user
497         return initial
498
499     def get_success_url(self):
500         messages.success(self.request, SUCCESS_MESSAGE)
501         return self.object.get_absolute_url()
502
503
504 class NewsItemDeleteView(DeleteView):
505     model = NewsItem
506     success_url = reverse_lazy('home')
507
508     def get_form(self, *args, **kwargs):
509         if not self.request.user.can_manage(self.object):
510             raise PermissionDenied()
511         return super(NewsItemDeleteView, self).get_form(*args, **kwargs)
512
513     def get_success_url(self):
514         messages.success(self.request, SUCCESS_MESSAGE)
515         return super(NewsItemDeleteView, self).get_success_url()
516
517
518 class SoundFileDeleteView(DeleteView):
519     model = SoundFile
520
521     def get_form(self, *args, **kwargs):
522         if not self.request.user.can_manage(self.object):
523             raise PermissionDenied()
524         return super(SoundFileDeleteView, self).get_form(*args, **kwargs)
525
526     def get_success_url(self):
527         messages.success(self.request, SUCCESS_MESSAGE)
528         return reverse('episode-view', kwargs={
529             'emission_slug': self.object.episode.emission.slug,
530             'slug': self.object.episode.slug})
531
532
533 class SoundFileUpdateView(UpdateView):
534     template_name_suffix = '_form_update'
535     form_class = SoundFileEditForm
536     model = SoundFile
537
538     def get_form(self, *args, **kwargs):
539         if not self.request.user.can_manage(self.object.episode.emission):
540             raise PermissionDenied()
541         return super(SoundFileUpdateView, self).get_form(*args, **kwargs)
542
543     def get_success_url(self):
544         messages.success(self.request, SUCCESS_MESSAGE)
545         return '../../'
546
547
548 class EmissionOpenChatView(DetailView):
549     model = Emission
550
551     def render_to_response(self, context):
552         self.object.chat_open = datetime.datetime.now()
553         self.object.save()
554         return redirect(self.object.get_absolute_url())
555
556
557 class EmissionCloseChatView(DetailView):
558     model = Emission
559
560     def render_to_response(self, context):
561         self.object.chat_open = None
562         self.object.save()
563         return redirect(self.object.get_absolute_url())
564
565
566 class EpisodeRegieView(DetailView):
567     model = Episode
568     template_name = 'emissions/episode_regie.html'
569
570     def get_object(self, queryset=None):
571         try:
572             return Episode.objects.get(slug=self.kwargs.get('slug'),
573                     emission__slug=self.kwargs.get('emission_slug'))
574         except Episode.DoesNotExist:
575             raise Http404()
576
577     def post(self, request, *args, **kwargs):
578         episode = self.get_object()
579         form = PlaylistElementForm(request.POST, request.FILES)
580         if not form.is_valid():
581             messages.error(request, _('Error adding file'))
582             return HttpResponseRedirect('.')
583         i = PlaylistElement.objects.filter(episode=episode).count()
584         playlist_element = PlaylistElement(
585                 episode=episode,
586                 title=os.path.basename(form.cleaned_data['sound'].name),
587                 sound=form.cleaned_data['sound'],
588                 order=i+1)
589         playlist_element.save()
590         messages.info(request, _('File uploaded successfully.'))
591         return HttpResponseRedirect('.')
592
593     def get_context_data(self, **kwargs):
594         context = super(EpisodeRegieView, self).get_context_data(**kwargs)
595         context['playlist'] = PlaylistElement.objects.filter(episode=self.object.id)
596         context['start_time'] = ''
597         context['end_time'] = ''
598         if self.object.effective_start:
599             context['ready'] = 'ready'
600             context['start_time'] = int(time.mktime(self.object.effective_start.timetuple())*1000
601                     + self.object.effective_start.microsecond/1000)
602         if self.object.effective_end:
603             context['end_time'] = int(time.mktime(self.object.effective_end.timetuple())*1000
604                     + self.object.effective_end.microsecond/1000)
605             context['download_url'] = self.object.get_pige_download_url()
606
607         try:
608             context['can_manage'] = self.request.user.can_manage(self.object)
609         except AttributeError:
610             pass
611
612         context['upload_file_form'] = PlaylistElementForm(initial={'episode': self.object})
613
614         return context
615
616 class EpisodeRegieUpdateOrderView(View):
617     def get(self, request, *args, **kwargs):
618         new_order = request.GET.getlist('new-order[]')
619         for element in PlaylistElement.objects.filter(id__in=new_order):
620             element.order = new_order.index(str(element.id)) + 1
621             element.save()
622         return HttpResponse('ok')
623
624
625 class EpisodeRegieMarks(EpisodeRegieView):
626     def get(self, request, *args, **kwargs):
627         episode = self.get_object()
628         start = self.request.GET['start']
629         end = self.request.GET['end']
630         if start:
631             episode.effective_start = datetime.datetime.fromtimestamp(float(start)/1000)
632         else:
633             episode.effective_start = None
634         if end:
635             episode.effective_end = datetime.datetime.fromtimestamp(float(end)/1000)
636         else:
637             episode.effective_end = None
638         episode.save()
639         obj = {'err': 0}
640         if end:
641             obj['pige_download_url'] = episode.get_pige_download_url()
642         return JSONResponse(obj)