From 80f5012ff084663b870efaed554c337ebd011b86 Mon Sep 17 00:00:00 2001 From: Jens Kleineheismann Date: Wed, 14 Mar 2018 15:00:23 +0100 Subject: [PATCH] Finalized copy event feature. --- TODO.txt | 3 +- dav_events/forms/events.py | 38 +++++---- dav_events/forms/generic.py | 80 ++++++++++++------- .../templates/dav_events/event_detail.html | 2 +- dav_events/urls.py | 1 - dav_events/views/events.py | 33 ++++---- 6 files changed, 96 insertions(+), 61 deletions(-) diff --git a/TODO.txt b/TODO.txt index 950da2f..22f38af 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,12 +1,11 @@ - Save as Draft -- Copy Event - Tourenreferent managed Gruppen der Subreferenten - Placeholder von forms in config/app_config - Besserer Zurück-Button in Formulare - uhrzeitfelder ohne widget - vorbereitung: textfeld beschreibung einleitung, so dass beschreibung nur auf webseite geht. -- kontaktdaten für 2. und 3. trainer wieder weg +- kontaktdaten für 2. und 3. trainer wieder weg? - erster teil des anmeldungshowto editierbar - publizierendes feld für redaktionellen hinweis - vortreffen ohne datum? diff --git a/dav_events/forms/events.py b/dav_events/forms/events.py index 0182ccb..77624de 100644 --- a/dav_events/forms/events.py +++ b/dav_events/forms/events.py @@ -6,7 +6,7 @@ from babel.dates import format_date from django import forms from django.apps import apps from django.utils.translation import get_language, ugettext, ugettext_lazy as _ -from django_countries.fields import LazyTypedChoiceField +from django_countries.fields import Country, LazyTypedChoiceField from datetimewidget.widgets import DateWidget, TimeWidget, DateTimeWidget from .. import choices @@ -80,6 +80,12 @@ class EventCreateForm(ModelMixin, ChainedForm): _model = models.Event _initial_form_name = 'ModeForm' + def _serialize_value(self, value): + r = super(EventCreateForm, self)._serialize_value(value) + if isinstance(r, Country): + r = r.code + return r + def _get_instance_kwargs(self): kwargs = self._session_data.copy() if 'deadline' in kwargs: @@ -264,8 +270,8 @@ class LocationForm(EventCreateForm): label=_(u'Anderes Verkehrsmittel zur An- und Abreise'), ) - def _proceed_session_data(self, session_data): - super(LocationForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(LocationForm, self).proceed_session_data(session_data) sport = session_data.get('sport', None) last_day = session_data.get('last_day', None) @@ -386,8 +392,8 @@ class JourneyForm(EventCreateForm): return 'AccommodationForm' return super(JourneyForm, self).next_form_name - def _proceed_session_data(self, session_data): - super(JourneyForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(JourneyForm, self).proceed_session_data(session_data) first_day = session_data.get('first_day', None) last_day = session_data.get('last_day', None) @@ -438,8 +444,8 @@ class AccommodationForm(EventCreateForm): label=_(u'Andere Verpflegung'), ) - def _proceed_session_data(self, session_data): - super(AccommodationForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(AccommodationForm, self).proceed_session_data(session_data) self.fields['basecamp'].widget.attrs['placeholder'] = _(u'Kann freigelassen werden') self.fields['accommodation_other'].widget.attrs['placeholder'] = _(u'Nebenstehendes Feld beachten') self.fields['meals_other'].widget.attrs['placeholder'] = _(u'Nebenstehendes Feld beachten') @@ -548,8 +554,8 @@ class TrainerForm(EventCreateForm): help_text=_(u'Kann freigelassen werden'), ) - def _proceed_session_data(self, session_data): - super(TrainerForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(TrainerForm, self).proceed_session_data(session_data) self.fields['trainer_firstname'].widget.attrs['placeholder'] = _(u'Vorname') self.fields['trainer_familyname'].widget.attrs['placeholder'] = _(u'Nachname') @@ -635,8 +641,8 @@ class RegistrationForm(EventCreateForm): return value - def _proceed_session_data(self, session_data): - super(RegistrationForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(RegistrationForm, self).proceed_session_data(session_data) first_day = session_data.get('first_day', None) @@ -705,8 +711,8 @@ class ChargesForm(EventCreateForm): return 'TrainingForm' return super(ChargesForm, self).next_form_name - def _proceed_session_data(self, session_data): - super(ChargesForm, self)._proceed_session_data(session_data) + def proceed_session_data(self, session_data): + super(ChargesForm, self).proceed_session_data(session_data) first_day = session_data.get('first_day', None) arrival_previous_day = session_data.get('arrival_previous_day', False) @@ -890,7 +896,7 @@ class SummaryForm(EventCreateForm): u' für Tourenreferenten und Redakteure eingeben.'), widget=forms.Textarea(attrs={'rows': 5})) - def _proceed_session_data(self, session_data): + def proceed_session_data(self, session_data): registration_required = self._session_data.get('registration_required', False) if registration_required: deadline = self._session_data.get('deadline', None) @@ -901,7 +907,7 @@ class SummaryForm(EventCreateForm): if deadline_field_name in self._session_data: deadline = self._session_data.get(deadline_field_name) else: - logger.error('SummaryForm._proceed_session_data(): invalid value for deadline.') + logger.error('SummaryForm.proceed_session_data(): invalid value for deadline.') deadline = None if deadline: @@ -916,7 +922,7 @@ class SummaryForm(EventCreateForm): for year in (today.year, today.year + 1): for issue in app_config.settings.publish_issues: if not ('issue' in issue and 'release' in issue and 'deadline' in issue): - logger.error('SummaryForm._proceed_session_data(): invalid configured issue.') + logger.error('SummaryForm.proceed_session_data(): invalid configured issue.') continue issue_release = datetime.date(year, issue['release'][1], issue['release'][0]) diff --git a/dav_events/forms/generic.py b/dav_events/forms/generic.py index 6de15a8..e21224f 100644 --- a/dav_events/forms/generic.py +++ b/dav_events/forms/generic.py @@ -17,7 +17,13 @@ class ChainedForm(forms.Form): def __init__(self, *args, **kwargs): self._session_data = dict() self._request = kwargs.pop('request', None) - self._load_session_data() + self.load_session_data() + + if 'instance' in kwargs: + if hasattr(self, 'load_from_instance'): + self._session_data.update(self.load_from_instance(kwargs.pop('instance'))) + else: + raise TypeError('Keyword argument \'instance\' requires method \'load_from_instance\'') if 'initial' not in kwargs: kwargs['initial'] = self._session_data @@ -26,7 +32,7 @@ class ChainedForm(forms.Form): super(ChainedForm, self).__init__(*args, **kwargs) - self._proceed_session_data(self._session_data) + self.proceed_session_data(self._session_data) def _serialize_value(self, value): return converters.Iso8601Serializer.serialize(value, ignore_unsupported_input=True) @@ -34,27 +40,9 @@ class ChainedForm(forms.Form): def _deserialize_value(self, value): return converters.Iso8601Serializer.deserialize(value, ignore_unsupported_input=True) - def _load_session_data(self): - if self._request is not None and hasattr(self._request, 'session'): - session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) - session_data = self._request.session.get(session_var_name, dict()) - for k in session_data: - self._session_data[k] = self._deserialize_value(session_data[k]) - - def _proceed_session_data(self, session_data): - pass - - def _save_session_data(self): - if self._request is not None and hasattr(self._request, 'session'): - session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) - session_data = dict() - for k in self._session_data: - session_data[k] = self._serialize_value(self._session_data[k]) - self._request.session[session_var_name] = session_data - def _post_clean(self): self._session_data.update(self.cleaned_data) - self._save_session_data() + self.save_session_data() @property def form_name(self): @@ -72,6 +60,10 @@ class ChainedForm(forms.Form): def next_form_name(self): return self.__class__.get_next_form_name() + @property + def session_data(self): + return self._session_data + @classmethod def get_form_name(cls): return cls.__name__ @@ -102,6 +94,41 @@ class ChainedForm(forms.Form): value = app_config.settings.form_initials[form_name][field_name].get_value(self._session_data) return value + def load_session_data(self, data=None, request=None): + if data is None: + if request is None: + if self._request is None: + logger.warning('ChainedForm.load_session_data(): Cannot access request.') + return + request = self._request + if not hasattr(request, 'session'): + logger.warning('ChainedForm.load_session_data(): Cannot access session.') + return + session_var_name = '{}_chained_form_session_data'.format(request.resolver_match.url_name) + data = request.session.get(session_var_name, dict()) + for k in data: + self._session_data[k] = self._deserialize_value(data[k]) + + def save_session_data(self, request=None): + if request is None: + if self._request is None: + logger.warning('ChainedForm.save_session_data(): Cannot access request.') + return + request = self._request + if not hasattr(request, 'session'): + logger.warning('ChainedForm.save_session_data(): Cannot access session.') + return + + session_var_name = '{}_chained_form_session_data'.format(request.resolver_match.url_name) + session_data = dict() + for k in self._session_data: + session_data[k] = self._serialize_value(self._session_data[k]) + request.session[session_var_name] = session_data + return session_data + + def proceed_session_data(self, session_data): + pass + def flush_session_data(self): if self._request is not None and hasattr(self._request, 'session'): session_var_name = '{}_chained_form_session_data'.format(self._request.resolver_match.url_name) @@ -135,10 +162,9 @@ class ModelMixin(object): model = self._get_model() if not isinstance(instance, model): raise TypeError('Expected %s' % model.__class__.__name__) - self.is_bound = True - self.data = {} - self.cleaned_data = {} + data = {} for field in instance._meta.get_fields(): - self.data[field.name] = getattr(instance, field.name) - self.cleaned_data[field.name] = getattr(instance, field.name) - self._post_clean() \ No newline at end of file + data[field.name] = getattr(instance, field.name) + self.is_bound = True + self.data = data + return data diff --git a/dav_events/templates/dav_events/event_detail.html b/dav_events/templates/dav_events/event_detail.html index 0e2db91..f646b71 100644 --- a/dav_events/templates/dav_events/event_detail.html +++ b/dav_events/templates/dav_events/event_detail.html @@ -61,7 +61,7 @@
{% bootstrap_icon 'duplicate' %}  {% trans 'Kopieren' %} diff --git a/dav_events/urls.py b/dav_events/urls.py index 0dd15d3..6b584ec 100644 --- a/dav_events/urls.py +++ b/dav_events/urls.py @@ -11,7 +11,6 @@ urlpatterns = [ url(r'^events$', views.events.EventListView.as_view(), name='event_list'), url(r'^events/export$', views.events.EventListExportView.as_view(), name='event_list_export'), url(r'^events/create$', views.events.EventCreateView.as_view(), name='event_create'), - url(r'^events/(?P\d+)/copy', views.events.EventCopyView.as_view(), name='event_copy'), url(r'^events/(?P\d+)/confirmpublication', views.events.EventConfirmPublicationView.as_view(), name='event_confirmpublication'), url(r'^events/(?P\d+)/accept', views.events.EventAcceptView.as_view(), name='event_accept'), diff --git a/dav_events/views/events.py b/dav_events/views/events.py index dcb7c31..d3c6cf4 100644 --- a/dav_events/views/events.py +++ b/dav_events/views/events.py @@ -9,6 +9,7 @@ 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 _ @@ -220,20 +221,7 @@ class EventUpdateView(EventPermissionMixin, generic.UpdateView): return super(EventUpdateView, self).dispatch(request, *args, **kwargs) -class EventCopyView(EventDetailView): - permission = 'view' - form_class = forms.events.EventCreateForm - - def get(self, request, *args, **kwargs): - event = self.get_object() - initial_form_name = self.form_class.get_initial_form_name() - form_class = getattr(forms.events, initial_form_name) - form = form_class(request=self.request) - form.load_from_instance(event) - return HttpResponseRedirect(reverse('dav_events:event_create')) - - -class EventCreateView(generic.FormView): +class EventCreateView(EventPermissionMixin, generic.FormView): form_class = forms.events.EventCreateForm template_dir = os.path.join('dav_events', 'event_create') default_template_name = 'default.html' @@ -313,6 +301,23 @@ class EventCreateView(generic.FormView): 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'): + setattr(event, field, None) + for field in ('accepted', 'publication_confirmed'): + 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):