# -*- coding: utf-8 -*- import datetime import logging import os from django.apps import apps from django.contrib import messages from django.contrib.auth import login from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied, SuspiciousOperation from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import reverse, reverse_lazy from django.utils.decorators import method_decorator from django.utils.translation import ugettext as _ from django.views import generic from .. import choices from .. import forms from .. import models from ..utils import has_role app_config = apps.get_containing_app_config(__package__) logger = logging.getLogger(__name__) class EventListView(generic.ListView): model = models.Event def get_queryset(self): user = self.request.user if user.is_superuser: qs = self.model.objects.all() elif has_role(user, 'manage_all'): qs = self.model.objects.all() else: filter = Q(owner=user) user_sports_list = list() for k in ('W', 'S', 'M', 'K', 'B'): role = 'manage_{}'.format(k.lower()) if has_role(user, role): user_sports_list.append(k) filter |= Q(sport__in=user_sports_list) if has_role(user, 'publish') or has_role(user, 'publish_incremental'): filter |= Q(flags__status__code='accepted') qs = self.model.objects.filter(filter) return qs def get_context_data(self, **kwargs): context = super(EventListView, self).get_context_data(**kwargs) user = self.request.user context['has_permission_export'] = user.is_superuser or has_role(user, 'publish') return context @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): return super(EventListView, self).dispatch(request, *args, **kwargs) class EventListExportView(generic.FormView): form_class = forms.events.EventListExportForm template_name = 'dav_events/event_list_export_form.html' def form_valid(self, form): filename = _(u'Veranstaltungen') filter_kwargs = { 'flags__status__code': 'accepted', } if form.cleaned_data['sport']: sport = form.cleaned_data['sport'] filter_kwargs['sport'] = sport filename += u'--%s' % choices.SPORT_CHOICES.get_label(sport) if form.cleaned_data['begin']: date = form.cleaned_data['begin'] filter_kwargs['first_day__gte'] = date filename += u'--%s' % date.strftime('%Y-%m-%d') if form.cleaned_data['end']: date = form.cleaned_data['end'] filter_kwargs['first_day__lte'] = date filename += u'--%s' % date.strftime('%Y-%m-%d') exclude_expired = not form.cleaned_data.get('expired', False) txt = u'' event_qs = models.Event.objects.filter(**filter_kwargs).order_by('sport', 'first_day') for event in event_qs: if exclude_expired and event.is_flagged('expired'): continue txt += event.render_as_text(format='ka-alpin') if event.internal_note: txt += u'\n> Bearbeitungshinweis:\n> ' + event.internal_note.replace('\n', '\n> ') + u'\n' txt += u'\n' + (u'-' * 72) + '\n\n' filename += u'.txt' response = HttpResponse(txt, content_type='text/plain') response['Content-Disposition'] = 'attachment; filename="{filename}"'.format(filename=filename) return response @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): user = request.user if not user.is_superuser and not has_role(user, 'publish'): raise PermissionDenied('publish') return super(EventListExportView, self).dispatch(request, *args, **kwargs) class EventPermissionMixin(object): permission = 'view' def has_permission(self, permission, obj): user = self.request.user if user.is_superuser: return True if permission == 'view': if user == obj.owner: return True if has_role(user, 'manage_all'): return True if has_role(user, 'manage_{}'.format(obj.sport.lower())): return True if has_role(user, 'publish_incremental') and obj.is_flagged('accepted'): return True if has_role(user, 'publish') and obj.is_flagged('accepted'): return True elif permission == 'submit': if user == obj.owner: return True elif permission == 'accept': if has_role(user, 'manage_all'): return True if has_role(user, 'manage_{}'.format(obj.sport.lower())): return True elif permission == 'publish': if has_role(user, 'publish') or has_role(user, 'publish_incremental'): return True elif permission == 'update': if not obj.is_flagged('submitted'): if user == obj.owner: return True elif not obj.is_flagged('accepted'): if has_role(user, 'manage_all'): return True if has_role(user, 'manage_{}'.format(obj.sport.lower())): return True elif has_role(user, 'publish') or has_role(user, 'publish_incremental'): return True return False def enforce_permission(self, obj): permission = self.permission if not self.has_permission(permission, obj): raise PermissionDenied(permission) class EventDetailView(EventPermissionMixin, generic.DetailView): model = models.Event def get_object(self, queryset=None): obj = super(EventDetailView, self).get_object(queryset=queryset) self.enforce_permission(obj) return obj def get_context_data(self, **kwargs): context = super(EventDetailView, self).get_context_data(**kwargs) obj = context.get('event') context['has_permission_submit'] = self.has_permission('submit', obj) context['has_permission_accept'] = self.has_permission('accept', obj) context['has_permission_publish'] = self.has_permission('publish', obj) context['has_permission_update'] = self.has_permission('update', obj) return context @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): return super(EventDetailView, self).dispatch(request, *args, **kwargs) class EventConfirmStatusView(EventPermissionMixin, generic.DetailView): model = models.Event def get(self, request, *args, **kwargs): status = kwargs.get('status') event = self.get_object() if status == 'submitted': if not self.has_permission('submit', event): raise PermissionDenied(status) elif status == 'accepted': if not self.has_permission('accept', event): raise PermissionDenied(status) if not event.is_flagged('submitted'): messages.error(request, _(u'Veranstaltung ist noch nicht eingereicht.')) return HttpResponseRedirect(event.get_absolute_url()) elif status == 'publishing' or status == 'published': if not self.has_permission('publish', event): raise PermissionDenied(status) if not event.is_flagged('accepted'): messages.error(request, _(u'Veranstaltung ist noch nicht freigegeben.')) return HttpResponseRedirect(event.get_absolute_url()) else: if not self.has_permission('update', event): raise PermissionDenied(status) event.confirm_status(status, request.user) if status == 'submitted': messages.success(request, _(u'Veranstaltung eingereicht.')) elif status == 'accepted': messages.success(request, _(u'Veranstaltung freigegeben.')) elif status == 'publishing' or status == 'published': messages.success(request, _(u'Veröffentlichung registriert.')) else: messages.success(request, _(u'Veranstaltungsstatus registriert.')) return HttpResponseRedirect(event.get_absolute_url()) class EventUpdateView(EventPermissionMixin, generic.UpdateView): permission = 'update' model = models.Event form_class = forms.events.EventUpdateForm template_name_suffix = '_update_form' def get_object(self, queryset=None): obj = super(EventUpdateView, self).get_object(queryset=queryset) self.enforce_permission(obj) return obj def get_context_data(self, **kwargs): context = super(EventUpdateView, self).get_context_data(**kwargs) obj = context.get('event') context['has_permission_accept'] = self.has_permission('accept', obj) context['has_permission_update'] = self.has_permission('update', obj) context['has_permission_publish'] = self.has_permission('publish', obj) return context @method_decorator(login_required) def dispatch(self, request, *args, **kwargs): return super(EventUpdateView, self).dispatch(request, *args, **kwargs) class EventCreateView(EventPermissionMixin, generic.FormView): form_class = forms.events.EventCreateForm template_dir = os.path.join('dav_events', 'event_create') default_template_name = 'default.html' abort_url = reverse_lazy('dav_events:home') def get_template_names(self): form = self.get_form() form_name = form.form_name template = os.path.join(self.template_dir, '{}.html'.format(form_name)) default_template = os.path.join(self.template_dir, self.default_template_name) return [ template, default_template ] def get_form_class(self, form_name=None): if form_name is not None: form_class = getattr(forms.events, form_name) elif 'dav_events_event_create_next_form_name' in self.request.session: form_name = self.request.session['dav_events_event_create_next_form_name'] form_class = getattr(forms.events, form_name) if not issubclass(form_class, self.form_class): raise SuspiciousOperation('Invalid next form: {}'.format(form_name)) else: base_form_class = self.form_class initial_form_name = base_form_class.get_initial_form_name() form_class = getattr(forms.events, initial_form_name) return form_class def get_form_kwargs(self): kwargs = super(EventCreateView, self).get_form_kwargs() if 'request' not in kwargs: kwargs['request'] = self.request return kwargs def get_context_data(self, **kwargs): context = super(EventCreateView, self).get_context_data(**kwargs) context['abort_url'] = self.abort_url return context def form_valid(self, form): event = form.get_instance() next_form_name = form.next_form_name if next_form_name: self.request.session['dav_events_event_create_next_form_name'] = next_form_name next_form_class = self.get_form_class(next_form_name) next_form = next_form_class(request=self.request) return self.render_to_response(self.get_context_data(form=next_form, event=event)) else: event.save() if 'submit' in form.data: event.confirm_status('submitted', event.owner) messages.success(self.request, _(u'Veranstaltung eingereicht.')) else: messages.success(self.request, _(u'Veranstaltung angelegt.')) form.flush_session_data() owner = event.owner self.clean_session_data() if self.request.user.is_authenticated: next_url = reverse('dav_events:event_list') elif owner.has_usable_password(): next_url = reverse('dav_events:event_list') else: login(self.request, owner) next_url = reverse('dav_events:set_password') messages.success(self.request, _(u'Neuen Benutzer angemeldet: %(username)s') % {'username': owner.username}) messages.warning(self.request, _(u'Bitte neues Passwort setzen!')) return HttpResponseRedirect(next_url) def clean_session_data(self, session=None): if session is None: session = self.request.session if 'dav_events_event_create_next_form_name' in session: del session['dav_events_event_create_next_form_name'] def get(self, request, *args, **kwargs): self.clean_session_data(request.session) if 'abort' in request.GET: form = self.get_form() form.flush_session_data() return HttpResponseRedirect(self.abort_url) elif 'copy' in request.GET: event = get_object_or_404(models.Event, pk=request.GET.get('copy')) if not self.has_permission('view', event): raise PermissionDenied('copy') for field in ('id', 'owner', 'created_at', 'accepted_at', 'accepted_by', 'publication_confirmed_at', 'publication_confirmed_by', 'number', 'planned_publication_date', 'internal_note',): if hasattr(event, field): setattr(event, field, None) for field in ('accepted', 'publication_confirmed'): if hasattr(event, field): setattr(event, field, False) initial_form_name = self.form_class.get_initial_form_name() form_class = getattr(forms.events, initial_form_name) form = form_class(request=self.request, instance=event) form.save_session_data() return super(EventCreateView, self).get(request, *args, **kwargs) def post(self, request, *args, **kwargs): return super(EventCreateView, self).post(request, *args, **kwargs)