diff --git a/src/pretix/api/serializers/event.py b/src/pretix/api/serializers/event.py index dd20324e62..a9060fa405 100644 --- a/src/pretix/api/serializers/event.py +++ b/src/pretix/api/serializers/event.py @@ -269,16 +269,13 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer): def validate_plugins(self, value): current_plugins = self.instance.get_plugins() if self.instance and self.instance.pk else [] - settings_holder = self.instance if self.instance and self.instance.pk else self.context['organizer'] - plugins_available = settings_holder.get_available_plugins() + obj = self.instance if self.instance and self.instance.pk else self.context['organizer'] + plugins_available = obj.get_available_plugins(filter_restricted=True) allowed_levels = (PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID) for plugin in value.get('plugins'): if plugin not in plugins_available: - raise ValidationError(_('Unknown plugin: \'{name}\'.').format(name=plugin)) - if getattr(plugins_available[plugin], 'restricted', False): - if plugin not in settings_holder.settings.allowed_restricted_plugins: - raise ValidationError(_('Restricted plugin: \'{name}\'.').format(name=plugin)) + raise ValidationError(_('Unknown or restricted plugin: \'{name}\'.').format(name=plugin)) level = getattr(plugins_available[plugin], 'level', PLUGIN_LEVEL_EVENT) if level not in allowed_levels: raise ValidationError('Plugin cannot be enabled on this level: \'{name}\'.'.format(name=plugin)) diff --git a/src/pretix/api/serializers/organizer.py b/src/pretix/api/serializers/organizer.py index 7047b01c15..cb4473ddda 100644 --- a/src/pretix/api/serializers/organizer.py +++ b/src/pretix/api/serializers/organizer.py @@ -80,16 +80,12 @@ class OrganizerSerializer(I18nAwareModelSerializer): fields = ('name', 'slug', 'public_url', 'plugins') def validate_plugins(self, value): - plugins_available = self.instance.get_available_plugins() - settings_holder = self.instance + plugins_available = self.instance.get_available_plugins(filter_restricted=True) allowed_levels = (PLUGIN_LEVEL_ORGANIZER, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID) for plugin in value.get('plugins'): if plugin not in plugins_available: - raise ValidationError(_('Unknown plugin: \'{name}\'.').format(name=plugin)) - if getattr(plugins_available[plugin], 'restricted', False): - if plugin not in settings_holder.settings.allowed_restricted_plugins: - raise ValidationError(_('Restricted plugin: \'{name}\'.').format(name=plugin)) + raise ValidationError(_('Unknown or restricted plugin: \'{name}\'.').format(name=plugin)) if getattr(plugins_available[plugin], 'level', PLUGIN_LEVEL_EVENT) not in allowed_levels: raise ValidationError('Plugin cannot be enabled on this level: \'{name}\'.'.format(name=plugin)) diff --git a/src/pretix/base/models/event.py b/src/pretix/base/models/event.py index 63a16519b0..f84fbdb616 100644 --- a/src/pretix/base/models/event.py +++ b/src/pretix/base/models/event.py @@ -1466,10 +1466,10 @@ class Event(PluginsMixin, EventMixin, LoggedModel): self.items.all().delete() self.subevents.all().delete() - def get_available_plugins(self): - from pretix.base.plugins import get_all_plugins_map + def get_available_plugins(self, filter_restricted=False): + from pretix.base.plugins import get_all_plugins_map, ALLOW_ALL - return get_all_plugins_map(event=self, only_visible=True) + return get_all_plugins_map(event=self, only_visible=True, allow_restricted=self.settings.allowed_restricted_plugins if filter_restricted else ALLOW_ALL) @staticmethod def clean_has_subevents(event, has_subevents): diff --git a/src/pretix/base/models/organizer.py b/src/pretix/base/models/organizer.py index 01b536b124..92fd63f53d 100644 --- a/src/pretix/base/models/organizer.py +++ b/src/pretix/base/models/organizer.py @@ -166,10 +166,10 @@ class Organizer(PluginsMixin, LoggedModel): return ObjectRelatedCache(self) - def get_available_plugins(self): - from pretix.base.plugins import get_all_plugins_map + def get_available_plugins(self, *, filter_restricted=False): + from pretix.base.plugins import get_all_plugins_map, ALLOW_ALL - return get_all_plugins_map(organizer=self, only_visible=True) + return get_all_plugins_map(organizer=self, only_visible=True, allow_restricted=self.settings.allowed_restricted_plugins if filter_restricted else ALLOW_ALL) @property def timezone(self): diff --git a/src/pretix/base/plugins.py b/src/pretix/base/plugins.py index 789ed8af25..9d14c16117 100644 --- a/src/pretix/base/plugins.py +++ b/src/pretix/base/plugins.py @@ -37,6 +37,10 @@ PLUGIN_LEVEL_ORGANIZER = 'organizer' PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID = 'event_organizer' +class ALLOW_ALL: + pass + + class PluginType(Enum): """ Plugin type classification. THIS IS DEPRECATED, DO NOT USE ANY MORE. @@ -49,10 +53,13 @@ class PluginType(Enum): EXPORT = 4 -def plugin_is_available(meta, event=None, organizer=None, only_visible=False): +def plugin_is_available(meta, event=None, organizer=None, only_visible=False, allow_restricted: type[ALLOW_ALL] | List[str]=ALLOW_ALL): if only_visible and (meta.name.startswith('.') or not getattr(meta, 'visible', True)): return False + if allow_restricted is not ALLOW_ALL and getattr(meta, 'restricted', False) and meta.module not in allow_restricted: + return False + if not hasattr(meta.app, 'is_available'): return True @@ -90,15 +97,15 @@ def get_plugin_meta_from_app_config(app): return meta -def iter_all_plugins(*, event=None, organizer=None, only_visible=False) -> Iterable[type]: +def iter_all_plugins(*, event=None, organizer=None, only_visible=False, allow_restricted: type[ALLOW_ALL] | List[str]=ALLOW_ALL) -> Iterable[type]: assert not event or not organizer for app in apps.get_app_configs(): if meta := get_plugin_meta_from_app_config(app): - if plugin_is_available(meta, event, organizer, only_visible): + if plugin_is_available(meta, event, organizer, only_visible, allow_restricted): yield meta -def get_all_plugins(*, event=None, organizer=None, only_visible=False) -> List[type]: +def get_all_plugins(*, event=None, organizer=None, only_visible=False, allow_restricted: type[ALLOW_ALL] | List[str]=ALLOW_ALL) -> List[type]: """ Returns the PretixPluginMeta classes of all plugins found in the installed Django apps. @@ -106,14 +113,14 @@ def get_all_plugins(*, event=None, organizer=None, only_visible=False) -> List[t calling `is_available`, not for filtering by plugin level. """ return sorted( - iter_all_plugins(event=event, organizer=organizer, only_visible=only_visible), + iter_all_plugins(event=event, organizer=organizer, only_visible=only_visible, allow_restricted=allow_restricted), key=lambda m: (0 if m.module.startswith('pretix.') else 1, str(m.name).lower().replace('pretix ', '')) ) -def get_all_plugins_map(*, event=None, organizer=None, only_visible=False) -> dict[str, type]: +def get_all_plugins_map(*, event=None, organizer=None, only_visible=False, allow_restricted: type[ALLOW_ALL] | List[str]=ALLOW_ALL) -> dict[str, type]: return { - p.module: p for p in iter_all_plugins(event=event, organizer=organizer, only_visible=only_visible) + p.module: p for p in iter_all_plugins(event=event, organizer=organizer, only_visible=only_visible, allow_restricted=allow_restricted) } diff --git a/src/pretix/control/views/event.py b/src/pretix/control/views/event.py index 2a840dc4d0..ed94399610 100644 --- a/src/pretix/control/views/event.py +++ b/src/pretix/control/views/event.py @@ -432,7 +432,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat def post(self, request, *args, **kwargs): self.object = self.get_object() - plugins_available = self.object.get_available_plugins() + plugins_available = self.object.get_available_plugins(filter_restricted=True) plugin_enabled = None with transaction.atomic(): @@ -442,10 +442,6 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat module = key.split(":")[1] if value == "enable" and module in plugins_available: pluginmeta = plugins_available[module] - if getattr(pluginmeta, 'restricted', False): - if module not in request.event.settings.allowed_restricted_plugins: - continue - if getattr(pluginmeta, 'level', PLUGIN_LEVEL_EVENT) not in (PLUGIN_LEVEL_EVENT, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID): continue diff --git a/src/pretix/control/views/organizer.py b/src/pretix/control/views/organizer.py index 59a7a0aada..7197f5122d 100644 --- a/src/pretix/control/views/organizer.py +++ b/src/pretix/control/views/organizer.py @@ -676,7 +676,7 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi def post(self, request, *args, **kwargs): self.object = self.get_object() - plugins_available = self.object.get_available_plugins() + plugins_available = self.object.get_available_plugins(filter_restricted=True) choose_events_next = False with transaction.atomic(): for key, value in request.POST.items(): @@ -684,10 +684,6 @@ class OrganizerPlugins(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixi module = key.split(":")[1] if value == "enable" and module in plugins_available: pluginmeta = plugins_available[module] - if getattr(pluginmeta, 'restricted', False): - if module not in request.organizer.settings.allowed_restricted_plugins: - continue - level = getattr(pluginmeta, 'level', PLUGIN_LEVEL_EVENT) if level not in (PLUGIN_LEVEL_ORGANIZER, PLUGIN_LEVEL_EVENT_ORGANIZER_HYBRID): continue