diff --git a/src/pretix/control/signals.py b/src/pretix/control/signals.py index f3b68cc85..57f87109a 100644 --- a/src/pretix/control/signals.py +++ b/src/pretix/control/signals.py @@ -141,7 +141,7 @@ event_dashboard_widgets = EventPluginSignal() This signal is sent out to include widgets in the event dashboard. Receivers should return a list of dictionaries, where each dictionary can have the keys: -* content (str, containing HTML) +* content (SafeString, containing HTML) * display_size (str, one of "full" (whole row), "big" (half a row) or "small" (quarter of a row). May be ignored on small displays, default is "small") * priority (int, used for ordering, higher comes first, default is 1) @@ -158,7 +158,7 @@ Arguments: 'user' This signal is sent out to include widgets in the personal user dashboard. Receivers should return a list of dictionaries, where each dictionary can have the keys: -* content (str, containing HTML) +* content (SafeString, containing HTML) * display_size (str, one of "full" (whole row), "big" (half a row) or "small" (quarter of a row). May be ignored on small displays, default is "small") * priority (int, used for ordering, higher comes first, default is 1) diff --git a/src/pretix/control/templates/pretixcontrol/dashboard.html b/src/pretix/control/templates/pretixcontrol/dashboard.html index 7dace3937..cfc2a9046 100644 --- a/src/pretix/control/templates/pretixcontrol/dashboard.html +++ b/src/pretix/control/templates/pretixcontrol/dashboard.html @@ -28,7 +28,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} @@ -51,7 +51,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} @@ -72,7 +72,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} @@ -94,7 +94,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} {% else %} @@ -102,7 +102,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} {% endif %} diff --git a/src/pretix/control/templates/pretixcontrol/event/index.html b/src/pretix/control/templates/pretixcontrol/event/index.html index f1fd140be..a8d04040d 100644 --- a/src/pretix/control/templates/pretixcontrol/event/index.html +++ b/src/pretix/control/templates/pretixcontrol/event/index.html @@ -106,7 +106,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} {% elif w.link %} @@ -114,7 +114,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} {% else %} @@ -122,7 +122,7 @@ {% if w.lazy %} {% else %} - {{ w.content|safe }} + {{ w.content }} {% endif %} {% endif %} diff --git a/src/pretix/control/views/dashboards.py b/src/pretix/control/views/dashboards.py index 02bddc996..0d8d6e6a6 100644 --- a/src/pretix/control/views/dashboards.py +++ b/src/pretix/control/views/dashboards.py @@ -49,7 +49,7 @@ from django.shortcuts import render from django.template.loader import get_template from django.urls import reverse from django.utils.formats import date_format -from django.utils.html import escape +from django.utils.html import conditional_escape, escape, format_html from django.utils.timezone import now from django.utils.translation import gettext_lazy as _, ngettext, pgettext @@ -112,7 +112,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs): return [ { - 'content': None if lazy else NUM_WIDGET.format(num=intcomma(tickc), text=_('Attendees (ordered)')), + 'content': None if lazy else format_html(NUM_WIDGET, num=intcomma(tickc), text=_('Attendees (ordered)')), 'lazy': 'attendees-ordered', 'display_size': 'small', 'priority': 100, @@ -122,7 +122,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs): }) + ('?subevent={}'.format(subevent.pk) if subevent else '') }, { - 'content': None if lazy else NUM_WIDGET.format(num=intcomma(paidc), text=_('Attendees (paid)')), + 'content': None if lazy else format_html(NUM_WIDGET, num=intcomma(paidc), text=_('Attendees (paid)')), 'lazy': 'attendees-paid', 'display_size': 'small', 'priority': 100, @@ -132,7 +132,8 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs): }) + ('?subevent={}'.format(subevent.pk) if subevent else '') }, { - 'content': None if lazy else NUM_WIDGET.format( + 'content': None if lazy else format_html( + NUM_WIDGET, num=money_filter(round_decimal(rev, sender.currency), sender.currency, hide_currency=True), text=_('Total revenue ({currency})').format(currency=sender.currency) ), @@ -145,7 +146,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs): }) + ('?subevent={}'.format(subevent.pk) if subevent else '') }, { - 'content': None if lazy else NUM_WIDGET.format(num=prodc, text=_('Active products')), + 'content': None if lazy else format_html(NUM_WIDGET, num=prodc, text=_('Active products')), 'lazy': 'active-products', 'display_size': 'small', 'priority': 100, @@ -209,8 +210,8 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs): quota_cache[q.pk] = (quota_cache[q.pk][0], quota_cache[q.pk][1] - min(wlt['cnt'], row[1])) widgets.append({ - 'content': None if lazy else NUM_WIDGET.format( - num=intcomma(happy), text=_('available to give to people on waiting list') + 'content': None if lazy else format_html( + NUM_WIDGET, num=intcomma(happy), text=_('available to give to people on waiting list') ), 'lazy': 'waitinglist-avail', 'priority': 50, @@ -220,7 +221,9 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs): }) }) widgets.append({ - 'content': None if lazy else NUM_WIDGET.format(num=intcomma(wles.count()), text=_('total waiting list length')), + 'content': None if lazy else format_html( + NUM_WIDGET, num=intcomma(wles.count()), text=_('total waiting list length') + ), 'lazy': 'waitinglist-length', 'display_size': 'small', 'priority': 50, @@ -247,7 +250,8 @@ def quota_widgets(sender, subevent=None, lazy=False, **kwargs): if not lazy: status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True) widgets.append({ - 'content': None if lazy else NUM_WIDGET.format( + 'content': None if lazy else format_html( + NUM_WIDGET, num='{}/{}'.format(intcomma(left), intcomma(q.size)) if q.size is not None else '\u221e', text=_('{quota} left').format(quota=escape(q.name)) ), @@ -268,7 +272,8 @@ def shop_state_widget(sender, **kwargs): return [{ 'display_size': 'small', 'priority': 1000, - 'content': '
{t1}
{state}{t2}
'.format( + 'content': format_html( + '
{t1}
{state}{t2}
', t1=_('Your ticket shop is'), t2=_('Click here to change'), state=_('live') if sender.live and not sender.testmode else ( _('live and in test mode') if sender.live else ( @@ -299,7 +304,8 @@ def checkin_widget(sender, subevent=None, lazy=False, **kwargs): qs = sender.checkin_lists.filter(subevent=subevent) for cl in qs: widgets.append({ - 'content': None if lazy else NUM_WIDGET.format( + 'content': None if lazy else format_html( + NUM_WIDGET, num='{}/{}'.format(intcomma(cl.inside_count), intcomma(cl.position_count)), text=_('Present – {list}').format(list=escape(cl.name)) ), @@ -340,6 +346,12 @@ def welcome_wizard_widget(sender, **kwargs): }] +def build_json_response(widgets): + for widget in widgets: + widget['content'] = conditional_escape(widget['content']) + return JsonResponse({'widgets': widgets}) + + def event_index(request, organizer, event): from pretix.control.forms.event import CommentForm @@ -418,7 +430,7 @@ def event_index_widgets_lazy(request, organizer, event): for r, result in event_dashboard_widgets.send(sender=request.event, subevent=subevent, lazy=False): widgets.extend(result) - return JsonResponse({'widgets': widgets}) + return build_json_response(widgets) def event_index_log_lazy(request, organizer, event): @@ -505,7 +517,7 @@ def widgets_for_event_qs(request, qs, user, nmax, lazy=False):
{event}
{daterange}
-
{times}
+
{times}{timezone}
{orders} @@ -549,14 +561,16 @@ def widgets_for_event_qs(request, qs, user, nmax, lazy=False): status = ('success', _('On sale')) widgets.append({ - 'content': tpl.format( + 'content': format_html( + tpl, event=escape(event.name), times=_('Event series') if event.has_subevents else ( ((date_format(event.date_admission.astimezone(tz), 'TIME_FORMAT') + ' / ') if event.date_admission and event.date_admission != event.date_from else '') + (date_format(event.date_from.astimezone(tz), 'TIME_FORMAT') if event.date_from else '') - ) + ( - ' '.format(tzname) + ), + timezone=( + format_html(' ', tzname) if tzname != request.timezone and not event.has_subevents else '' ), url=reverse('control:event.index', kwargs={ @@ -564,7 +578,8 @@ def widgets_for_event_qs(request, qs, user, nmax, lazy=False): 'organizer': event.organizer.slug }), orders=( - '{orders_text}'.format( + format_html( + '{orders_text}', orders_url=reverse('control:event.orders', kwargs={ 'event': event.slug, 'organizer': event.organizer.slug @@ -631,7 +646,7 @@ def user_index_widgets_lazy(request): request.user, 8 ) - return JsonResponse({'widgets': widgets}) + return build_json_response(widgets) def user_index(request):