diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst
index fcad5e0c14..9a1a43b3f6 100644
--- a/doc/development/api/general.rst
+++ b/doc/development/api/general.rst
@@ -10,65 +10,56 @@ specific type of plugin but might come in handy for various plugins.
HTML head injection
-------------------
-These two signals allow you to put code inside the HTML ``
`` tag
-of every page. One signal is for the front end, one for the back end. You
-will get the request as a keyword argument ``request`` and can return plain
-HTML. The ``request`` object will have an attribute ``event``.
+.. automodule:: pretix.control.signals
+ :members: html_head
-* ``pretix.presale.signals.html_head``
-* ``pretix.control.signals.html_head``
+.. automodule:: pretix.presale.signals
+ :members: html_head
Admin navigation
----------------
-The following signals allow you to add additional views to the admin panel
-navigation. You will get the request as a keyword argument ``return``.
-Receivers are expected to return a list of dictionaries. The dictionaries
-should contain at least the keys ``label`` and ``url``. You can also return
-a fontawesome icon name with the key ``icon``, it will be respected depending
-on the type of navigation. You should also return an ``active`` key with a boolean
-set to ``True``, when this item should be marked as active. The ``request`` object
-will have an attribute ``event``.
-If you use this, you should read the documentation on :ref:`how to deal with URLs `
-in pretix.
-
-``pretix.control.signals.nav_event``
- The sidebar navigation when the admin has selected an event.
+.. automodule:: pretix.control.signals
+ :members: nav_event
Footer links
------------
-The signal ``pretix.presale.signals.footer_links`` allows you to add links to the footer of an event page. You
-are expected to return a dictionary containing the keys ``label`` and ``url``.
+
+.. automodule:: pretix.presale.signals
+ :members: footer_link
Order events
------------
There are multiple signals that will be sent out in the ordering cycle:
-``pretix.base.signals.order_placed``
- Sent out every time an order has been created. Provides the ``order`` as the only
- keyword argument.
-``pretix.base.signals.order_paid``
- Sent out every time an order has been paid. Provides the ``order`` as the only
- keyword argument.
+.. automodule:: pretix.base.signals
+ :members: order_paid, order_placed
+
+Voucher system
+--------------
+
+.. automodule:: pretix.presale.signals
+ :members: voucher_redeem_info
+
+
+Dashboards
+----------
+
+.. automodule:: pretix.control.signals
+ :members: event_dashboard_widgets, user_dashboard_widgets
Displaying of log entries
-------------------------
-To display an instance of the ``LogEntry`` model to a human user,
-``pretix.base.signals.logentry_display`` will be sent out with a ``logentry`` argument.
-
-The first received response that is not ``None`` will be used to display the log entry
-to the user.
+.. automodule:: pretix.base.signals
+ :members: logentry_display
Periodic tasks
--------------
-The ``pretix.base.signals.periodic_task`` is a regular django signal (no pretix event
-signal) that we send out every time the periodic task cronjob runs. This interval
-is not sharply defined, it can be everything between a minute and a day. The actions
-you perform should be idempotent, i.e. it should not make a difference if this is send
-out more often than expected.
+.. automodule:: pretix.base.signals
+ :members: periodic_task
diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py
index 46b8ed03e8..31dcf20ef2 100644
--- a/src/pretix/base/signals.py
+++ b/src/pretix/base/signals.py
@@ -47,55 +47,70 @@ class EventPluginSignal(django.dispatch.Signal):
responses.append((receiver, response))
return responses
-"""
-This signal is sent out to get all known payment providers. Receivers should return a
-subclass of pretix.base.payment.BasePaymentProvider
-"""
register_payment_providers = EventPluginSignal(
providing_args=[]
)
+"""
+This signal is sent out to get all known payment providers. Receivers should return a
+subclass of pretix.base.payment.BasePaymentProvider
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to get all known ticket outputs. Receivers should return a
-subclass of pretix.base.ticketoutput.BaseTicketOutput
-"""
+
register_ticket_outputs = EventPluginSignal(
providing_args=[]
)
+"""
+This signal is sent out to get all known ticket outputs. Receivers should return a
+subclass of pretix.base.ticketoutput.BaseTicketOutput
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to get all known data exporters. Receivers should return a
-subclass of pretix.base.exporter.BaseExporter
-"""
+
register_data_exporters = EventPluginSignal(
providing_args=[]
)
+"""
+This signal is sent out to get all known data exporters. Receivers should return a
+subclass of pretix.base.exporter.BaseExporter
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out every time an order is placed. The order object is given
-as the first argument.
-"""
+
order_placed = EventPluginSignal(
providing_args=["order"]
)
-
"""
-This signal is sent out every time an order is paid. The order object is given
+This signal is sent out every time an order is placed. The order object is given
as the first argument.
+
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
+
order_paid = EventPluginSignal(
providing_args=["order"]
)
+"""
+This signal is sent out every time an order is paid. The order object is given
+as the first argument.
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out every time we need to display a LogEntry object and we
-don't know how to turn it into human-readable text.
-"""
+
logentry_display = EventPluginSignal(
providing_args=["logentry"]
)
+"""
+To display an instance of the ``LogEntry`` model to a human user,
+``pretix.base.signals.logentry_display`` will be sent out with a ``logentry`` argument.
+The first received response that is not ``None`` will be used to display the log entry
+to the user.
+As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
+"""
+
+periodic_task = django.dispatch.Signal()
"""
This is a regular django signal (no pretix event signal) that we send out every
time the periodic task cronjob runs. This interval is not sharply defined, it can
@@ -103,4 +118,3 @@ be everything between a minute and a day. The actions you perform should be
idempotent, i.e. it should not make a difference if this is send out more often
than expected.
"""
-periodic_task = django.dispatch.Signal()
diff --git a/src/pretix/base/templatetags/eventsignal.py b/src/pretix/base/templatetags/eventsignal.py
new file mode 100644
index 0000000000..29f28da826
--- /dev/null
+++ b/src/pretix/base/templatetags/eventsignal.py
@@ -0,0 +1,25 @@
+import importlib
+
+from django import template
+
+from pretix.base.models import Event
+
+register = template.Library()
+
+
+@register.simple_tag
+def eventsignal(event: Event, signame: str, **kwargs):
+ """
+ Send a signal and return the concatenated return values of all responses.
+
+ Usage::
+
+ {% eventsignal event "path.to.signal" argument="value" ... %}
+ """
+ sigstr = signame.rsplit('.', 1)
+ sigmod = importlib.import_module(sigstr[0])
+ signal = getattr(sigmod, sigstr[1])
+ _html = []
+ for receiver, response in signal.send(event, **kwargs):
+ _html.append(response)
+ return "".join(_html)
diff --git a/src/pretix/control/signals.py b/src/pretix/control/signals.py
index d6697fae8c..6de3688849 100644
--- a/src/pretix/control/signals.py
+++ b/src/pretix/control/signals.py
@@ -2,50 +2,74 @@ from django.dispatch import Signal
from pretix.base.signals import EventPluginSignal
-"""
-This signal is sent out to build configuration forms for all restriction formsets
-(see plugin API documentation for details).
-"""
restriction_formset = EventPluginSignal(
providing_args=["item"]
)
+"""
+This signal is sent out to build configuration forms for all restriction formsets
+(see plugin API documentation for details).
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to include code into the HTML tag
-"""
+
html_head = EventPluginSignal(
providing_args=["request"]
)
+"""
+This signal allows you to put code inside the HTML ```` tag
+of every page in the backend. You will get the request as a keyword argument
+``request`` and can return plain HTML.
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to include navigation items in the event admin
-"""
+
nav_event = EventPluginSignal(
providing_args=["request"]
)
+"""
+This signal allows you to add additional views to the admin panel
+navigation. You will get the request as a keyword argument ``return``.
+Receivers are expected to return a list of dictionaries. The dictionaries
+should contain at least the keys ``label`` and ``url``. You can also return
+a fontawesome icon name with the key ``icon``, it will be respected depending
+on the type of navigation. You should also return an ``active`` key with a boolean
+set to ``True``, when this item should be marked as active. The ``request`` object
+will have an attribute ``event``.
+If you use this, you should read the documentation on :ref:`how to deal with URLs `
+in pretix.
+
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to include widgets to the event dashboard. Receivers
-should return a list of dictionaries, where each dictionary can have the keys:
-* content (str, containing HTML)
-* minimal width (int, widget width in 1/12ths of the page, default ist 3, can be
- ignored on small displays)
-* priority (int, used for ordering, higher comes first, default is 1)
-* link (str, optional, if the full widget should be a link)
-"""
+
event_dashboard_widgets = EventPluginSignal(
providing_args=[]
)
-
"""
-This signal is sent out to include widgets to the personal user dashboard. Receivers
+This signal is sent out to include widgets to the event dashboard. Receivers
should return a list of dictionaries, where each dictionary can have the keys:
+
* content (str, containing HTML)
* minimal width (int, widget width in 1/12ths of the page, default ist 3, can be
ignored on small displays)
* priority (int, used for ordering, higher comes first, default is 1)
* link (str, optional, if the full widget should be a link)
+
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
+
user_dashboard_widgets = Signal(
providing_args=['user']
)
+"""
+This signal is sent out to include widgets to the personal user dashboard. Receivers
+should return a list of dictionaries, where each dictionary can have the keys:
+
+* content (str, containing HTML)
+* minimal width (int, widget width in 1/12ths of the page, default ist 3, can be
+ ignored on small displays)
+* priority (int, used for ordering, higher comes first, default is 1)
+* link (str, optional, if the full widget should be a link)
+
+This is a regular django signal (no pretix event signal).
+"""
diff --git a/src/pretix/presale/signals.py b/src/pretix/presale/signals.py
index 65ebe35d8f..216a184984 100644
--- a/src/pretix/presale/signals.py
+++ b/src/pretix/presale/signals.py
@@ -1,20 +1,38 @@
from pretix.base.signals import EventPluginSignal
-"""
-This signal is sent out to include code into the HTML tag
-"""
html_head = EventPluginSignal(
providing_args=["request"]
)
+"""
+This signal allows you to put code inside the HTML ```` tag
+of every page in the frontend. You will get the request as a keyword argument
+``request`` and can return plain HTML.
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
-This signal is sent out to include links in the footer
-"""
+
footer_link = EventPluginSignal(
providing_args=["request"]
)
+"""
+The signal ``pretix.presale.signals.footer_links`` allows you to add links to the footer of an event page. You
+are expected to return a dictionary containing the keys ``label`` and ``url``.
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
+"""
+
+checkout_flow_steps = EventPluginSignal()
"""
This signal is sent out to retrieve pages for the checkout flow
+
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
+"""
+
+voucher_redeem_info = EventPluginSignal(
+ providing_args=["voucher"]
+)
+"""
+This signal is sent out to display additional information on the "redeem a voucher" page
+
+As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
-checkout_flow_steps = EventPluginSignal()
diff --git a/src/pretix/presale/templates/pretixpresale/event/voucher.html b/src/pretix/presale/templates/pretixpresale/event/voucher.html
index 4167a4af56..a39c4ce8d1 100644
--- a/src/pretix/presale/templates/pretixpresale/event/voucher.html
+++ b/src/pretix/presale/templates/pretixpresale/event/voucher.html
@@ -1,6 +1,7 @@
{% extends "pretixpresale/event/base.html" %}
{% load i18n %}
{% load eventurl %}
+{% load eventsignal %}
{% load thumbnail %}
{% block title %}{% trans "Voucher redemption" %}{% endblock %}
@@ -139,6 +140,7 @@
{% endfor %}
{% endfor %}
+ {% eventsignal event "pretix.presale.signals.voucher_redeem_info" voucher=voucher %}
{% if event.presale_is_running %}