mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
refactor signal receiver active check
This commit is contained in:
@@ -44,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, EventPluginRegistry
|
from pretix.base.signals import logentry_object_link, EventPluginRegistry, is_app_active
|
||||||
|
|
||||||
|
|
||||||
class VisibleOnlyManager(models.Manager):
|
class VisibleOnlyManager(models.Manager):
|
||||||
@@ -52,21 +52,21 @@ 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):
|
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=None):
|
||||||
if a_map:
|
if a_map:
|
||||||
if is_active:
|
if is_active:
|
||||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||||
elif event:
|
elif event and plugin_name:
|
||||||
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['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,
|
**a_map,
|
||||||
"errmes": _("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
|
"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={
|
"plugin_href": reverse('control:event.settings.plugins', kwargs={
|
||||||
'organizer': event.organizer.slug,
|
'organizer': event.organizer.slug,
|
||||||
'event': event.slug,
|
'event': event.slug,
|
||||||
}),
|
}) + '#plugin_' + plugin_name,
|
||||||
})
|
})
|
||||||
else:
|
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,
|
**a_map,
|
||||||
"errmes": _("The relevant plugin is currently not active."),
|
"errmes": _("The relevant plugin is currently not active."),
|
||||||
})
|
})
|
||||||
@@ -157,6 +157,15 @@ class LogEntry(models.Model):
|
|||||||
SubEvent, Voucher,
|
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:
|
try:
|
||||||
if self.content_type.model_class() is Event:
|
if self.content_type.model_class() is Event:
|
||||||
return ''
|
return ''
|
||||||
@@ -165,10 +174,6 @@ class LogEntry(models.Model):
|
|||||||
except:
|
except:
|
||||||
return ''
|
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):
|
for receiver, response in logentry_object_link.send(self.event, logentry=self):
|
||||||
if response:
|
if response:
|
||||||
return response
|
return response
|
||||||
@@ -228,9 +233,9 @@ 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, is_active):
|
def get_object_link(self, logentry):
|
||||||
a_map = self.get_object_link_info(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}'
|
object_link_wrapper = '{val}'
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,50 @@ def _populate_app_cache():
|
|||||||
app_cache[ac.name] = ac
|
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):
|
class EventPluginSignal(django.dispatch.Signal):
|
||||||
"""
|
"""
|
||||||
This is an extension to Django's built-in signals which differs in a way that it sends
|
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.
|
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]]:
|
def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
|
||||||
"""
|
"""
|
||||||
Send signal from sender to all connected receivers that belong to
|
Send signal from sender to all connected receivers that belong to
|
||||||
@@ -93,7 +121,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
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)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
responses.append((receiver, response))
|
responses.append((receiver, response))
|
||||||
return responses
|
return responses
|
||||||
@@ -117,7 +145,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
for receiver in self._sorted_receivers(sender):
|
||||||
if self._is_active(sender, receiver):
|
if is_receiver_active(sender, receiver):
|
||||||
named[chain_kwarg_name] = response
|
named[chain_kwarg_name] = response
|
||||||
response = receiver(signal=self, sender=sender, **named)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
return response
|
return response
|
||||||
@@ -144,7 +172,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
for receiver in self._sorted_receivers(sender):
|
||||||
if self._is_active(sender, receiver):
|
if is_receiver_active(sender, receiver):
|
||||||
try:
|
try:
|
||||||
response = receiver(signal=self, sender=sender, **named)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -217,32 +245,9 @@ class Registry:
|
|||||||
return self.by_key.get(key).get(value, (None, None))
|
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):
|
class EventPluginRegistry(Registry):
|
||||||
def __init__(self, keys):
|
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()
|
event_live_issues = EventPluginSignal()
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ from pretix.base.models.log import (
|
|||||||
QuotaLogEntryType, TaxRuleLogEntryType, VoucherLogEntryType,
|
QuotaLogEntryType, TaxRuleLogEntryType, VoucherLogEntryType,
|
||||||
log_entry_types,
|
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
|
from pretix.base.templatetags.money import money_filter
|
||||||
|
|
||||||
OVERVIEW_BANLIST = [
|
OVERVIEW_BANLIST = [
|
||||||
@@ -674,6 +674,7 @@ class CoreUserImpersonatedLogEntryType(UserImpersonatedLogEntryType):
|
|||||||
class CoreLogEntryType(LogEntryType):
|
class CoreLogEntryType(LogEntryType):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@log_entry_types.new_from_dict({
|
@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.'),
|
||||||
@@ -684,8 +685,6 @@ class CoreLogEntryType(LogEntryType):
|
|||||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||||
'pretix.event.settings': _('The event settings have been changed.'),
|
'pretix.event.settings': _('The event settings have been changed.'),
|
||||||
'pretix.event.tickets.settings': _('The ticket download 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.activated': _('The shop has been taken live.'),
|
||||||
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
||||||
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
||||||
@@ -704,6 +703,27 @@ class CoreLogEntryType(LogEntryType):
|
|||||||
class CoreEventLogEntryType(EventLogEntryType):
|
class CoreEventLogEntryType(EventLogEntryType):
|
||||||
pass
|
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({
|
@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.'),
|
||||||
@@ -736,7 +756,7 @@ class VariationLogEntryType(ItemLogEntryType):
|
|||||||
logentry.parsed_data['value'] = '?'
|
logentry.parsed_data['value'] = '?'
|
||||||
else:
|
else:
|
||||||
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
|
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
|
||||||
return super().display(logentry_display)
|
return super().display(logentry)
|
||||||
|
|
||||||
|
|
||||||
@log_entry_types.new_from_dict({
|
@log_entry_types.new_from_dict({
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<legend>{{ catlabel }}</legend>
|
<legend>{{ catlabel }}</legend>
|
||||||
<div class="plugin-list">
|
<div class="plugin-list">
|
||||||
{% for plugin in plist %}
|
{% 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 %}
|
{% if plugin.featured %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|||||||
Reference in New Issue
Block a user