From 212967b4126595c7f182f8bc5ced8e38bcd3a9d8 Mon Sep 17 00:00:00 2001 From: Kara Engelhardt Date: Fri, 25 Sep 2026 14:26:29 +0200 Subject: [PATCH] Fix crash on too old time machine date (Z#23245824) dateutil.parser seems to reject dates with second-precision timezone-offsets, which datetime produces for some dates aroung the year 200. datetime.fromisoformat has no problem parsing them --- src/pretix/base/timemachine.py | 17 ++++++++++++++--- src/pretix/presale/views/event.py | 16 ++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/pretix/base/timemachine.py b/src/pretix/base/timemachine.py index c8ba4c2c21..b25804504a 100644 --- a/src/pretix/base/timemachine.py +++ b/src/pretix/base/timemachine.py @@ -21,9 +21,11 @@ # import contextvars from contextlib import contextmanager +from datetime import datetime -from dateutil.parser import parse +from django.contrib import messages from django.utils.timezone import now +from django.utils.translation import gettext_lazy as _ from pretix.base.auth import has_event_access_permission @@ -34,8 +36,17 @@ timemachine_now_var = contextvars.ContextVar('timemachine_now', default=None) def time_machine_now_assigned_from_request(request): if hasattr(request, 'event') and f'timemachine_now_dt:{request.event.pk}' in request.session and \ request.event.testmode and has_event_access_permission(request): - request.now_dt = parse(request.session[f'timemachine_now_dt:{request.event.pk}']) - request.now_dt_is_fake = True + try: + request.now_dt = datetime.fromisoformat(request.session[f'timemachine_now_dt:{request.event.pk}']) + request.now_dt_is_fake = True + except ValueError: + del request.session[f'timemachine_now_dt:{request.event.pk}'] + messages.error( + request, _('Invalid date.') + ) + request.now_dt = now() + request.now_dt_is_fake = False + else: request.now_dt = now() request.now_dt_is_fake = False diff --git a/src/pretix/presale/views/event.py b/src/pretix/presale/views/event.py index fe54f21eb8..17faa5b8e6 100644 --- a/src/pretix/presale/views/event.py +++ b/src/pretix/presale/views/event.py @@ -41,7 +41,6 @@ from importlib import import_module from urllib.parse import urlencode import isoweek -from dateutil import parser from django import forms from django.conf import settings from django.contrib import messages @@ -603,12 +602,17 @@ class EventTimeMachine(EventViewMixin, TemplateView): raise PermissionDenied(_('You are not allowed to access time machine mode.')) if not request.event.testmode: raise PermissionDenied(_('This feature is only available in test mode.')) + + initial = {} + if request.session.get(f'timemachine_now_dt:{request.event.pk}', None): + try: + initial['now_dt'] = datetime.fromisoformat(request.session.get(f'timemachine_now_dt:{request.event.pk}', None)) + except ValueError: + pass + self.timemachine_form = TimemachineForm( data=request.method == 'POST' and request.POST or None, - initial=( - {'now_dt': parser.parse(request.session.get(f'timemachine_now_dt:{request.event.pk}', None))} - if request.session.get(f'timemachine_now_dt:{request.event.pk}', None) else {} - ) + initial=initial ) def get_context_data(self, **kwargs): @@ -622,7 +626,7 @@ class EventTimeMachine(EventViewMixin, TemplateView): messages.success(self.request, _('Time machine disabled!')) return redirect(self.get_success_url()) elif self.timemachine_form.is_valid(): - request.session[f'timemachine_now_dt:{request.event.pk}'] = str(self.timemachine_form.cleaned_data['now_dt']) + request.session[f'timemachine_now_dt:{request.event.pk}'] = self.timemachine_form.cleaned_data['now_dt'].isoformat() return redirect(eventreverse(request.event, "presale:event.index")) else: return self.get(request)