From e4abfb0bdffa909d72dbee71a53bb57b42ee3efd Mon Sep 17 00:00:00 2001 From: Mira Weller Date: Wed, 6 Mar 2024 13:13:40 +0100 Subject: [PATCH] start implementing time machine mode --- src/pretix/base/models/event.py | 35 +++++++++++------- src/pretix/presale/checkoutflow.py | 1 + src/pretix/presale/forms/waitinglist.py | 1 + src/pretix/presale/middleware.py | 27 ++++++++++++++ .../templates/pretixpresale/event/base.html | 11 ++++++ src/pretix/presale/views/cart.py | 1 + src/pretix/presale/views/checkout.py | 2 +- src/pretix/presale/views/event.py | 36 +++++++++++-------- src/pretix/presale/views/order.py | 3 +- src/pretix/presale/views/organizer.py | 7 ++-- src/pretix/presale/views/widget.py | 5 +-- src/pretix/settings.py | 1 + 12 files changed, 96 insertions(+), 34 deletions(-) diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py index 4914d59be3..f9aabe3fc2 100644 --- a/src/pretix/base/models/event.py +++ b/src/pretix/base/models/event.py @@ -80,6 +80,15 @@ from .organizer import Organizer, Team logger = logging.getLogger(__name__) +def annotate_with_time_based_properties(events_or_subevents, now_dt): + print("annotate_with_time_based_properties", now_dt) + for e_s in events_or_subevents: + if e_s: + e_s.presale_is_running = e_s.presale_is_running_by_time(now_dt) + e_s.presale_has_ended = e_s.presale_has_ended_by_time(now_dt) + return events_or_subevents + + class EventMixin: def clean(self): if self.presale_start and self.presale_end and self.presale_start > self.presale_end: @@ -229,17 +238,17 @@ class EventMixin: else: return self.presale_end - @property - def presale_has_ended(self): + def presale_has_ended_by_time(self, now_dt: datetime=None): """ Is true, when ``presale_end`` is set and in the past. """ + now_dt = now_dt or now() if self.effective_presale_end: - return now() > self.effective_presale_end + return now_dt > self.effective_presale_end elif self.date_to: - return now() > self.date_to + return now_dt > self.date_to else: - return now().astimezone(self.timezone).date() > self.date_from.astimezone(self.timezone).date() + return now_dt.astimezone(self.timezone).date() > self.date_from.astimezone(self.timezone).date() @property def effective_presale_start(self): @@ -253,15 +262,15 @@ class EventMixin: else: return self.presale_start - @property - def presale_is_running(self): + def presale_is_running_by_time(self, now_dt: datetime=None): """ Is true, when ``presale_end`` is not set or in the future and ``presale_start`` is not set or in the past. """ - if self.effective_presale_start and now() < self.effective_presale_start: + now_dt = now_dt or now() + if self.effective_presale_start and now_dt < self.effective_presale_start: return False - return not self.presale_has_ended + return not self.presale_has_ended_by_time(now_dt) @property def event_microdata(self): @@ -683,12 +692,12 @@ class Event(EventMixin, LoggedModel): return qs_annotated - @property - def presale_has_ended(self): + def presale_has_ended_by_time(self, now_dt: datetime = None): + now_dt = now_dt or now() if self.has_subevents: - return self.presale_end and now() > self.presale_end + return self.presale_end and now_dt > self.presale_end else: - return super().presale_has_ended + return super().presale_has_ended_by_time(now_dt) def delete_all_orders(self, really=False): from .checkin import Checkin diff --git a/src/pretix/presale/checkoutflow.py b/src/pretix/presale/checkoutflow.py index 748d0457f5..b9b17ec432 100644 --- a/src/pretix/presale/checkoutflow.py +++ b/src/pretix/presale/checkoutflow.py @@ -545,6 +545,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep): ) if getattr(self.request, 'customer', None) else None ), + now_dt=self.request.now_dt, ) item_cache[ckey] = items else: diff --git a/src/pretix/presale/forms/waitinglist.py b/src/pretix/presale/forms/waitinglist.py index 1343c1fbcb..b6b3c7c489 100644 --- a/src/pretix/presale/forms/waitinglist.py +++ b/src/pretix/presale/forms/waitinglist.py @@ -59,6 +59,7 @@ class WaitingListForm(forms.ModelForm): ) if customer else None ), + now_dt=request.now_dt, ) for i in items: if not i.allow_waitinglist: diff --git a/src/pretix/presale/middleware.py b/src/pretix/presale/middleware.py index 4cbf52a839..bced4f128f 100644 --- a/src/pretix/presale/middleware.py +++ b/src/pretix/presale/middleware.py @@ -32,8 +32,11 @@ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under the License. +from dateutil.parser import parse + from django.template.response import TemplateResponse from django.urls import resolve +from django.utils.timezone import now from django_scopes import scope from pretix.base.channels import WebshopSalesChannel @@ -79,3 +82,27 @@ class EventMiddleware: response = response.render() return response + + +class TimeMachineMiddleware: + def __init__(self, get_response=None): + self.get_response = get_response + super().__init__() + + def __call__(self, request): + if hasattr(request, 'event') and hasattr(request, '_namespace') and request._namespace == 'presale' and \ + 'time_machine' in request.COOKIES and \ + request.user.has_event_permission(request.organizer, request.event, 'can_change_event_settings', request): + print("setting now_dt from cookie") + request.now_dt = parse(request.COOKIES['time_machine']) + request.now_dt_is_fake = True + else: + print("setting now_dt to now", + "hasevent?",hasattr(request, 'event') , + "namespace?",hasattr(request, '_namespace') and request._namespace, + "cookies?",request.COOKIES) + request.now_dt = now() + + return self.get_response(request) + + diff --git a/src/pretix/presale/templates/pretixpresale/event/base.html b/src/pretix/presale/templates/pretixpresale/event/base.html index a3c2e48a81..f65b811ce4 100644 --- a/src/pretix/presale/templates/pretixpresale/event/base.html +++ b/src/pretix/presale/templates/pretixpresale/event/base.html @@ -33,6 +33,17 @@ {% endif %} + {% if request.now_dt_is_fake %} +
+
+ + {% trans "You are currently using the time machine. The ticket shop is rendered as if it were" %} {{ request.now_dt }} + + {% trans "Go back to current time" %} + +
+
+ {% endif %}