diff --git a/doc/api/resources/webhooks.rst b/doc/api/resources/webhooks.rst index c7be77326..94dcc1b68 100644 --- a/doc/api/resources/webhooks.rst +++ b/doc/api/resources/webhooks.rst @@ -60,6 +60,9 @@ The following values for ``action_types`` are valid with pretix core: * ``pretix.event.added`` * ``pretix.event.changed`` * ``pretix.event.deleted`` + * ``pretix.voucher.added`` + * ``pretix.voucher.changed`` + * ``pretix.voucher.deleted`` * ``pretix.subevent.added`` * ``pretix.subevent.changed`` * ``pretix.subevent.deleted`` diff --git a/src/pretix/api/webhooks.py b/src/pretix/api/webhooks.py index 927f0f885..2dcf525e9 100644 --- a/src/pretix/api/webhooks.py +++ b/src/pretix/api/webhooks.py @@ -78,6 +78,13 @@ class WebhookEvent: """ raise NotImplementedError() # NOQA + @property + def help_text(self) -> str: + """ + A human-readable description + """ + return "" + def get_all_webhook_events(): global _ALL_EVENTS @@ -97,9 +104,10 @@ def get_all_webhook_events(): class ParametrizedWebhookEvent(WebhookEvent): - def __init__(self, action_type, verbose_name): + def __init__(self, action_type, verbose_name, help_text=""): self._action_type = action_type self._verbose_name = verbose_name + self._help_text = help_text super().__init__() @property @@ -110,6 +118,10 @@ class ParametrizedWebhookEvent(WebhookEvent): def verbose_name(self): return self._verbose_name + @property + def help_text(self): + return self._help_text + class ParametrizedOrderWebhookEvent(ParametrizedWebhookEvent): def build_payload(self, logentry: LogEntry): @@ -161,6 +173,19 @@ class ParametrizedEventWebhookEvent(ParametrizedWebhookEvent): } +class ParametrizedVoucherWebhookEvent(ParametrizedWebhookEvent): + + def build_payload(self, logentry: LogEntry): + # do not use content_object, this is also called in deletion + return { + 'notification_id': logentry.pk, + 'organizer': logentry.event.organizer.slug, + 'event': logentry.event.slug, + 'voucher': logentry.object_id, + 'action': logentry.action_type, + } + + class ParametrizedSubEventWebhookEvent(ParametrizedWebhookEvent): def build_payload(self, logentry: LogEntry): @@ -346,8 +371,9 @@ def register_default_webhook_events(sender, **kwargs): ), ParametrizedItemWebhookEvent( 'pretix.event.item.*', - _('Product changed (including product added or deleted and including changes to nested objects like ' - 'variations or bundles)'), + _('Product changed'), + _('This includes product added or deleted and changes to nested objects like ' + 'variations or bundles.'), ), ParametrizedEventWebhookEvent( 'pretix.event.live.activated', @@ -381,6 +407,19 @@ def register_default_webhook_events(sender, **kwargs): 'pretix.event.orders.waitinglist.voucher_assigned', _('Waiting list entry received voucher'), ), + ParametrizedVoucherWebhookEvent( + 'pretix.voucher.added', + _('Voucher added'), + ), + ParametrizedVoucherWebhookEvent( + 'pretix.voucher.changed', + _('Voucher changed'), + _('Only includes explicit changes to the voucher, not e.g. an increase of the number of redemptions.') + ), + ParametrizedVoucherWebhookEvent( + 'pretix.voucher.deleted', + _('Voucher deleted'), + ), ParametrizedCustomerWebhookEvent( 'pretix.customer.created', _('Customer account created'), diff --git a/src/pretix/base/models/waitinglist.py b/src/pretix/base/models/waitinglist.py index 38f50de50..f7cf0ff8e 100644 --- a/src/pretix/base/models/waitinglist.py +++ b/src/pretix/base/models/waitinglist.py @@ -207,16 +207,19 @@ class WaitingListEntry(LoggedModel): block_quota=True, subevent=self.subevent, ) - v.log_action('pretix.voucher.added.waitinglist', { + v.log_action('pretix.voucher.added', { 'item': self.item.pk, 'variation': self.variation.pk if self.variation else None, 'tag': 'waiting-list', 'block_quota': True, 'valid_until': v.valid_until.isoformat(), 'max_usages': 1, + 'subevent': self.subevent.pk if self.subevent else None, + 'source': 'waitinglist', + }, user=user, auth=auth) + v.log_action('pretix.voucher.added.waitinglist', { 'email': self.email, 'waitinglistentry': self.pk, - 'subevent': self.subevent.pk if self.subevent else None, }, user=user, auth=auth) self.voucher = v self.save() diff --git a/src/pretix/control/forms/organizer.py b/src/pretix/control/forms/organizer.py index 0b7252931..e3226c776 100644 --- a/src/pretix/control/forms/organizer.py +++ b/src/pretix/control/forms/organizer.py @@ -43,7 +43,7 @@ from django.forms import formset_factory, inlineformset_factory from django.forms.utils import ErrorDict from django.urls import reverse from django.utils.crypto import get_random_string -from django.utils.html import conditional_escape +from django.utils.html import conditional_escape, format_html from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _, pgettext_lazy from django_scopes.forms import SafeModelChoiceField @@ -695,7 +695,9 @@ class WebHookForm(forms.ModelForm): self.fields['events'].choices = [ ( a.action_type, - mark_safe('{} – {}'.format(a.verbose_name, a.action_type)) + format_html('{} – {}
{}', a.verbose_name, a.action_type, a.help_text) + if a.help_text else + format_html('{} – {}', a.verbose_name, a.action_type) ) for a in get_all_webhook_events().values() ] if self.instance and self.instance.pk: diff --git a/src/pretix/control/logdisplay.py b/src/pretix/control/logdisplay.py index 34066f640..ffbe1e3bb 100644 --- a/src/pretix/control/logdisplay.py +++ b/src/pretix/control/logdisplay.py @@ -571,11 +571,11 @@ class CoreOrderLogEntryType(OrderLogEntryType): @log_entry_types.new_from_dict({ 'pretix.voucher.added': _('The voucher has been created.'), 'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'), - 'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'), 'pretix.voucher.expired.waitinglist': _( 'The voucher has been set to expire because the recipient removed themselves from the waiting list.'), 'pretix.voucher.changed': _('The voucher has been changed.'), 'pretix.voucher.deleted': _('The voucher has been deleted.'), + 'pretix.voucher.added.waitinglist': _('The voucher has been sent to {email} through the waiting list.'), }) class CoreVoucherLogEntryType(VoucherLogEntryType): pass diff --git a/src/pretix/control/views/vouchers.py b/src/pretix/control/views/vouchers.py index 9990039cb..bee6db27e 100644 --- a/src/pretix/control/views/vouchers.py +++ b/src/pretix/control/views/vouchers.py @@ -380,7 +380,7 @@ class VoucherCreate(EventPermissionRequiredMixin, CreateView): messages.success(self.request, mark_safe(_('The new voucher has been created: {code}').format( code=format_html('{code}', url=url, code=self.object.code) ))) - form.instance.log_action('pretix.voucher.added', data=dict(form.cleaned_data), user=self.request.user) + form.instance.log_action('pretix.voucher.added', data={**dict(form.cleaned_data), "source": "control"}, user=self.request.user) return ret @transaction.atomic @@ -475,7 +475,7 @@ class VoucherBulkCreate(EventPermissionRequiredMixin, AsyncFormView): data['bulk'] = True del data['codes'] log_entries.append( - v.log_action('pretix.voucher.added', data=data, user=self.request.user, save=False) + v.log_action('pretix.voucher.added', data={**data, "source": "control_bulk"}, user=self.request.user, save=False) ) LogEntry.bulk_create_and_postprocess(log_entries) form.post_bulk_save(batch_vouchers) diff --git a/src/tests/base/test_shredders.py b/src/tests/base/test_shredders.py index d8c9cb22d..e6e86913e 100644 --- a/src/tests/base/test_shredders.py +++ b/src/tests/base/test_shredders.py @@ -140,7 +140,7 @@ def test_waitinglist_shredder(event, item): ) wle.send_voucher() assert '@' in wle.voucher.comment - assert '@' in wle.voucher.all_logentries().last().data + assert '@' in wle.voucher.all_logentries().get(action_type="pretix.voucher.added.waitinglist").data s = WaitingListShredder(event) f = list(s.generate_files()) assert json.loads(f[0][2]) == [ @@ -166,7 +166,7 @@ def test_waitinglist_shredder(event, item): assert '@' not in wle.email assert '+49' not in str(wle.phone) assert '@' not in wle.voucher.comment - assert '@' not in wle.voucher.all_logentries().last().data + assert '@' not in wle.voucher.all_logentries().get(action_type="pretix.voucher.added.waitinglist").data @pytest.mark.django_db