From cd0e1cb52076dd95d769b6e29fa7439e73de83a4 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 1 Apr 2015 11:54:56 +0200 Subject: [PATCH] Wider usage of the settings framework (#17) --- src/pretix/base/admin.py | 2 +- src/pretix/base/middleware.py | 4 +- .../migrations/0023_auto_20150401_0954.py | 38 ++++++ src/pretix/base/models.py | 45 +------ src/pretix/base/settings.py | 10 +- .../pretixcontrol/event/settings.html | 80 +++++++------ src/pretix/control/views/event.py | 110 +++++++++++++++--- .../templates/pretixpresale/event/base.html | 2 +- src/pretix/presale/views/checkout.py | 8 +- 9 files changed, 198 insertions(+), 101 deletions(-) create mode 100644 src/pretix/base/migrations/0023_auto_20150401_0954.py diff --git a/src/pretix/base/admin.py b/src/pretix/base/admin.py index 862c5afbe..965007593 100644 --- a/src/pretix/base/admin.py +++ b/src/pretix/base/admin.py @@ -88,7 +88,7 @@ class EventAdmin(admin.ModelAdmin): inlines = [EventPermissionInline] list_display = ('name', 'slug', 'organizer', 'date_from') search_fields = ('name', 'slug') - list_filter = ('date_from', 'locale', 'currency') + list_filter = ('date_from', 'currency') class PropertyValueInline(admin.StackedInline): diff --git a/src/pretix/base/middleware.py b/src/pretix/base/middleware.py index 0bd64d392..8f26e4fef 100644 --- a/src/pretix/base/middleware.py +++ b/src/pretix/base/middleware.py @@ -33,7 +33,7 @@ class LocaleMiddleware(BaseLocaleMiddleware): if request.user.is_authenticated(): tzname = request.user.timezone if hasattr(request, 'event'): - tzname = request.event.timezone + tzname = request.event.settings.timezone if tzname: try: timezone.activate(pytz.timezone(tzname)) @@ -72,7 +72,7 @@ def get_language_from_session_or_cookie(request) -> str: def get_language_from_event(request) -> str: if hasattr(request, 'event'): - lang_code = request.event.locale + lang_code = request.event.settings.locale try: return get_supported_language_variant(lang_code) except LookupError: diff --git a/src/pretix/base/migrations/0023_auto_20150401_0954.py b/src/pretix/base/migrations/0023_auto_20150401_0954.py new file mode 100644 index 000000000..e5fca2a59 --- /dev/null +++ b/src/pretix/base/migrations/0023_auto_20150401_0954.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('pretixbase', '0022_auto_20150320_2239'), + ] + + operations = [ + migrations.RemoveField( + model_name='event', + name='locale', + ), + migrations.RemoveField( + model_name='event', + name='payment_term_days', + ), + migrations.RemoveField( + model_name='event', + name='payment_term_last', + ), + migrations.RemoveField( + model_name='event', + name='show_date_to', + ), + migrations.RemoveField( + model_name='event', + name='show_times', + ), + migrations.RemoveField( + model_name='event', + name='timezone', + ), + ] diff --git a/src/pretix/base/models.py b/src/pretix/base/models.py index 2e63908f0..cae4f386b 100644 --- a/src/pretix/base/models.py +++ b/src/pretix/base/models.py @@ -362,32 +362,16 @@ class Event(Versionable): :param slug: A short, alphanumeric, all-lowercase name for use in URLs. The slug has to be unique among the events of the same organizer. :type slug: str - :param locale: This events default locale - :type locale: str - :param timezone: The timezone this event takes place in (or is being described in) - :type timezone: str :param currency: The currency of all prices and payments of this event :type currency: str :param date_from: The datetime this event starts :type date_from: datetime :param date_to: The datetime this event ends :type date_to: datetime - :param show_date_to: If ``False``, the ``date_to`` value will not be shown to the - user and the event will be listed only with it's start date. - :type show_date_to: bool - :param show_times: If ``False``, ``date_from`` and ``date_to`` will only be displayed - as dates, without a time of day. - :type show_times: bool :param presale_start: No tickets will be sold before this date. :type presale_start: datetime :param presale_end: No tickets will be sold before this date. :type presale_end: datetime - :param payment_term_days: The number of days in which an order has to be - paid after it has been submitted. - :type payment_term_days: int - :param payment_term_last: The day all orders must be paid by, no matter when - the order was placed. - :type payment_term_last: datetime :param plugins: A comma-separated list of plugin names that are active for this event. :type plugins: str @@ -412,29 +396,12 @@ class Event(Versionable): ) permitted = models.ManyToManyField(User, through='EventPermission', related_name="events",) - locale = models.CharField(max_length=10, - choices=settings.LANGUAGES, - verbose_name=_("Default locale"), - default=settings.LANGUAGE_CODE) - timezone = models.CharField(max_length=100, - default=settings.TIME_ZONE, - verbose_name=_('Default timezone')) currency = models.CharField(max_length=10, verbose_name=_("Default currency"), default=settings.DEFAULT_CURRENCY) date_from = models.DateTimeField(verbose_name=_("Event start time")) date_to = models.DateTimeField(null=True, blank=True, verbose_name=_("Event end time")) - show_date_to = models.BooleanField( - default=True, - verbose_name=_("Show event end date"), - help_text=_("If disabled, only event's start date will be displayed to the public."), - ) - show_times = models.BooleanField( - default=True, - verbose_name=_("Show dates with time"), - help_text=_("If disabled, the event's start and end date will be displayed without the time of day."), - ) presale_end = models.DateTimeField( null=True, blank=True, verbose_name=_("End of presale"), @@ -445,16 +412,6 @@ class Event(Versionable): verbose_name=_("Start of presale"), help_text=_("No products will be sold before this date."), ) - payment_term_days = models.PositiveIntegerField( - default=14, - verbose_name=_("Payment term in days"), - help_text=_("The number of days after placing an order the user has to pay to preserve his reservation."), - ) - payment_term_last = models.DateTimeField( - null=True, blank=True, - verbose_name=_("Last date of payments"), - help_text=_("The last date any payments are accepted. This has precedence over the number of days configured above.") - ) plugins = models.TextField( null=True, blank=True, verbose_name=_("Plugins"), @@ -498,7 +455,7 @@ class Event(Versionable): to the current locale and to the ``show_times`` setting. Returns an empty string if ``show_date_to`` is ``False``. """ - if not self.show_date_to: + if not self.settings.get('show_date_to', as_type=bool): return "" return _date( self.date_to, diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 8d6bf9b96..f4ae80e01 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -37,6 +37,14 @@ DEFAULTS = { 'default': None, 'type': datetime, }, + 'timezone': { + 'default': settings.TIME_ZONE, + 'type': str + }, + 'locale': { + 'default': settings.LANGUAGE_CODE, + 'type': str + }, 'show_date_to': { 'default': 'True', 'type': bool @@ -50,7 +58,7 @@ DEFAULTS = { 'type': bool }, 'last_order_modification_date': { - 'default': 'None', + 'default': None, 'type': datetime }, 'mail_from': { diff --git a/src/pretix/control/templates/pretixcontrol/event/settings.html b/src/pretix/control/templates/pretixcontrol/event/settings.html index cce15645e..c77f4a23c 100644 --- a/src/pretix/control/templates/pretixcontrol/event/settings.html +++ b/src/pretix/control/templates/pretixcontrol/event/settings.html @@ -2,42 +2,52 @@ {% load i18n %} {% load bootstrap3 %} {% block inside %} -
- {% if "success" in request.GET %} -
- {% trans "Your changes have been saved." %} -
- {% endif %} - {% csrf_token %} -
- {% trans "General information" %} - {% bootstrap_field form.name layout="horizontal" %} - {% bootstrap_field form.slug layout="horizontal" %} - {% bootstrap_field form.date_from layout="horizontal" %} - {% bootstrap_field form.date_to layout="horizontal" %} - {% bootstrap_field form.currency layout="horizontal" %} -
-
- {% trans "Display settings" %} - {% bootstrap_field form.locale layout="horizontal" %} - {% bootstrap_field form.timezone layout="horizontal" %} - {% bootstrap_field form.show_date_to layout="horizontal" %} - {% bootstrap_field form.show_times layout="horizontal" %} -
-
- {% trans "Presale settings" %} - {% bootstrap_field form.presale_start layout="horizontal" %} - {% bootstrap_field form.presale_end layout="horizontal" %} -
-
- {% trans "Payment settings" %} - {% bootstrap_field form.payment_term_days layout="horizontal" %} - {% bootstrap_field form.payment_term_last layout="horizontal" %} -
-
+ + {% if "success" in request.GET %} +
+ {% trans "Your changes have been saved." %} +
+ {% endif %} + {% csrf_token %} +
+ {% trans "General information" %} + {% bootstrap_field form.name layout="horizontal" %} + {% bootstrap_field form.slug layout="horizontal" %} + {% bootstrap_field form.date_from layout="horizontal" %} + {% bootstrap_field form.date_to layout="horizontal" %} + {% bootstrap_field form.currency layout="horizontal" %} +
+
+ {% trans "Display settings" %} + {% bootstrap_field sform.locale layout="horizontal" %} + {% bootstrap_field sform.timezone layout="horizontal" %} + {% bootstrap_field sform.show_date_to layout="horizontal" %} + {% bootstrap_field sform.show_times layout="horizontal" %} +
+
+ {% trans "Timeline" %} + {% bootstrap_field form.presale_start layout="horizontal" %} + {% bootstrap_field form.presale_end layout="horizontal" %} + {% bootstrap_field sform.payment_term_days layout="horizontal" %} + {% bootstrap_field sform.payment_term_last layout="horizontal" %} + {% bootstrap_field sform.last_order_modification_date layout="horizontal" %} +
+
+ {% trans "Order process settings" %} + {% bootstrap_field sform.reservation_time layout="horizontal" %} + {% bootstrap_field sform.max_items_per_order layout="horizontal" %} + {% bootstrap_field sform.user_mail_required layout="horizontal" %} + {% bootstrap_field sform.attendee_names_asked layout="horizontal" %} + {% bootstrap_field sform.attendee_names_required layout="horizontal" %} +
+
+ {% trans "E-Mail settings" %} + {% bootstrap_field sform.mail_from layout="horizontal" %} +
+
-
- +
+ {% endblock %} diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py index 738308c86..c556e93e1 100644 --- a/src/pretix/control/views/event.py +++ b/src/pretix/control/views/event.py @@ -1,4 +1,5 @@ from collections import OrderedDict +from django.conf import settings from django.shortcuts import render, redirect from django.utils.functional import cached_property from django.views.generic.edit import UpdateView @@ -17,10 +18,6 @@ from pretix.control.permissions import EventPermissionRequiredMixin class EventUpdateForm(VersionedModelForm): - timezone = forms.ChoiceField( - choices=((a, a) for a in common_timezones), - label=_("Default timezone"), - ) def clean_slug(self): return self.instance.slug @@ -35,35 +32,122 @@ class EventUpdateForm(VersionedModelForm): fields = [ 'name', 'slug', - 'locale', - 'timezone', 'currency', 'date_from', 'date_to', - 'show_date_to', - 'show_times', 'presale_start', 'presale_end', - 'payment_term_days', - 'payment_term_last', ] +class EventSettingsForm(SettingsForm): + show_date_to = forms.BooleanField( + label=_("Show event end date"), + help_text=_("If disabled, only event's start date will be displayed to the public."), + required=False + ) + show_times = forms.BooleanField( + label=_("Show dates with time"), + help_text=_("If disabled, the event's start and end date will be displayed without the time of day."), + required=False + ) + payment_term_days = forms.IntegerField( + label='Payment term in days', + help_text=_("The number of days after placing an order the user has to pay to preserve his reservation."), + ) + payment_term_last = forms.DateTimeField( + label='Last date of payments', + help_text=_("The last date any payments are accepted. This has precedence over the number of " + "days configured above."), + required=False + ) + last_order_modification_date = forms.DateTimeField( + label='Last date of modifications', + help_text=_("The last date users can modify details of their orders, such as attendee names or " + "answers to questions."), + required=False + ) + timezone = forms.ChoiceField( + choices=((a, a) for a in common_timezones), + label=_("Default timezone"), + ) + locale = forms.ChoiceField( + choices=settings.LANGUAGES, + label=_("Default locale"), + ) + user_mail_required = forms.BooleanField( + label=_("Require e-mail adresses"), + help_text=_("Require all customers to provide an e-mail address."), + required=False + ) + attendee_names_asked = forms.BooleanField( + label=_("Ask for attendee names"), + help_text=_("Ask for a name for all tickets which include admission to the event."), + required=False + ) + attendee_names_required = forms.BooleanField( + label=_("Require attendee names"), + help_text=_("Require customers to fill in the names of all attendees."), + required=False + ) + max_items_per_order = forms.IntegerField( + min_value=1, + label=_("Maximum number of items per order") + ) + reservation_time = forms.IntegerField( + min_value=0, + label=_("Reservation period"), + help_text=_("The number of minutes the items in a user's card are reserved for this user."), + ) + mail_from = forms.EmailField( + label=_("Sender address"), + help_text=_("Sender address for outgoing e-mails") + ) + + class EventUpdate(EventPermissionRequiredMixin, UpdateView): model = Event form_class = EventUpdateForm template_name = 'pretixcontrol/event/settings.html' permission = 'can_change_settings' - def get_object(self, queryset=None) -> Event: + @cached_property + def object(self) -> Event: return self.request.event + def get_object(self, queryset=None) -> Event: + return self.object + + @cached_property + def sform(self): + return EventSettingsForm( + obj=self.object, + prefix='settings', + data=self.request.POST if self.request.method == 'POST' else None + ) + + def get_context_data(self, *args, **kwargs) -> dict: + context = super().get_context_data(*args, **kwargs) + context['sform'] = self.sform + return context + + def form_valid(self, form): + self.sform.save() + return super().form_valid(form) + def get_success_url(self) -> str: return reverse('control:event.settings', kwargs={ - 'organizer': self.get_object().organizer.slug, - 'event': self.get_object().slug, + 'organizer': self.object.organizer.slug, + 'event': self.object.slug, }) + '?success=true' + def post(self, request, *args, **kwargs): + form = self.get_form() + if form.is_valid() and self.sform.is_valid(): + return self.form_valid(form) + else: + return self.form_invalid(form) + class EventPlugins(EventPermissionRequiredMixin, TemplateView, SingleObjectMixin): model = Event diff --git a/src/pretix/presale/templates/pretixpresale/event/base.html b/src/pretix/presale/templates/pretixpresale/event/base.html index 9c34b6e7f..31bcef3be 100644 --- a/src/pretix/presale/templates/pretixpresale/event/base.html +++ b/src/pretix/presale/templates/pretixpresale/event/base.html @@ -33,7 +33,7 @@ {% trans "Login" %} {% endif %} -

{{ event.name }} {{ event.date_from|date }}{% if event.show_date_to %} – {{ event.date_to|date }}{% endif %}

+

{{ event.name }} {{ event.date_from|date }}{% if event.settings.show_date_to %} – {{ event.date_to|date }}{% endif %}

{% if messages %} {% for message in messages %} diff --git a/src/pretix/presale/views/checkout.py b/src/pretix/presale/views/checkout.py index 830d76996..315bd7a65 100644 --- a/src/pretix/presale/views/checkout.py +++ b/src/pretix/presale/views/checkout.py @@ -1,4 +1,4 @@ -from datetime import timedelta +from datetime import timedelta, datetime from django.contrib import messages from django.core.urlresolvers import reverse from django.db import transaction @@ -394,9 +394,9 @@ class OrderConfirm(EventViewMixin, CartDisplayMixin, EventLoginRequiredMixin, Ch total = sum([c.price for c in cartpos]) payment_fee = self.payment_provider.calculate_fee(total) total += payment_fee - expires = [dt + timedelta(days=self.request.event.payment_term_days)] - if self.request.event.payment_term_last: - expires.append(self.request.event.payment_term_last) + expires = [dt + timedelta(days=self.request.event.settings.get('payment_term_days', as_type=int))] + if self.request.event.settings.get('payment_term_last'): + expires.append(self.request.event.settings.get('payment_term_last', as_type=datetime)) order = Order.objects.create( status=Order.STATUS_PENDING, event=self.request.event,