forked from CGM_Public/pretix_original
Move timemachine controls into presale, implement session transfer for multidomain time machine support
This commit is contained in:
@@ -49,7 +49,7 @@ class TimeMachineMiddleware:
|
||||
def __call__(self, request):
|
||||
if hasattr(request, 'event') and hasattr(request, '_namespace') and request._namespace == 'presale' and \
|
||||
'timemachine_now_dt' in request.session and \
|
||||
request.event.testmode and \
|
||||
request.event.testmode and request.user.is_authenticated and \
|
||||
request.user.has_event_permission(request.organizer, request.event, 'can_change_event_settings', request):
|
||||
request.now_dt = parse(request.session['timemachine_now_dt'])
|
||||
request.now_dt_is_fake = True
|
||||
|
||||
@@ -106,7 +106,7 @@ def _default_context(request):
|
||||
else:
|
||||
ctx['complain_testmode_orders'] = False
|
||||
|
||||
if not request.event.live and ctx['has_domain']:
|
||||
if (request.event.testmode or not request.event.live) and ctx['has_domain']:
|
||||
child_sess = request.session.get('child_session_{}'.format(request.event.pk))
|
||||
s = SessionStore()
|
||||
if not child_sess or not s.exists(child_sess):
|
||||
|
||||
@@ -124,35 +124,6 @@
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% if request.event.testmode %}
|
||||
<div class="panel {% if request.session.timemachine_now_dt %}panel-success{% else %}panel-default{% endif %}">
|
||||
<div class="panel-heading">
|
||||
{% trans "Time machine" %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="" method="post" class="">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors timemachine_form %}
|
||||
|
||||
<p>{% trans "Test your shop as if it were a different date and time." %}</p>
|
||||
|
||||
{% bootstrap_field timemachine_form.now_dt layout="control" show_label=False field_class="col-md-6" %}
|
||||
<div class="text-right">
|
||||
<button type="submit" class="btn btn-default btn-lg btn-save">
|
||||
{% if request.session.timemachine_now_dt %}{% trans "Change" %}{% else %}{% trans "Enable time machine" %}{% endif %}
|
||||
</button>
|
||||
{% if request.session.timemachine_now_dt %}
|
||||
<button name="timemachine_disable" value="true" type="submit" class="btn btn-default btn-lg btn-save">
|
||||
{% trans "Disable" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="text-right">
|
||||
<a href="{% url "control:event.dangerzone" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-default btn-lg">
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{% load eventurl %}
|
||||
{% load static %}
|
||||
<form action="{% eventurl request.event "presale:event.auth" %}" method="post">
|
||||
<input type="hidden" value="{{ new_session }}" name="session">
|
||||
<button type="submit">
|
||||
Continue
|
||||
</button>
|
||||
</form>
|
||||
<script src="{% static "pretixcontrol/js/send_form.js" %}"></script>
|
||||
@@ -247,6 +247,7 @@ urlpatterns = [
|
||||
re_path(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
|
||||
re_path(r'^logs/embed$', dashboards.event_index_log_lazy, name='event.index.logs'),
|
||||
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),
|
||||
re_path(r'^transfer_session/$', event.EventTransferSession.as_view(), name='event.transfer_session'),
|
||||
re_path(r'^logs/$', event.EventLog.as_view(), name='event.log'),
|
||||
re_path(r'^delete/$', event.EventDelete.as_view(), name='event.delete'),
|
||||
re_path(r'^comment/$', event.EventComment.as_view(),
|
||||
|
||||
@@ -46,8 +46,6 @@ from zoneinfo import ZoneInfo
|
||||
import bleach
|
||||
import qrcode
|
||||
import qrcode.image.svg
|
||||
from dateutil import parser
|
||||
from django import forms
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
@@ -65,7 +63,7 @@ from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import url_has_allowed_host_and_scheme
|
||||
from django.utils.timezone import get_current_timezone, now
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext, gettext_lazy as _, gettext_noop
|
||||
from django.views.generic import FormView, ListView
|
||||
from django.views.generic.base import TemplateView, View
|
||||
@@ -94,12 +92,11 @@ from pretix.control.views.mailsetup import MailSettingsSetupView
|
||||
from pretix.control.views.user import RecentAuthenticationRequiredMixin
|
||||
from pretix.helpers.database import rolledback_transaction
|
||||
from pretix.multidomain.urlreverse import (
|
||||
build_absolute_uri, eventreverse, get_event_domain,
|
||||
build_absolute_uri, get_event_domain,
|
||||
)
|
||||
from pretix.plugins.stripe.payment import StripeSettingsHolder
|
||||
from pretix.presale.style import regenerate_css
|
||||
|
||||
from ...base.forms.widgets import SplitDateTimePickerWidget
|
||||
from ...base.i18n import language
|
||||
from ...base.models.items import (
|
||||
Item, ItemCategory, ItemMetaProperty, Question, Quota,
|
||||
@@ -955,43 +952,21 @@ class EventPermissions(EventSettingsViewMixin, EventPermissionRequiredMixin, Tem
|
||||
template_name = 'pretixcontrol/event/permissions.html'
|
||||
|
||||
|
||||
class TimemachineForm(forms.Form):
|
||||
now_dt = forms.SplitDateTimeField(
|
||||
label=_('Fake date time'),
|
||||
widget=SplitDateTimePickerWidget(),
|
||||
initial=lambda: now().astimezone(get_current_timezone())
|
||||
)
|
||||
|
||||
|
||||
class EventLive(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
template_name = 'pretixcontrol/event/live.html'
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.timemachine_form = TimemachineForm(
|
||||
data=request.method == 'POST' and request.POST or None,
|
||||
initial=(
|
||||
{'now_dt': parser.parse(request.session.get('timemachine_now_dt', None))}
|
||||
if request.session.get('timemachine_now_dt', None) else {}
|
||||
)
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['issues'] = self.request.event.live_issues
|
||||
ctx['actual_orders'] = self.request.event.orders.filter(testmode=False).exists()
|
||||
ctx['timemachine_form'] = self.timemachine_form
|
||||
return ctx
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if request.POST.get("timemachine_disable"):
|
||||
del request.session['timemachine_now_dt']
|
||||
messages.success(self.request, _('Time machine disabled!'))
|
||||
elif self.timemachine_form.is_valid():
|
||||
request.session['timemachine_now_dt'] = str(self.timemachine_form.cleaned_data['now_dt'])
|
||||
return redirect(eventreverse(request.event, "presale:event.index"))
|
||||
elif request.POST.get("live") == "true" and not self.request.event.live_issues:
|
||||
if request.POST.get("live") == "true" and not self.request.event.live_issues:
|
||||
with transaction.atomic():
|
||||
request.event.live = True
|
||||
request.event.save()
|
||||
@@ -1047,6 +1022,11 @@ class EventLive(EventPermissionRequiredMixin, TemplateView):
|
||||
})
|
||||
|
||||
|
||||
class EventTransferSession(EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
template_name = 'pretixcontrol/event/transfer_session.html'
|
||||
|
||||
|
||||
class EventDelete(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, FormView):
|
||||
permission = 'can_change_event_settings'
|
||||
template_name = 'pretixcontrol/event/delete.html'
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
<div class="container">
|
||||
<span class="fa fa-clock-o" aria-hidden="true"></span>
|
||||
{% trans "You are currently using the time machine. The ticket shop is rendered as if it were" %} {{ request.now_dt }}
|
||||
<a href="{{ site_url }}{% url "control:event.live" event=event.slug organizer=event.organizer.slug %}" class="btn-link">
|
||||
<a href="{% eventurl event "presale:event.timemachine" %}" class="btn-link">
|
||||
{% trans "Change" %}
|
||||
</a>
|
||||
<form action="{{ site_url }}{% url "control:event.live" event=event.slug organizer=event.organizer.slug %}" method="post" class="download-btn-form">
|
||||
<form action="{% eventurl event "presale:event.timemachine" %}" method="post" class="download-btn-form">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn-link" value="true" name="timemachine_disable">{% trans "Go back to current time" %}</button>
|
||||
</form>
|
||||
@@ -126,6 +126,15 @@
|
||||
{% if request.event.testmode %}
|
||||
{% if request.sales_channel.testmode_supported %}
|
||||
<div class="alert alert-warning">
|
||||
{% if request.user.is_authenticated %}
|
||||
<a href="{% eventurl event "presale:event.timemachine" %}" class="btn btn-default pull-right" title="{% trans "Enable time machine" %}">
|
||||
<span class="fa fa-clock-o" aria-hidden="true"></span>
|
||||
</a>
|
||||
{% elif request.event_domain or request.organizer_domain %}
|
||||
<a href="{% url "control:event.transfer_session" event=event.slug organizer=event.organizer.slug %}" class="btn btn-default pull-right" title="{% trans "Enable time machine" %}">
|
||||
<span class="fa fa-clock-o" aria-hidden="true"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<p><strong><span class="sr-only">{% trans "Warning" context "alert-messages" %}:</span>
|
||||
{% trans "This ticket shop is currently in test mode. Please do not perform any real purchases as your order might be deleted without notice." %}
|
||||
</strong></p>
|
||||
@@ -137,6 +146,8 @@
|
||||
</strong></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{% extends "pretixpresale/event/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load l10n %}
|
||||
{% load money %}
|
||||
{% load eventurl %}
|
||||
{% load eventsignal %}
|
||||
{% load thumb %}
|
||||
{% load rich_text %}
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Time machine" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="panel {% if request.session.timemachine_now_dt %}panel-success{% else %}panel-default{% endif %}">
|
||||
<div class="panel-heading">
|
||||
{% trans "Time machine" %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="" method="post" class="">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form_errors timemachine_form %}
|
||||
|
||||
<p>{% trans "Test your shop as if it were a different date and time." %}</p>
|
||||
|
||||
{% bootstrap_field timemachine_form.now_dt layout="control" show_label=False field_class="col-md-6" %}
|
||||
<div class="text-right">
|
||||
<button type="submit" class="btn btn-default btn-lg btn-save">
|
||||
{% if request.session.timemachine_now_dt %}{% trans "Change" %}{% else %}{% trans "Enable time machine" %}{% endif %}
|
||||
</button>
|
||||
{% if request.session.timemachine_now_dt %}
|
||||
<button name="timemachine_disable" value="true" type="submit" class="btn btn-default btn-lg btn-save">
|
||||
{% trans "Disable" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -173,6 +173,8 @@ event_patterns = [
|
||||
re_path(r'^(?P<subevent>\d+)/widget/product_list$', pretix.presale.views.widget.WidgetAPIProductList.as_view(),
|
||||
name='event.widget.productlist'),
|
||||
|
||||
re_path(r'timemachine/$', pretix.presale.views.event.EventTimeMachine.as_view(), name='event.timemachine'),
|
||||
|
||||
# Account management is done on org level, but we at least need a logout
|
||||
re_path(r'^account/logout$', pretix.presale.views.customer.LogoutView.as_view(), name='organizer.customer.logout'),
|
||||
]
|
||||
|
||||
@@ -38,6 +38,9 @@ from importlib import import_module
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import (
|
||||
BACKEND_SESSION_KEY, SESSION_KEY, get_user_model, load_backend,
|
||||
)
|
||||
from django.db.models import Q
|
||||
from django.http import Http404, HttpResponseForbidden
|
||||
from django.middleware.csrf import rotate_token
|
||||
@@ -218,6 +221,15 @@ def customer_logout(request):
|
||||
request._cached_customer = None
|
||||
|
||||
|
||||
def _apply_user_from_session_data(request, sessiondata):
|
||||
user_id = get_user_model()._meta.pk.to_python(sessiondata[SESSION_KEY])
|
||||
backend_path = sessiondata[BACKEND_SESSION_KEY]
|
||||
if backend_path in settings.AUTHENTICATION_BACKENDS:
|
||||
backend = load_backend(backend_path)
|
||||
user = backend.get_user(user_id)
|
||||
request.user = user
|
||||
|
||||
|
||||
@scope(organizer=None)
|
||||
def _detect_event(request, require_live=True, require_plugin=None):
|
||||
|
||||
@@ -303,7 +315,7 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
||||
# Restrict locales to the ones available for this event
|
||||
LocaleMiddleware(NotImplementedError).process_request(request)
|
||||
|
||||
if require_live and not request.event.live:
|
||||
if require_live and (request.event.testmode or not request.event.live):
|
||||
can_access = (
|
||||
url.url_name == 'event.auth'
|
||||
or (
|
||||
@@ -320,8 +332,10 @@ def _detect_event(request, require_live=True, require_plugin=None):
|
||||
pass
|
||||
else:
|
||||
can_access = 'event_access' in parentdata
|
||||
if can_access:
|
||||
_apply_user_from_session_data(request, parentdata)
|
||||
|
||||
if not can_access:
|
||||
if not can_access and not request.event.live:
|
||||
# Directly construct view instead of just calling `raise` since this case is so common that we
|
||||
# don't want it to show in our log files.
|
||||
template = loader.get_template("pretixpresale/event/offline.html")
|
||||
|
||||
@@ -42,18 +42,21 @@ 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
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models import (
|
||||
Count, Exists, IntegerField, OuterRef, Prefetch, Q, Value,
|
||||
)
|
||||
from django.db.models.lookups import Exact
|
||||
from django.http import Http404, HttpResponse
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.formats import get_format
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from django.utils.timezone import now
|
||||
from django.utils.timezone import get_current_timezone, now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
@@ -78,6 +81,8 @@ from pretix.presale.views.organizer import (
|
||||
filter_qs_by_attr, has_before_after, weeks_for_template,
|
||||
)
|
||||
|
||||
from ...base.forms.widgets import SplitDateTimePickerWidget
|
||||
from ...control.permissions import EventPermissionRequiredMixin
|
||||
from ...helpers.formats.en.formats import SHORT_MONTH_DAY_FORMAT, WEEK_FORMAT
|
||||
from ...helpers.http import redirect_to_url
|
||||
from . import (
|
||||
@@ -918,3 +923,43 @@ class EventAuth(View):
|
||||
|
||||
request.session['pretix_event_access_{}'.format(request.event.pk)] = parent
|
||||
return redirect_to_url(eventreverse(request.event, 'presale:event.index'))
|
||||
|
||||
|
||||
class TimemachineForm(forms.Form):
|
||||
now_dt = forms.SplitDateTimeField(
|
||||
label=_('Fake date time'),
|
||||
widget=SplitDateTimePickerWidget(),
|
||||
initial=lambda: now().astimezone(get_current_timezone())
|
||||
)
|
||||
|
||||
|
||||
class EventTimeMachine(EventViewMixin, EventPermissionRequiredMixin, TemplateView):
|
||||
permission = 'can_change_event_settings'
|
||||
template_name = 'pretixpresale/event/timemachine.html'
|
||||
|
||||
def setup(self, request, *args, **kwargs):
|
||||
super().setup(request, *args, **kwargs)
|
||||
self.timemachine_form = TimemachineForm(
|
||||
data=request.method == 'POST' and request.POST or None,
|
||||
initial=(
|
||||
{'now_dt': parser.parse(request.session.get('timemachine_now_dt', None))}
|
||||
if request.session.get('timemachine_now_dt', None) else {}
|
||||
)
|
||||
)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['timemachine_form'] = self.timemachine_form
|
||||
return ctx
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if request.POST.get("timemachine_disable"):
|
||||
del request.session['timemachine_now_dt']
|
||||
messages.success(self.request, _('Time machine disabled!'))
|
||||
return redirect(self.get_success_url())
|
||||
elif self.timemachine_form.is_valid():
|
||||
request.session['timemachine_now_dt'] = str(self.timemachine_form.cleaned_data['now_dt'])
|
||||
return redirect(eventreverse(request.event, "presale:event.index"))
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return eventreverse(self.request.event, 'presale:event.timemachine')
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
document.forms[0].submit();
|
||||
Reference in New Issue
Block a user