From 15d3fbc02ed53448dc600357b0770210ef7d119f Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Fri, 26 Jan 2024 19:22:45 +0100 Subject: [PATCH] Fix auto-selected date in calendar with long-running events (Z#23141457) (#3829) * Fix auto-selected date in calendar with long-running events (Z#23141457) * Review fixes * Update src/pretix/presale/views/organizer.py Co-authored-by: Richard Schreiber --------- Co-authored-by: Richard Schreiber --- src/pretix/presale/views/organizer.py | 113 ++++++++++++++++++-------- 1 file changed, 80 insertions(+), 33 deletions(-) diff --git a/src/pretix/presale/views/organizer.py b/src/pretix/presale/views/organizer.py index 17894f10d..5bd941c62 100644 --- a/src/pretix/presale/views/organizer.py +++ b/src/pretix/presale/views/organizer.py @@ -45,7 +45,9 @@ import dateutil import isoweek from django.conf import settings from django.core.cache import caches -from django.db.models import Exists, Max, Min, OuterRef, Prefetch, Q +from django.db.models import ( + Case, Exists, F, Max, Min, OuterRef, Prefetch, Q, Value, When, +) from django.db.models.functions import Coalesce, Greatest from django.http import Http404, HttpResponse, QueryDict from django.templatetags.static import static @@ -216,14 +218,20 @@ class EventListMixin: def _set_month_to_next_subevent(self): tz = self.request.event.timezone - next_sev = self.request.event.subevents.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + now_dt = now() + next_sev = self.request.event.subevents.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, active=True, is_public=True, - ).select_related('event').order_by('date_from').first() + ).select_related('event').order_by('effective_date').first() if next_sev: - datetime_from = next_sev.date_from + datetime_from = next_sev.effective_date self.year = datetime_from.astimezone(tz).year self.month = datetime_from.astimezone(tz).month else: @@ -231,28 +239,39 @@ class EventListMixin: self.month = now().month def _set_month_to_next_event(self): - next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + now_dt = now() + next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now())), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, organizer=self.request.organizer, live=True, is_public=True, has_subevents=False - ), self.request).order_by('date_from').first() - next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + ), self.request).order_by('effective_date').first() + next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, event__organizer=self.request.organizer, event__is_public=True, event__live=True, active=True, is_public=True, - ), self.request).select_related('event').order_by('date_from').first() + ), self.request).select_related('event').order_by('effective_date').first() datetime_from = None - if (next_ev and next_sev and next_sev.date_from < next_ev.date_from) or (next_sev and not next_ev): - datetime_from = next_sev.date_from + if (next_ev and next_sev and next_sev.effective_date < next_ev.effective_date) or (next_sev and not next_ev): + datetime_from = next_sev.effective_date next_ev = next_sev.event elif next_ev: - datetime_from = next_ev.date_from + datetime_from = next_ev.effective_date if datetime_from: tz = next_ev.timezone @@ -277,15 +296,21 @@ class EventListMixin: self._set_month_to_next_event() def _set_week_to_next_subevent(self): + now_dt = now() tz = self.request.event.timezone - next_sev = self.request.event.subevents.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + next_sev = self.request.event.subevents.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, active=True, is_public=True, - ).select_related('event').order_by('date_from').first() + ).select_related('event').order_by('effective_date').first() if next_sev: - datetime_from = next_sev.date_from + datetime_from = next_sev.effective_date self.year = datetime_from.astimezone(tz).isocalendar()[0] self.week = datetime_from.astimezone(tz).isocalendar()[1] else: @@ -293,28 +318,39 @@ class EventListMixin: self.week = now().isocalendar()[1] def _set_week_to_next_event(self): - next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + now_dt = now() + next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, organizer=self.request.organizer, live=True, is_public=True, has_subevents=False - ), self.request).order_by('date_from').first() - next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + ), self.request).order_by('effective_date').first() + next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, event__organizer=self.request.organizer, event__is_public=True, event__live=True, active=True, is_public=True, - ), self.request).select_related('event').order_by('date_from').first() + ), self.request).select_related('event').order_by('effective_date').first() datetime_from = None - if (next_ev and next_sev and next_sev.date_from < next_ev.date_from) or (next_sev and not next_ev): - datetime_from = next_sev.date_from + if (next_ev and next_sev and next_sev.effective_date < next_ev.effective_date) or (next_sev and not next_ev): + datetime_from = next_sev.effective_date next_ev = next_sev.event elif next_ev: - datetime_from = next_ev.date_from + datetime_from = next_ev.effective_date if datetime_from: tz = next_ev.timezone @@ -825,21 +861,32 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView): template_name = 'pretixpresale/organizers/calendar_day.html' def _set_date_to_next_event(self): - next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + now_dt = now() + next_ev = filter_qs_by_attr(Event.objects.using(settings.DATABASE_REPLICA).anootate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, organizer=self.request.organizer, live=True, is_public=True, date_from__gte=now(), - ), self.request).order_by('date_from').first() - next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).filter( - Q(date_from__gte=now()) | Q(date_to__isnull=False, date_to__gte=now()), + ), self.request).order_by('effective_date').first() + next_sev = filter_qs_by_attr(SubEvent.objects.using(settings.DATABASE_REPLICA).annotate( + effective_date=Case( + When(date_from__lt=now_dt, date_to__isnull=False, date_to__gte=now_dt, then=Value(now_dt)), + default=F('date_from'), + ) + ).filter( + effective_date__gte=now_dt, event__organizer=self.request.organizer, event__is_public=True, event__live=True, active=True, is_public=True, - ), self.request).select_related('event').order_by('date_from').first() + ), self.request).select_related('event').order_by('effective_date').first() datetime_from = None if (next_ev and next_sev and next_sev.date_from < next_ev.date_from) or (next_sev and not next_ev):