diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py index 2ae2eb1b9e..b86a6252b6 100644 --- a/src/pretix/base/models/event.py +++ b/src/pretix/base/models/event.py @@ -2,6 +2,7 @@ import string import uuid from collections import OrderedDict from datetime import datetime, time +from operator import attrgetter import pytz from django.conf import settings @@ -535,6 +536,23 @@ class Event(EventMixin, LoggedModel): ) ).order_by('date_from', 'name') + @property + def subevent_list_subevents(self): + ordering = self.settings.get('frontpage_subevent_ordering', default='date_ascending', as_type=str) + orderfields = { + 'date_ascending': ('date_from', 'name'), + 'date_descending': ('-date_from', 'name'), + 'name_ascending': ('name', 'date_from'), + 'name_descending': ('-name', 'date_from'), + }[ordering] + subevs = self.subevents.filter( + Q(active=True) & ( + Q(Q(date_to__isnull=True) & Q(date_from__gte=now())) + | Q(date_to__gte=now()) + ) + ) # order_by doesn't make sense with I18nField + return sorted(subevs, key=attrgetter(*orderfields)) + @property def meta_data(self): data = {p.name: p.default for p in self.organizer.meta_properties.all()} diff --git a/src/pretix/base/settings.py b/src/pretix/base/settings.py index 30de1cb559..3452a20a6d 100644 --- a/src/pretix/base/settings.py +++ b/src/pretix/base/settings.py @@ -495,6 +495,10 @@ Your {event} team""")) 'default': '', 'type': LazyI18nString }, + 'frontpage_subevent_ordering': { + 'default': 'date_ascending', + 'type': str + }, } settings_hierarkey = Hierarkey(attribute_name='settings') diff --git a/src/pretix/control/forms/event.py b/src/pretix/control/forms/event.py index fd664faea8..87fefae0ce 100644 --- a/src/pretix/control/forms/event.py +++ b/src/pretix/control/forms/event.py @@ -6,7 +6,9 @@ from django.core.validators import RegexValidator from django.db.models import Q from django.forms import formset_factory from django.utils.timezone import get_current_timezone_name -from django.utils.translation import pgettext_lazy, ugettext_lazy as _ +from django.utils.translation import ( + pgettext, pgettext_lazy, ugettext_lazy as _, +) from django_countries import Countries from django_countries.fields import LazyTypedChoiceField from i18nfield.forms import ( @@ -854,12 +856,24 @@ class DisplaySettingsForm(SettingsForm): label=_("Show variations of a product expanded by default"), required=False ) + frontpage_subevent_ordering = forms.ChoiceField( + label=pgettext('subevent', 'Date ordering'), + choices=[ + ('date_ascending', _('Event start time')), + ('date_descending', _('Event start time (descending)')), + ('name_ascending', _('Name')), + ('name_descending', _('Name (descending)')), + ], # When adding a new ordering, remember to also define it in the event model + ) def __init__(self, *args, **kwargs): + event = kwargs['obj'] super().__init__(*args, **kwargs) self.fields['primary_font'].choices += [ (a, a) for a in get_fonts() ] + if not event.has_subevents: + del self.fields['frontpage_subevent_ordering'] class TicketSettingsForm(SettingsForm): diff --git a/src/pretix/control/templates/pretixcontrol/event/display.html b/src/pretix/control/templates/pretixcontrol/event/display.html index dcca5883c7..bb781a2bd8 100644 --- a/src/pretix/control/templates/pretixcontrol/event/display.html +++ b/src/pretix/control/templates/pretixcontrol/event/display.html @@ -11,6 +11,9 @@ {% bootstrap_field form.logo_image layout="control" %} {% bootstrap_field form.frontpage_text layout="control" %} {% bootstrap_field form.show_variations_expanded layout="control" %} + {% if form.frontpage_subevent_ordering %} + {% bootstrap_field form.frontpage_subevent_ordering layout="control" %} + {% endif %}
{% trans "Shop design" %} diff --git a/src/pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html b/src/pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html index e090ce106f..172cf619e7 100644 --- a/src/pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html +++ b/src/pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html @@ -1,6 +1,6 @@ {% load i18n %} {% load eventurl %} -{% for subev in event.active_future_subevents %} +{% for subev in event.subevent_list_subevents %}
diff --git a/src/tests/presale/test_event.py b/src/tests/presale/test_event.py index fca586fc03..d3a9c2162e 100644 --- a/src/tests/presale/test_event.py +++ b/src/tests/presale/test_event.py @@ -153,7 +153,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest): resp = self.client.get('/%s/%s/%d/' % (self.orga.slug, self.event.slug, se1.pk + 1000)) assert resp.status_code == 404 - def test_subevent_list(self): + def test_subevent_list_activeness(self): self.event.has_subevents = True self.event.save() self.event.subevents.create(name='Foo SE1', date_from=now() + datetime.timedelta(days=1), active=True) @@ -162,6 +162,20 @@ class ItemDisplayTest(EventTestMixin, SoupTest): self.assertIn("Foo SE1", resp.rendered_content) self.assertNotIn("Foo SE2", resp.rendered_content) + def test_subevent_list_ordering(self): + self.event.has_subevents = True + self.event.save() + self.event.subevents.create(name='Epic SE', date_from=now() + datetime.timedelta(days=1), active=True) + self.event.subevents.create(name='Cool SE', date_from=now() + datetime.timedelta(days=2), active=True) + + self.event.settings.frontpage_subevent_ordering = 'date_ascending' + content = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content + self.assertLess(content.index('Epic SE'), content.index('Cool SE')) + + self.event.settings.frontpage_subevent_ordering = 'name_ascending' + content = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug)).rendered_content + self.assertLess(content.index('Cool SE'), content.index('Epic SE')) + def test_subevent_calendar(self): self.event.settings.event_list_type = 'calendar' self.event.has_subevents = True