refactor signal receiver active check

This commit is contained in:
Mira Weller
2024-06-18 16:54:21 +02:00
parent 9269a485a6
commit 2045009e2e
4 changed files with 90 additions and 60 deletions

View File

@@ -44,7 +44,7 @@ from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from pretix.base.signals import logentry_object_link, EventPluginRegistry
from pretix.base.signals import logentry_object_link, EventPluginRegistry, is_app_active
class VisibleOnlyManager(models.Manager):
@@ -52,21 +52,21 @@ class VisibleOnlyManager(models.Manager):
return super().get_queryset().filter(visible=True)
def make_link(a_map, wrapper, is_active=True, event=None):
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=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({
elif event and plugin_name:
a_map['val'] = '<i>{val}</i> <a href="{plugin_href}"><span data-toggle="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,
}),
}) + '#plugin_' + plugin_name,
})
else:
a_map['val'] = '<i>{val}</i> <span data-tooltip title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
a_map['val'] = '<i>{val}</i> <span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
**a_map,
"errmes": _("The relevant plugin is currently not active."),
})
@@ -157,6 +157,15 @@ class LogEntry(models.Model):
SubEvent, Voucher,
)
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
if log_entry_type:
link_info = log_entry_type.get_object_link_info(self)
if is_app_active(self.event, meta['plugin']):
return make_link(link_info, log_entry_type.object_link_wrapper)
else:
return make_link(link_info, log_entry_type.object_link_wrapper, is_active=False,
event=self.event, plugin_name=meta['plugin'] and getattr(meta['plugin'], 'name'))
try:
if self.content_type.model_class() is Event:
return ''
@@ -165,10 +174,6 @@ class LogEntry(models.Model):
except:
return ''
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
if log_entry_type:
return log_entry_type.get_object_link(self, is_active=meta['plugin'] == 'CORE' or (meta['plugin'] and meta['plugin'] in self.event.get_plugins()))
for receiver, response in logentry_object_link.send(self.event, logentry=self):
if response:
return response
@@ -228,9 +233,9 @@ class LogEntryType:
def get_object_link_info(self, logentry) -> dict:
pass
def get_object_link(self, logentry, is_active):
def get_object_link(self, logentry):
a_map = self.get_object_link_info(logentry)
return make_link(a_map, self.object_link_wrapper, is_active, logentry.event)
return make_link(a_map, self.object_link_wrapper)
object_link_wrapper = '{val}'

View File

@@ -52,6 +52,50 @@ def _populate_app_cache():
app_cache[ac.name] = ac
def get_defining_app(o):
# 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'
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
def is_app_active(sender, app):
if app == 'CORE':
return True
excluded = settings.PRETIX_PLUGINS_EXCLUDE
if sender and app and app.name in sender.get_plugins() and app.name not in excluded:
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
return True
return False
def is_receiver_active(sender, receiver):
if sender is None:
# Send to all events!
return True
app = get_defining_app(receiver)
return is_app_active(sender, app)
class EventPluginSignal(django.dispatch.Signal):
"""
This is an extension to Django's built-in signals which differs in a way that it sends
@@ -59,22 +103,6 @@ class EventPluginSignal(django.dispatch.Signal):
Event.
"""
def _is_active(self, sender, receiver):
if sender is None:
# Send to all events!
return True
name, app = get_defining_app(receiver)
if app == 'CORE':
return True
# Only fire receivers from active plugins and core modules
excluded = settings.PRETIX_PLUGINS_EXCLUDE
if sender and app and app.name in sender.get_plugins() and app.name not in excluded:
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
return True
return False
def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers that belong to
@@ -93,7 +121,7 @@ class EventPluginSignal(django.dispatch.Signal):
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
if self._is_active(sender, receiver):
if is_receiver_active(sender, receiver):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
return responses
@@ -117,7 +145,7 @@ class EventPluginSignal(django.dispatch.Signal):
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
if self._is_active(sender, receiver):
if is_receiver_active(sender, receiver):
named[chain_kwarg_name] = response
response = receiver(signal=self, sender=sender, **named)
return response
@@ -144,7 +172,7 @@ class EventPluginSignal(django.dispatch.Signal):
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
if self._is_active(sender, receiver):
if is_receiver_active(sender, receiver):
try:
response = receiver(signal=self, sender=sender, **named)
except Exception as err:
@@ -217,32 +245,9 @@ class Registry:
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})
super().__init__({"plugin": lambda o: get_defining_app(o), **keys})
event_live_issues = EventPluginSignal()

View File

@@ -57,7 +57,7 @@ from pretix.base.models.log import (
QuotaLogEntryType, TaxRuleLogEntryType, VoucherLogEntryType,
log_entry_types,
)
from pretix.base.signals import logentry_display, orderposition_blocked_display
from pretix.base.signals import logentry_display, orderposition_blocked_display, app_cache
from pretix.base.templatetags.money import money_filter
OVERVIEW_BANLIST = [
@@ -674,6 +674,7 @@ class CoreUserImpersonatedLogEntryType(UserImpersonatedLogEntryType):
class CoreLogEntryType(LogEntryType):
pass
@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.deleted': _('A meta property has been removed from this event.'),
@@ -684,8 +685,6 @@ class CoreLogEntryType(LogEntryType):
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
'pretix.event.settings': _('The event settings have been changed.'),
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
'pretix.event.plugins.enabled': _('A plugin has been enabled.'),
'pretix.event.plugins.disabled': _('A plugin has been disabled.'),
'pretix.event.live.activated': _('The shop has been taken live.'),
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
@@ -704,6 +703,27 @@ class CoreLogEntryType(LogEntryType):
class CoreEventLogEntryType(EventLogEntryType):
pass
@log_entry_types.new_from_dict({
'pretix.event.plugins.enabled': _('The plugin has been enabled.'),
'pretix.event.plugins.disabled': _('The plugin has been disabled.'),
})
class EventPluginStateLogEntryType(EventLogEntryType):
object_link_wrapper = _('Plugin {val}')
def get_object_link_info(self, logentry) -> dict:
if 'plugin' in logentry.parsed_data:
app = app_cache.get(logentry.parsed_data['plugin'])
if app and hasattr(app, 'PretixPluginMeta'):
return {
'href': reverse('control:event.settings.plugins', kwargs={
'organizer': logentry.event.organizer.slug,
'event': logentry.event.slug,
}) + '#plugin_' + logentry.parsed_data['plugin'],
'val': app.PretixPluginMeta.name
}
@log_entry_types.new_from_dict({
'pretix.event.item.added': _('The product has been created.'),
'pretix.event.item.changed': _('The product has been changed.'),
@@ -736,7 +756,7 @@ class VariationLogEntryType(ItemLogEntryType):
logentry.parsed_data['value'] = '?'
else:
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
return super().display(logentry_display)
return super().display(logentry)
@log_entry_types.new_from_dict({

View File

@@ -23,7 +23,7 @@
<legend>{{ catlabel }}</legend>
<div class="plugin-list">
{% for plugin in plist %}
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}">
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}" id="plugin_{{ plugin.module }}">
{% if plugin.featured %}
<div class="panel panel-default">
<div class="panel-body">