Add search and links to plugin settings (#4854)

* Show links to plugin views and settings in plugin list and in success message after activating a plugin
* Fix menu highlighting in payment provider settings
* Specify settings_links and navigation_links for built-in plugins
* Add link to payment plugins from payment settings
* Add client-side search and "View only active plugins" for plugins page
This commit is contained in:
luelista
2025-03-24 15:04:35 +01:00
committed by GitHub
parent 6a92b98766
commit 5375e22781
20 changed files with 272 additions and 36 deletions

View File

@@ -34,6 +34,7 @@
# License for the specific language governing permissions and limitations under the License.
import json
import logging
import operator
import re
from collections import OrderedDict
@@ -62,8 +63,9 @@ from django.http import (
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils.functional import cached_property
from django.utils.html import conditional_escape
from django.utils.html import conditional_escape, format_html
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.safestring import mark_safe
from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _, gettext_noop
from django.views.generic import FormView, ListView
@@ -109,6 +111,8 @@ from ...helpers.format import (
from ..logdisplay import OVERVIEW_BANLIST
from . import CreateView, PaginationMixin, UpdateView
logger = logging.getLogger(__name__)
class EventSettingsViewMixin:
def get_context_data(self, **kwargs):
@@ -339,12 +343,29 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
def get_object(self, queryset=None) -> Event:
return self.request.event
def get_context_data(self, *args, **kwargs) -> dict:
def available_plugins(self, event):
from pretix.base.plugins import get_all_plugins
return (p for p in get_all_plugins(event) if not p.name.startswith('.')
and getattr(p, 'visible', True))
def prepare_links(self, pluginmeta, key):
links = getattr(pluginmeta, key, [])
try:
return [
(
reverse(urlname, kwargs={"organizer": self.request.organizer.slug, "event": self.request.event.slug, **kwargs}),
" > ".join(map(str, linktext)) if isinstance(linktext, tuple) else linktext,
) for linktext, urlname, kwargs in links
]
except:
logger.exception('Failed to resolve settings links.')
return []
def get_context_data(self, *args, **kwargs) -> dict:
context = super().get_context_data(*args, **kwargs)
plugins = [p for p in get_all_plugins(self.object) if not p.name.startswith('.')
and getattr(p, 'visible', True)]
plugins = list(self.available_plugins(self.object))
order = [
'FEATURE',
'PAYMENT',
@@ -375,12 +396,18 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
)
plugins_grouped = [(c, list(plist)) for c, plist in plugins_grouped]
active_plugins = self.object.get_plugins()
def plugin_details(plugin):
is_active = plugin.module in active_plugins
settings_links = self.prepare_links(plugin, 'settings_links') if is_active else None
navigation_links = self.prepare_links(plugin, 'navigation_links') if is_active else None
return (plugin, is_active, settings_links, navigation_links)
context['plugins'] = sorted([
(c, labels.get(c, c), plist, any(getattr(p, 'picture', None) for p in plist))
(c, labels.get(c, c), map(plugin_details, plist), any(getattr(p, 'picture', None) for p in plist))
for c, plist
in plugins_grouped
], key=lambda c: (order.index(c[0]), c[1]) if c[0] in order else (999, str(c[1])))
context['plugins_active'] = self.object.get_plugins()
context['show_meta'] = settings.PRETIX_PLUGINS_SHOW_META
return context
@@ -390,13 +417,10 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
return self.render_to_response(context)
def post(self, request, *args, **kwargs):
from pretix.base.plugins import get_all_plugins
self.object = self.get_object()
plugins_available = {
p.module: p for p in get_all_plugins(self.object)
if not p.name.startswith('.') and getattr(p, 'visible', True)
p.module: p for p in self.available_plugins(self.object)
}
with transaction.atomic():
@@ -404,19 +428,38 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
if key.startswith("plugin:"):
module = key.split(":")[1]
if value == "enable" and module in plugins_available:
if getattr(plugins_available[module], 'restricted', False):
pluginmeta = plugins_available[module]
if getattr(pluginmeta, 'restricted', False):
if module not in request.event.settings.allowed_restricted_plugins:
continue
self.request.event.log_action('pretix.event.plugins.enabled', user=self.request.user,
data={'plugin': module})
self.object.enable_plugin(module, allow_restricted=request.event.settings.allowed_restricted_plugins)
links = self.prepare_links(pluginmeta, 'settings_links')
if links:
info = [
'<p>',
format_html(_('The plugin {} is now active, you can configure it here:'),
format_html("<strong>{}</strong>", pluginmeta.name)),
'</p><p>',
] + [
format_html('<a href="{}" class="btn btn-default">{}</a> ', url, text)
for url, text in links
] + ['</p>']
else:
info = [
format_html(_('The plugin {} is now active.'),
format_html("<strong>{}</strong>", pluginmeta.name)),
]
messages.success(self.request, mark_safe("".join(info)))
else:
self.request.event.log_action('pretix.event.plugins.disabled', user=self.request.user,
data={'plugin': module})
self.object.disable_plugin(module)
messages.success(self.request, _('The plugin has been disabled.'))
self.object.save()
messages.success(self.request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
def get_success_url(self) -> str: