Experimental organizer-level plugin implementation

This commit is contained in:
Mira Weller
2024-09-23 18:45:33 +02:00
parent e395834811
commit 2ecf81bdfe
5 changed files with 47 additions and 19 deletions

View File

@@ -742,8 +742,8 @@ class Event(EventMixin, LoggedModel):
Returns the names of the plugins activated for this event as a list.
"""
if self.plugins is None:
return []
return self.plugins.split(",")
return self.organizer.get_plugins()
return self.plugins.split(",") + self.organizer.get_plugins()
def get_cache(self):
"""

View File

@@ -91,6 +91,10 @@ class Organizer(LoggedModel):
verbose_name=_("Short form"),
unique=True
)
plugins = models.TextField(
null=True, blank=True,
verbose_name=_("Plugins"),
)
class Meta:
verbose_name = _("Organizer")
@@ -119,6 +123,14 @@ class Organizer(LoggedModel):
"""
self.settings.cookie_consent = True
def get_plugins(self):
"""
Returns the names of the plugins activated for this organizer as a list.
"""
if self.plugins is None:
return []
return self.plugins.split(",")
def get_cache(self):
"""
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to

View File

@@ -96,22 +96,27 @@ def is_receiver_active(sender, receiver):
return is_app_active(sender, app)
class EventPluginSignal(django.dispatch.Signal):
def is_plugin_host(sender):
return hasattr(sender, 'get_plugins')
class PluginSignal(django.dispatch.Signal):
"""
This is an extension to Django's built-in signals which differs in a way that it sends
out it's events only to receivers which belong to plugins that are enabled for the given
Event.
"""
def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
def send(self, sender, **named) -> List[Tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers that belong to
plugins enabled for the given Event.
sender is required to be an instance of ``pretix.base.models.Event``.
sender is required to be a plugin host (an object with a `get_plugins` method),
for example a ``pretix.base.models.Event``.
"""
if sender and not isinstance(sender, Event):
raise ValueError("Sender needs to be an event.")
if sender and not is_plugin_host(sender):
raise ValueError("Sender needs to be a plugin host.")
responses = []
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
@@ -126,16 +131,17 @@ class EventPluginSignal(django.dispatch.Signal):
responses.append((receiver, response))
return responses
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
def send_chained(self, sender, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers. The return value of the first receiver
will be used as the keyword argument specified by ``chain_kwarg_name`` in the input to the
second receiver and so on. The return value of the last receiver is returned by this method.
sender is required to be an instance of ``pretix.base.models.Event``.
sender is required to be a plugin host (an object with a `get_plugins` method),
for example a ``pretix.base.models.Event``.
"""
if sender and not isinstance(sender, Event):
raise ValueError("Sender needs to be an event.")
if sender and not is_plugin_host(sender):
raise ValueError("Sender needs to be a plugin host.")
response = named.get(chain_kwarg_name)
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
@@ -150,16 +156,17 @@ class EventPluginSignal(django.dispatch.Signal):
response = receiver(signal=self, sender=sender, **named)
return response
def send_robust(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
def send_robust(self, sender, **named) -> List[Tuple[Callable, Any]]:
"""
Send signal from sender to all connected receivers. If a receiver raises an exception
instead of returning a value, the exception is included as the result instead of
stopping the response chain at the offending receiver.
sender is required to be an instance of ``pretix.base.models.Event``.
sender is required to be a plugin host (an object with a `get_plugins` method),
for example a ``pretix.base.models.Event``.
"""
if sender and not isinstance(sender, Event):
raise ValueError("Sender needs to be an event.")
if sender and not is_plugin_host(sender):
raise ValueError("Sender needs to be a plugin host.")
responses = []
if (
@@ -194,6 +201,14 @@ class EventPluginSignal(django.dispatch.Signal):
return sorted_list
class OrganizerPluginSignal(PluginSignal):
pass
class EventPluginSignal(PluginSignal):
pass
class GlobalSignal(django.dispatch.Signal):
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
"""
@@ -245,7 +260,7 @@ class Registry:
return self.by_key.get(key).get(value, (None, None))
class EventPluginRegistry(Registry):
class PluginRegistry(Registry):
def __init__(self, keys):
super().__init__({"plugin": lambda o: get_defining_app(o), **keys})

View File

@@ -34,7 +34,7 @@
from django.dispatch import Signal
from pretix.base.signals import DeprecatedSignal, EventPluginSignal
from pretix.base.signals import DeprecatedSignal, EventPluginSignal, OrganizerPluginSignal
html_page_start = Signal()
"""
@@ -221,7 +221,7 @@ Deprecated signal, no longer works. We just keep the definition so old plugins d
break the installation.
"""
nav_organizer = Signal()
nav_organizer = OrganizerPluginSignal()
"""
Arguments: 'organizer', 'request'

View File

@@ -26,8 +26,9 @@ from django.dispatch import receiver
from django.template.loader import get_template
from django.utils.translation import gettext_lazy as _
from pretix.base.logentrytypes import EventLogEntryType
from pretix.base.models import Event, SalesChannel
from pretix.base.models.log import EventLogEntryType, log_entry_types
from pretix.base.models.log import log_entry_types
from pretix.base.signals import ( # NOQA: legacy import
EventPluginSignal, event_copy_data, item_copy_data, layout_text_variables,
logentry_display, logentry_object_link, register_data_exporters,