store plugin name for registered types

This commit is contained in:
Mira Weller
2024-06-18 15:40:47 +02:00
parent 166f50fcb0
commit 9269a485a6
8 changed files with 189 additions and 206 deletions

View File

@@ -33,6 +33,7 @@
# License for the specific language governing permissions and limitations under the License. # License for the specific language governing permissions and limitations under the License.
import json import json
import logging
from collections import defaultdict from collections import defaultdict
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
@@ -43,7 +44,7 @@ from django.utils.functional import cached_property
from django.utils.html import escape from django.utils.html import escape
from django.utils.translation import gettext_lazy as _, pgettext_lazy from django.utils.translation import gettext_lazy as _, pgettext_lazy
from pretix.base.signals import logentry_object_link from pretix.base.signals import logentry_object_link, EventPluginRegistry
class VisibleOnlyManager(models.Manager): class VisibleOnlyManager(models.Manager):
@@ -51,6 +52,27 @@ class VisibleOnlyManager(models.Manager):
return super().get_queryset().filter(visible=True) return super().get_queryset().filter(visible=True)
def make_link(a_map, wrapper, is_active=True, event=None):
if a_map:
if is_active:
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
elif event:
a_map['val'] = '<i>{val}</i> <a href="{plugin_href}"><span data-tooltip title="{errmes}" class="fa fa-warning fa-fw"></span></a>'.format_map({
**a_map,
"errmes": _("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
"plugin_href": reverse('control:event.settings.plugins', kwargs={
'organizer': event.organizer.slug,
'event': event.slug,
}),
})
else:
a_map['val'] = '<i>{val}</i> <span data-tooltip title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
**a_map,
"errmes": _("The relevant plugin is currently not active."),
})
return wrapper.format_map(a_map)
class LogEntry(models.Model): class LogEntry(models.Model):
""" """
Represents a change or action that has been performed on another object Represents a change or action that has been performed on another object
@@ -93,7 +115,7 @@ class LogEntry(models.Model):
indexes = [models.Index(fields=["datetime", "id"])] indexes = [models.Index(fields=["datetime", "id"])]
def display(self): def display(self):
log_entry_type = log_entry_types.find(action_type=self.action_type) log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
if log_entry_type: if log_entry_type:
return log_entry_type.display(self) return log_entry_type.display(self)
@@ -142,92 +164,19 @@ class LogEntry(models.Model):
co = self.content_object co = self.content_object
except: except:
return '' return ''
a_map = None
a_text = None
if isinstance(co, Order): log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
a_text = _('Order {val}') if log_entry_type:
a_map = { return log_entry_type.get_object_link(self, is_active=meta['plugin'] == 'CORE' or (meta['plugin'] and meta['plugin'] in self.event.get_plugins()))
'href': reverse('control:event.order', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'code': co.code
}),
'val': escape(co.code),
}
elif isinstance(co, Voucher):
a_text = _('Voucher {val}')
a_map = {
'href': reverse('control:event.voucher', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'voucher': co.id
}),
'val': escape(co.code[:6]),
}
elif isinstance(co, Item):
a_text = _('Product {val}')
a_map = {
'href': reverse('control:event.item', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'item': co.id
}),
'val': escape(co.name),
}
elif isinstance(co, SubEvent):
a_text = pgettext_lazy('subevent', 'Date {val}')
a_map = {
'href': reverse('control:event.subevent', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'subevent': co.id
}),
'val': escape(str(co))
}
elif isinstance(co, Quota):
a_text = _('Quota {val}')
a_map = {
'href': reverse('control:event.items.quotas.show', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'quota': co.id
}),
'val': escape(co.name),
}
elif isinstance(co, Discount):
a_text = _('Discount {val}')
a_map = {
'href': reverse('control:event.items.discounts.edit', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'discount': co.id
}),
'val': escape(co.internal_name),
}
elif isinstance(co, Question):
a_text = _('Question {val}')
a_map = {
'href': reverse('control:event.items.questions.show', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
'question': co.id
}),
'val': escape(co.question),
}
if a_text and a_map: for receiver, response in logentry_object_link.send(self.event, logentry=self):
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map) if response:
return a_text.format_map(a_map) return response
else:
log_entry_type = log_entry_types.find(action_type=self.action_type)
if log_entry_type:
return log_entry_type.get_object_link(self)
for receiver, response in logentry_object_link.send(self.event, logentry=self): if isinstance(co, (Order, Voucher, Item, SubEvent, Quota, Discount, Question)):
if response: logging.warning("LogEntryType missing or ill-defined: %s", self.action_type)
return response
return '' return ''
@cached_property @cached_property
def parsed_data(self): def parsed_data(self):
@@ -250,33 +199,23 @@ class LogEntry(models.Model):
notify_webhooks.apply_async(args=(to_wh,)) notify_webhooks.apply_async(args=(to_wh,))
class Registry: class LogEntryTypeRegistry(EventPluginRegistry):
def __init__(self, keys): def new_from_dict(self, data):
self.registered_items = list()
self.keys = keys
self.by_key = {key: {} for key in self.keys.keys()}
def register(self, *objs):
for obj in objs:
self.registered_items.append(obj)
for key, accessor in self.keys.items():
self.by_key[key][accessor(obj)] = obj
def register_instance(self, *args, **kwargs):
def reg(clz): def reg(clz):
obj = clz(*args, **kwargs) for action_type, plain in data.items():
self.register(obj) self.register(clz(action_type=action_type, plain=plain))
return reg return reg
def find(self, **kwargs):
(key, value), = kwargs.items()
return self.by_key.get(key).get(value)
log_entry_types = LogEntryTypeRegistry({'action_type': lambda o: getattr(o, 'action_type')})
log_entry_types = Registry({'action_type': lambda o: getattr(o, 'action_type')})
class LogEntryType: class LogEntryType:
def __init__(self, action_type=None, plain=None):
assert self.__module__ != LogEntryType.__module__ # must not instantiate base classes, only derived ones
if action_type: self.action_type = action_type
if plain: self.plain = plain
def display(self, logentry): def display(self, logentry):
if hasattr(self, 'plain'): if hasattr(self, 'plain'):
plain = str(self.plain) plain = str(self.plain)
@@ -289,25 +228,15 @@ class LogEntryType:
def get_object_link_info(self, logentry) -> dict: def get_object_link_info(self, logentry) -> dict:
pass pass
def get_object_link(self, logentry): def get_object_link(self, logentry, is_active):
a_map = self.get_object_link_info(logentry) a_map = self.get_object_link_info(logentry)
if a_map: return make_link(a_map, self.object_link_wrapper, is_active, logentry.event)
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
return self.object_link_wrapper.format_map(a_map)
object_link_wrapper = '{val}' object_link_wrapper = '{val}'
def shred_pii(self, logentry): def shred_pii(self, logentry):
raise NotImplementedError raise NotImplementedError
@classmethod
def derive_plains(cls, plains):
for action_type, plain_display in plains.items():
obj = cls()
obj.action_type = action_type
obj.plain = plain_display
yield obj
class EventLogEntryType(LogEntryType): class EventLogEntryType(LogEntryType):
def get_object_link_info(self, logentry) -> dict: def get_object_link_info(self, logentry) -> dict:

View File

@@ -33,7 +33,7 @@
# License for the specific language governing permissions and limitations under the License. # License for the specific language governing permissions and limitations under the License.
import warnings import warnings
from typing import Any, Callable, List, Tuple from typing import Any, Callable, List, Tuple, Optional
import django.dispatch import django.dispatch
from django.apps import apps from django.apps import apps
@@ -64,23 +64,10 @@ class EventPluginSignal(django.dispatch.Signal):
# Send to all events! # Send to all events!
return True return True
# If sentry packed this in a wrapper, unpack that name, app = get_defining_app(receiver)
if "sentry" in receiver.__module__: if app == 'CORE':
receiver = receiver.__wrapped__
# Find the Django application this belongs to
searchpath = receiver.__module__
# Core modules are always active
if any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
return True return True
while True:
app = app_cache.get(searchpath)
if "." not in searchpath or app:
break
searchpath, _ = searchpath.rsplit(".", 1)
# Only fire receivers from active plugins and core modules # Only fire receivers from active plugins and core modules
excluded = settings.PRETIX_PLUGINS_EXCLUDE excluded = settings.PRETIX_PLUGINS_EXCLUDE
if sender and app and app.name in sender.get_plugins() and app.name not in excluded: if sender and app and app.name in sender.get_plugins() and app.name not in excluded:
@@ -204,6 +191,60 @@ class DeprecatedSignal(django.dispatch.Signal):
super().connect(receiver, sender=None, weak=True, dispatch_uid=None) super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
class Registry:
def __init__(self, keys):
self.registered_items = list()
self.keys = keys
self.by_key = {key: {} for key in self.keys.keys()}
def register(self, *objs):
for obj in objs:
meta = {k: accessor(obj) for k, accessor in self.keys.items()}
tup = (obj, meta)
for key, accessor in self.keys.items():
self.by_key[key][accessor(obj)] = tup
self.registered_items.append(tup)
def new(self, *args, **kwargs):
def reg(clz):
obj = clz(*args, **kwargs)
self.register(obj)
return clz
return reg
def find(self, **kwargs):
(key, value), = kwargs.items()
return self.by_key.get(key).get(value, (None, None))
def get_defining_app(o) -> Tuple[Optional[str], Optional["django.apps.AppConfig"]]:
# If sentry packed this in a wrapper, unpack that
if "sentry" in o.__module__:
o = o.__wrapped__
# Find the Django application this belongs to
searchpath = o.__module__
# Core modules are always active
if any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
return 'CORE', 'CORE'
if not app_cache:
_populate_app_cache()
while True:
app = app_cache.get(searchpath)
if "." not in searchpath or app:
break
searchpath, _ = searchpath.rsplit(".", 1)
return app and app.name, app
class EventPluginRegistry(Registry):
def __init__(self, keys):
super().__init__({"plugin": lambda o: get_defining_app(o)[0], **keys})
event_live_issues = EventPluginSignal() event_live_issues = EventPluginSignal()
""" """
This signal is sent out to determine whether an event can be taken live. If you want to This signal is sent out to determine whether an event can be taken live. If you want to

View File

@@ -382,7 +382,7 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
return _('Blocked because of an API integration') return _('Blocked because of an API integration')
log_entry_types.register(*OrderLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.order.modified': _('The order details have been changed.'), 'pretix.event.order.modified': _('The order details have been changed.'),
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'), 'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'), 'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
@@ -451,10 +451,12 @@ log_entry_types.register(*OrderLogEntryType.derive_plains({
'approval.'), 'approval.'),
'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'), 'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'),
'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'), 'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'),
})) })
class CoreOrderLogEntryType(OrderLogEntryType):
pass
log_entry_types.register(*VoucherLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.voucher.added': _('The voucher has been created.'), 'pretix.voucher.added': _('The voucher has been created.'),
'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'), '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.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
@@ -462,10 +464,12 @@ log_entry_types.register(*VoucherLogEntryType.derive_plains({
'The voucher has been set to expire because the recipient removed themselves from the waiting list.'), '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.changed': _('The voucher has been changed.'),
'pretix.voucher.deleted': _('The voucher has been deleted.'), 'pretix.voucher.deleted': _('The voucher has been deleted.'),
})) })
class CoreVoucherLogEntryType(VoucherLogEntryType):
pass
@log_entry_types.register_instance() @log_entry_types.new()
class VoucherRedeemedLogEntryType(VoucherLogEntryType): class VoucherRedeemedLogEntryType(VoucherLogEntryType):
action_type = 'pretix.voucher.redeemed' action_type = 'pretix.voucher.redeemed'
plain = _('The voucher has been redeemed in order {order_code}.') plain = _('The voucher has been redeemed in order {order_code}.')
@@ -483,19 +487,23 @@ class VoucherRedeemedLogEntryType(VoucherLogEntryType):
)) ))
log_entry_types.register(*ItemCategoryLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.category.added': _('The category has been added.'), 'pretix.event.category.added': _('The category has been added.'),
'pretix.event.category.deleted': _('The category has been deleted.'), 'pretix.event.category.deleted': _('The category has been deleted.'),
'pretix.event.category.changed': _('The category has been changed.'), 'pretix.event.category.changed': _('The category has been changed.'),
'pretix.event.category.reordered': _('The category has been reordered.'), 'pretix.event.category.reordered': _('The category has been reordered.'),
})) })
class CoreItemCategoryLogEntryType(ItemCategoryLogEntryType):
pass
log_entry_types.register(*TaxRuleLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.taxrule.added': _('The tax rule has been added.'), 'pretix.event.taxrule.added': _('The tax rule has been added.'),
'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'), 'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'),
'pretix.event.taxrule.changed': _('The tax rule has been changed.'), 'pretix.event.taxrule.changed': _('The tax rule has been changed.'),
})) })
class CoreTaxRuleLogEntryType(TaxRuleLogEntryType):
pass
class TeamMembershipLogEntryType(LogEntryType): class TeamMembershipLogEntryType(LogEntryType):
@@ -503,15 +511,17 @@ class TeamMembershipLogEntryType(LogEntryType):
return self.plain.format(user=logentry.parsed_data.get('email')) return self.plain.format(user=logentry.parsed_data.get('email'))
log_entry_types.register(*TeamMembershipLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.team.member.added': _('{user} has been added to the team.'), 'pretix.team.member.added': _('{user} has been added to the team.'),
'pretix.team.member.removed': _('{user} has been removed from the team.'), 'pretix.team.member.removed': _('{user} has been removed from the team.'),
'pretix.team.invite.created': _('{user} has been invited to the team.'), 'pretix.team.invite.created': _('{user} has been invited to the team.'),
'pretix.team.invite.resent': _('Invite for {user} has been resent.'), 'pretix.team.invite.resent': _('Invite for {user} has been resent.'),
})) })
class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
pass
@log_entry_types.register_instance() @log_entry_types.new()
class TeamMemberJoinedLogEntryType(LogEntryType): class TeamMemberJoinedLogEntryType(LogEntryType):
action_type = 'pretix.team.member.joined' action_type = 'pretix.team.member.joined'
@@ -521,7 +531,7 @@ class TeamMemberJoinedLogEntryType(LogEntryType):
) )
@log_entry_types.register_instance() @log_entry_types.new()
class UserSettingsChangedLogEntryType(LogEntryType): class UserSettingsChangedLogEntryType(LogEntryType):
action_type = 'pretix.user.settings.changed' action_type = 'pretix.user.settings.changed'
@@ -544,13 +554,15 @@ class UserImpersonatedLogEntryType(LogEntryType):
return self.plain.format(logentry.parsed_data['other_email']) return self.plain.format(logentry.parsed_data['other_email'])
log_entry_types.register(*UserImpersonatedLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.control.auth.user.impersonated': _('You impersonated {}.'), 'pretix.control.auth.user.impersonated': _('You impersonated {}.'),
'pretix.control.auth.user.impersonate_stopped': _('You stopped impersonating {}.'), 'pretix.control.auth.user.impersonate_stopped': _('You stopped impersonating {}.'),
})) })
class CoreUserImpersonatedLogEntryType(UserImpersonatedLogEntryType):
pass
log_entry_types.register(*LogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.object.cloned': _('This object has been created by cloning.'), 'pretix.object.cloned': _('This object has been created by cloning.'),
'pretix.organizer.changed': _('The organizer has been changed.'), 'pretix.organizer.changed': _('The organizer has been changed.'),
'pretix.organizer.settings': _('The organizer settings have been changed.'), 'pretix.organizer.settings': _('The organizer settings have been changed.'),
@@ -658,9 +670,11 @@ log_entry_types.register(*LogEntryType.derive_plains({
'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'), 'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'),
'pretix.team.token.created': _('The token "{name}" has been created.'), 'pretix.team.token.created': _('The token "{name}" has been created.'),
'pretix.team.token.deleted': _('The token "{name}" has been revoked.'), 'pretix.team.token.deleted': _('The token "{name}" has been revoked.'),
})) })
class CoreLogEntryType(LogEntryType):
pass
log_entry_types.register(*EventLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'), 'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'), 'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'), 'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
@@ -686,9 +700,11 @@ log_entry_types.register(*EventLogEntryType.derive_plains({
'pretix.event.permissions.invited': _('A user has been invited to the event team.'), 'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'), 'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
'pretix.event.permissions.deleted': _('A user has been removed from the event team.'), 'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
})) })
class CoreEventLogEntryType(EventLogEntryType):
pass
log_entry_types.register(*ItemLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.item.added': _('The product has been created.'), 'pretix.event.item.added': _('The product has been created.'),
'pretix.event.item.changed': _('The product has been changed.'), 'pretix.event.item.changed': _('The product has been changed.'),
'pretix.event.item.reordered': _('The product has been reordered.'), 'pretix.event.item.reordered': _('The product has been reordered.'),
@@ -699,9 +715,16 @@ log_entry_types.register(*ItemLogEntryType.derive_plains({
'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'), 'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'),
'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'), 'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'),
'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'), 'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'),
})) })
class CoreItemLogEntryType(ItemLogEntryType):
pass
@log_entry_types.new_from_dict({
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
})
class VariationLogEntryType(ItemLogEntryType): class VariationLogEntryType(ItemLogEntryType):
def display(self, logentry): def display(self, logentry):
if 'value' not in logentry.parsed_data: if 'value' not in logentry.parsed_data:
@@ -716,13 +739,7 @@ class VariationLogEntryType(ItemLogEntryType):
return super().display(logentry_display) return super().display(logentry_display)
log_entry_types.register(*VariationLogEntryType.derive_plains({ @log_entry_types.new_from_dict({
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
}))
log_entry_types.register(*OrderLogEntryType.derive_plains({
'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'), 'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'),
'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'), 'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'),
'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'), 'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'),
@@ -736,31 +753,42 @@ log_entry_types.register(*OrderLogEntryType.derive_plains({
'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'), 'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'),
'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'), 'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'),
'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'), 'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'),
})) })
class CoreOrderLogEntryType(OrderLogEntryType):
pass
log_entry_types.register(*QuotaLogEntryType.derive_plains({
@log_entry_types.new_from_dict({
'pretix.event.quota.added': _('The quota has been added.'), 'pretix.event.quota.added': _('The quota has been added.'),
'pretix.event.quota.deleted': _('The quota has been deleted.'), 'pretix.event.quota.deleted': _('The quota has been deleted.'),
'pretix.event.quota.changed': _('The quota has been changed.'), 'pretix.event.quota.changed': _('The quota has been changed.'),
'pretix.event.quota.closed': _('The quota has closed.'), 'pretix.event.quota.closed': _('The quota has closed.'),
'pretix.event.quota.opened': _('The quota has been re-opened.'), 'pretix.event.quota.opened': _('The quota has been re-opened.'),
})) })
class CoreQuotaLogEntryType(QuotaLogEntryType):
pass
log_entry_types.register(*QuestionLogEntryType.derive_plains({
@log_entry_types.new_from_dict({
'pretix.event.question.added': _('The question has been added.'), 'pretix.event.question.added': _('The question has been added.'),
'pretix.event.question.deleted': _('The question has been deleted.'), 'pretix.event.question.deleted': _('The question has been deleted.'),
'pretix.event.question.changed': _('The question has been changed.'), 'pretix.event.question.changed': _('The question has been changed.'),
'pretix.event.question.reordered': _('The question has been reordered.'), 'pretix.event.question.reordered': _('The question has been reordered.'),
})) })
class CoreQuestionLogEntryType(QuestionLogEntryType):
pass
log_entry_types.register(*DiscountLogEntryType.derive_plains({
@log_entry_types.new_from_dict({
'pretix.event.discount.added': _('The discount has been added.'), 'pretix.event.discount.added': _('The discount has been added.'),
'pretix.event.discount.deleted': _('The discount has been deleted.'), 'pretix.event.discount.deleted': _('The discount has been deleted.'),
'pretix.event.discount.changed': _('The discount has been changed.'), 'pretix.event.discount.changed': _('The discount has been changed.'),
})) })
class CoreDiscountLogEntryType(DiscountLogEntryType):
pass
@log_entry_types.register_instance() @log_entry_types.new()
class LegacyCheckinLogEntryType(OrderLogEntryType): class LegacyCheckinLogEntryType(OrderLogEntryType):
action_type = 'pretix.control.views.checkin' action_type = 'pretix.control.views.checkin'

View File

@@ -172,15 +172,13 @@ def control_order_info(sender: Event, request, order: Order, **kwargs):
return template.render(ctx, request=request) return template.render(ctx, request=request)
@log_entry_types.new_from_dict({
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
})
class BadgeLogEntryType(EventLogEntryType): class BadgeLogEntryType(EventLogEntryType):
object_type = BadgeLayout object_type = BadgeLayout
object_link_wrapper = _('Badge layout {val}') object_link_wrapper = _('Badge layout {val}')
object_link_viewname = 'plugins:badges:edit' object_link_viewname = 'plugins:badges:edit'
object_link_argname = 'layout' object_link_argname = 'layout'
log_entry_types.register(*BadgeLogEntryType.derive_plains({
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
}))

View File

@@ -118,7 +118,7 @@ def html_head_presale(sender, request=None, **kwargs):
return "" return ""
@log_entry_types.register_instance() @log_entry_types.new()
class BanktransferOrderEmailInvoiceLogEntryType(OrderLogEntryType): class BanktransferOrderEmailInvoiceLogEntryType(OrderLogEntryType):
action_type = 'pretix.plugins.banktransfer.order.email.invoice' action_type = 'pretix.plugins.banktransfer.order.email.invoice'
plain = _('The invoice was sent to the designated email address.') plain = _('The invoice was sent to the designated email address.')

View File

@@ -32,7 +32,7 @@ from django.utils.translation import gettext_lazy as _, pgettext_lazy
from pretix.base.forms import SecretKeySettingsField from pretix.base.forms import SecretKeySettingsField
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
from pretix.base.models.log import EventLogEntryType from pretix.base.models.log import EventLogEntryType, log_entry_types
from pretix.base.settings import settings_hierarkey from pretix.base.settings import settings_hierarkey
from pretix.base.signals import ( from pretix.base.signals import (
register_global_settings, register_payment_providers, register_global_settings, register_payment_providers,
@@ -47,6 +47,7 @@ def register_payment_provider(sender, **kwargs):
return [PaypalSettingsHolder, PaypalWallet, PaypalAPM] return [PaypalSettingsHolder, PaypalWallet, PaypalAPM]
@log_entry_types.new()
class PaypalEventLogEntryType(EventLogEntryType): class PaypalEventLogEntryType(EventLogEntryType):
action_type = 'pretix.plugins.paypal.event' action_type = 'pretix.plugins.paypal.event'

View File

@@ -119,26 +119,23 @@ def control_nav_import(sender, request=None, **kwargs):
] ]
@log_entry_types.new('pretix.plugins.sendmail.sent', _('Mass email was sent to customers or attendees.'))
@log_entry_types.new('pretix.plugins.sendmail.sent.waitinglist', _('Mass email was sent to waiting list entries.'))
class SendmailPluginLogEntryType(EventLogEntryType): class SendmailPluginLogEntryType(EventLogEntryType):
pass pass
log_entry_types.register(*SendmailPluginLogEntryType.derive_plains({ @log_entry_types.new('pretix.plugins.sendmail.order.email.sent', _('The order received a mass email.'))
'pretix.plugins.sendmail.sent': _('Mass email was sent to customers or attendees.'), @log_entry_types.new('pretix.plugins.sendmail.order.email.sent.attendee', _('A ticket holder of this order received a mass email.'))
'pretix.plugins.sendmail.sent.waitinglist': _('Mass email was sent to waiting list entries.'),
}))
class SendmailPluginOrderLogEntryType(OrderLogEntryType): class SendmailPluginOrderLogEntryType(OrderLogEntryType):
pass pass
log_entry_types.register(*SendmailPluginOrderLogEntryType.derive_plains({ @log_entry_types.new('pretix.plugins.sendmail.rule.added', _('An email rule was created'))
'pretix.plugins.sendmail.order.email.sent': _('The order received a mass email.'), @log_entry_types.new('pretix.plugins.sendmail.rule.changed', _('An email rule was updated'))
'pretix.plugins.sendmail.order.email.sent.attendee': _('A ticket holder of this order received a mass email.'), @log_entry_types.new('pretix.plugins.sendmail.rule.order.email.sent', _('A scheduled email was sent to the order'))
})) @log_entry_types.new('pretix.plugins.sendmail.rule.order.position.email.sent', _('A scheduled email was sent to a ticket holder'))
@log_entry_types.new('pretix.plugins.sendmail.rule.deleted', _('An email rule was deleted'))
class SendmailPluginRuleLogEntryType(EventLogEntryType): class SendmailPluginRuleLogEntryType(EventLogEntryType):
object_type = Rule object_type = Rule
object_link_wrapper = _('Mail rule {val}') object_link_wrapper = _('Mail rule {val}')
@@ -146,15 +143,6 @@ class SendmailPluginRuleLogEntryType(EventLogEntryType):
object_link_argname = 'rule' object_link_argname = 'rule'
log_entry_types.register(*SendmailPluginRuleLogEntryType.derive_plains({
'pretix.plugins.sendmail.rule.added': _('An email rule was created'),
'pretix.plugins.sendmail.rule.changed': _('An email rule was updated'),
'pretix.plugins.sendmail.rule.order.email.sent': _('A scheduled email was sent to the order'),
'pretix.plugins.sendmail.rule.order.position.email.sent': _('A scheduled email was sent to a ticket holder'),
'pretix.plugins.sendmail.rule.deleted': _('An email rule was deleted'),
}))
@receiver(periodic_task) @receiver(periodic_task)
def sendmail_run_rules(sender, **kwargs): def sendmail_run_rules(sender, **kwargs):
with scopes_disabled(): with scopes_disabled():

View File

@@ -133,6 +133,11 @@ def pdf_event_copy_data_receiver(sender, other, item_map, question_map, **kwargs
return layout_map return layout_map
@log_entry_types.new_from_dict({
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
})
class PdfTicketLayoutLogEntryType(EventLogEntryType): class PdfTicketLayoutLogEntryType(EventLogEntryType):
object_type = TicketLayout object_type = TicketLayout
object_link_wrapper = _('Ticket layout {val}') object_link_wrapper = _('Ticket layout {val}')
@@ -140,13 +145,6 @@ class PdfTicketLayoutLogEntryType(EventLogEntryType):
object_link_argname = 'layout' object_link_argname = 'layout'
log_entry_types.register(*PdfTicketLayoutLogEntryType.derive_plains({
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
}))
def _ticket_layouts_for_item(request, item): def _ticket_layouts_for_item(request, item):
if not hasattr(request, '_ticket_layouts_for_item'): if not hasattr(request, '_ticket_layouts_for_item'):
request._ticket_layouts_for_item = {} request._ticket_layouts_for_item = {}