diff --git a/doc/development/api/plugins.rst b/doc/development/api/plugins.rst index 5b66470b73..256ceff5dd 100644 --- a/doc/development/api/plugins.rst +++ b/doc/development/api/plugins.rst @@ -74,6 +74,13 @@ A working example would be:: default_app_config = 'pretix.plugins.timerestriction.TimeRestrictionApp' +The ``AppConfig`` class may implement a property ``compatiblity_errors``, that checks +whether the pretix installation meets all requirements of the plugin. If so, +it should contian ``None`` or an empty list, otherwise a list of strings containing +human-readable error messages. We recommend using the ``django.utils.functional.cached_property`` +decorator, as it might get called a lot. You can also implement ``compatibility_warnings``, +those will be displayed but not block the plugin execution. + Signals ------- diff --git a/src/pretix/base/plugins.py b/src/pretix/base/plugins.py index bbf760624b..e62909abb1 100644 --- a/src/pretix/base/plugins.py +++ b/src/pretix/base/plugins.py @@ -20,5 +20,6 @@ def get_all_plugins() -> "List[class]": if hasattr(app, 'PretixPluginMeta'): meta = app.PretixPluginMeta meta.module = app.name + meta.app = app plugins.append(meta) return plugins diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py index 800d064414..28e650a081 100644 --- a/src/pretix/base/signals.py +++ b/src/pretix/base/signals.py @@ -39,8 +39,9 @@ class EventPluginSignal(django.dispatch.Signal): # Only fire receivers from active plugins if app.name in sender.get_plugins(): - response = receiver(signal=self, sender=sender, **named) - responses.append((receiver, response)) + if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors: + response = receiver(signal=self, sender=sender, **named) + responses.append((receiver, response)) return responses """ diff --git a/src/pretix/control/static/pretixcontrol/less/forms.less b/src/pretix/control/static/pretixcontrol/less/forms.less index ac55223475..1fca2e1633 100644 --- a/src/pretix/control/static/pretixcontrol/less/forms.less +++ b/src/pretix/control/static/pretixcontrol/less/forms.less @@ -14,6 +14,9 @@ td > .form-group > .checkbox { .has-success .form-control { border-color: #cccccc; } +.panel-body div.alert:last-child { + margin-bottom: 0; +} .form-horizontal [data-formset] .form-group { width: 100%; } diff --git a/src/pretix/control/templates/pretixcontrol/event/plugins.html b/src/pretix/control/templates/pretixcontrol/event/plugins.html index 97b54e5612..cb82f68439 100644 --- a/src/pretix/control/templates/pretixcontrol/event/plugins.html +++ b/src/pretix/control/templates/pretixcontrol/event/plugins.html @@ -12,18 +12,19 @@ {% endif %} {% for plugin in plugins %} -
+

{{ plugin.name }}

- {% if plugin.module in plugins_active %} + {% if plugin.app.compatibility_errors %} + + {% elif plugin.module in plugins_active %} {% else %} - {% endif %}
@@ -33,6 +34,26 @@ Version {{ v }} by {{ a }} {% endblocktrans %}

{{ plugin.description }}

+ {% if plugin.app.compatibility_errors %} +
+ {% trans "This plugin cannot be enabled for the following reasons:" %} +
    + {% for e in plugin.app.compatibility_errors %} +
  • {{ e }}
  • + {% endfor %} +
+
+ {% endif %} + {% if plugin.app.compatibility_warnings %} +
+ {% trans "This plugin reports the following problems:" %} +
    + {% for e in plugin.app.compatibility_warnings %} +
  • {{ e }}
  • + {% endfor %} +
+
+ {% endif %}
{% endfor %} diff --git a/src/pretix/plugins/banktransfer/__init__.py b/src/pretix/plugins/banktransfer/__init__.py index a6ce5d9723..0a08759210 100644 --- a/src/pretix/plugins/banktransfer/__init__.py +++ b/src/pretix/plugins/banktransfer/__init__.py @@ -1,4 +1,5 @@ from django.apps import AppConfig +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from pretix.base.plugins import PluginType @@ -18,5 +19,14 @@ class BankTransferApp(AppConfig): def ready(self): from . import signals # NOQA + @cached_property + def compatibility_warnings(self): + errs = [] + try: + import chardet + except ImportError: + errs.append(_("Install the python package 'chardet' for better CSV import capabilities.")) + return errs + default_app_config = 'pretix.plugins.banktransfer.BankTransferApp' diff --git a/src/pretix/plugins/paypal/__init__.py b/src/pretix/plugins/paypal/__init__.py index ee5b78be2b..5f79d58bba 100644 --- a/src/pretix/plugins/paypal/__init__.py +++ b/src/pretix/plugins/paypal/__init__.py @@ -1,4 +1,5 @@ from django.apps import AppConfig +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from pretix.base.plugins import PluginType @@ -17,5 +18,13 @@ class PaypalApp(AppConfig): def ready(self): from . import signals # NOQA + @cached_property + def compatibility_errors(self): + errs = [] + try: + import paypalrestsdk + except ImportError: + errs.append("Python package 'paypalrestsdk' is not installed.") + return errs default_app_config = 'pretix.plugins.paypal.PaypalApp' diff --git a/src/pretix/plugins/paypal/signals.py b/src/pretix/plugins/paypal/signals.py index 28c49f2267..09b4924adc 100644 --- a/src/pretix/plugins/paypal/signals.py +++ b/src/pretix/plugins/paypal/signals.py @@ -2,9 +2,8 @@ from django.dispatch import receiver from pretix.base.signals import register_payment_providers -from .payment import Paypal - @receiver(register_payment_providers) def register_payment_provider(sender, **kwargs): + from .payment import Paypal return Paypal diff --git a/src/pretix/plugins/stripe/__init__.py b/src/pretix/plugins/stripe/__init__.py index 566aed5228..3240de1473 100644 --- a/src/pretix/plugins/stripe/__init__.py +++ b/src/pretix/plugins/stripe/__init__.py @@ -1,4 +1,5 @@ from django.apps import AppConfig +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from pretix.base.plugins import PluginType @@ -18,5 +19,14 @@ class StripeApp(AppConfig): def ready(self): from . import signals # NOQA + @cached_property + def compatibility_errors(self): + errs = [] + try: + import stripe + except ImportError: + errs.append("Python package 'stripe' is not installed.") + return errs + default_app_config = 'pretix.plugins.stripe.StripeApp' diff --git a/src/pretix/plugins/stripe/signals.py b/src/pretix/plugins/stripe/signals.py index 0fcbd20556..442398f132 100644 --- a/src/pretix/plugins/stripe/signals.py +++ b/src/pretix/plugins/stripe/signals.py @@ -5,17 +5,18 @@ from django.template.loader import get_template from pretix.base.signals import register_payment_providers -from .payment import Stripe from pretix.presale.signals import html_head @receiver(register_payment_providers) def register_payment_provider(sender, **kwargs): + from .payment import Stripe return Stripe @receiver(html_head) def html_head_presale(sender, request=None, **kwargs): + from .payment import Stripe provider = Stripe(sender) url = resolve(request.path_info) if provider.is_enabled and "checkout.payment" in url.url_name: