New handling of plugin URLs (#609)

This commit is contained in:
Raphael Michel
2017-08-29 10:01:50 +03:00
committed by GitHub
parent 557a05135e
commit 43b5140754
13 changed files with 83 additions and 37 deletions

View File

@@ -1,4 +1,5 @@
from django.apps import AppConfig
from django.urls import RegexURLPattern
class PretixMultidomainConfig(AppConfig):
@@ -7,3 +8,12 @@ class PretixMultidomainConfig(AppConfig):
default_app_config = 'pretix.multidomain.PretixMultidomainConfig'
def event_url(regex, view, kwargs=None, name=None, require_live=True):
if callable(view):
r = RegexURLPattern(regex, view, kwargs, name)
r._require_live = require_live
return r
else:
raise TypeError('view must be a callable.')

View File

@@ -5,6 +5,7 @@ from django.apps import apps
from django.conf.urls import include, url
from django.views.generic import TemplateView
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import (
event_patterns, locale_patterns, organizer_patterns,
)
@@ -27,8 +28,9 @@ for app in apps.get_app_configs():
if hasattr(urlmod, 'urlpatterns'):
single_plugin_patterns += urlmod.urlpatterns
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
single_plugin_patterns.append(url(r'^(?P<organizer>[^/]+)/(?P<event>[^/]+)/',
include(urlmod.event_patterns)))
include(patterns)))
raw_plugin_patterns.append(
url(r'', include((single_plugin_patterns, app.label)))
)

View File

@@ -50,6 +50,7 @@ class MultiDomainMiddleware(MiddlewareMixin):
cache.set('pretix_multidomain_organizer_{}'.format(domain), orga.pk if orga else False, 3600)
if orga:
request.organizer_domain = True
request.organizer = orga if isinstance(orga, Organizer) else Organizer.objects.get(pk=orga)
request.urlconf = "pretix.multidomain.subdomain_urlconf"
else:

View File

@@ -0,0 +1,11 @@
from pretix.presale.utils import _event_view
def plugin_event_urls(urllist, plugin):
for entry in urllist:
if hasattr(entry, 'url_patterns'):
plugin_event_urls(entry.url_patterns, plugin)
elif hasattr(entry, 'callback'):
entry.callback = _event_view(entry.callback, require_plugin=plugin,
require_live=getattr(entry, '_require_live', True))
return urllist

View File

@@ -4,6 +4,7 @@ import warnings
from django.apps import apps
from django.conf.urls import include, url
from pretix.multidomain.plugin_handler import plugin_event_urls
from pretix.presale.urls import (
event_patterns, locale_patterns, organizer_patterns,
)
@@ -22,9 +23,11 @@ for app in apps.get_app_configs():
if importlib.util.find_spec(app.name + '.urls'):
urlmod = importlib.import_module(app.name + '.urls')
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
raw_plugin_patterns.append(
url(r'^(?P<event>[^/]+)/', include((urlmod.event_patterns, app.label)))
url(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
)
elif importlib.util.find_spec(app.name + '.subdomain_urls'): # noqa
warnings.warn('Please put your config in an \'urls\' module using the event_patterns '
'attribute. Support for subdomain_urls in plugins will be dropped in the future.',

View File

@@ -1,12 +1,14 @@
from django.conf.urls import include, url
from .views import abort, event_webbook, refund, success, webhook
from pretix.multidomain import event_url
from .views import abort, refund, success, webhook
event_patterns = [
url(r'^paypal/', include([
url(r'^abort/$', abort, name='abort'),
url(r'^return/$', success, name='return'),
url(r'^webhook/$', event_webbook, name='webhook'),
event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
])),
]

View File

@@ -55,7 +55,6 @@ def success(request, *args, **kwargs):
return redirect(eventreverse(request.event, 'presale:event.checkout', kwargs={'step': 'confirm'}))
@event_view(require_live=False)
def abort(request, *args, **kwargs):
messages.error(request, _('It looks like you canceled the PayPal payment'))
@@ -151,9 +150,6 @@ def webhook(request, *args, **kwargs):
return HttpResponse(status=200)
event_webbook = csrf_exempt(event_view(require_live=False)(webhook))
@event_permission_required('can_view_orders')
@require_POST
def refund(request, **kwargs):

View File

@@ -1,10 +1,12 @@
from django.conf.urls import include, url
from .views import ReturnView, event_webbook, refund, webhook
from pretix.multidomain import event_url
from .views import ReturnView, refund, webhook
event_patterns = [
url(r'^stripe/', include([
url(r'^webhook/$', event_webbook, name='webhook'),
event_url(r'^webhook/$', webhook, name='webhook', require_live=False),
url(r'^return/(?P<order>[^/]+)/(?P<hash>[^/]+)/$', ReturnView.as_view(), name='return'),
])),
]

View File

@@ -8,7 +8,6 @@ from django.db import transaction
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from django.views import View
@@ -22,7 +21,6 @@ from pretix.control.permissions import event_permission_required
from pretix.multidomain.urlreverse import eventreverse
from pretix.plugins.stripe.models import ReferencedStripeObject
from pretix.plugins.stripe.payment import StripeCC
from pretix.presale.utils import event_view
logger = logging.getLogger('pretix.plugins.stripe')
@@ -59,9 +57,6 @@ def webhook(request, *args, **kwargs):
return HttpResponse("Unable to detect event", status=200)
event_webbook = csrf_exempt(event_view(require_live=False)(webhook))
def charge_webhook(event, event_json, charge_id):
prov = StripeCC(event)
prov._init_api()
@@ -198,7 +193,6 @@ class StripeOrderView:
return self.request.event.get_payment_providers()[self.order.payment_provider]
@method_decorator(event_view, name='dispatch')
class ReturnView(StripeOrderView, View):
def get(self, request, *args, **kwargs):
prov = self.pprov

View File

@@ -1,3 +1,4 @@
import warnings
from importlib import import_module
from urllib.parse import urljoin
@@ -16,10 +17,13 @@ from pretix.presale.signals import process_request, process_response
SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
def _detect_event(request, require_live=True):
def _detect_event(request, require_live=True, require_plugin=None):
if hasattr(request, '_event_detected'):
return
url = resolve(request.path_info)
try:
if hasattr(request, 'organizer'):
if hasattr(request, 'organizer_domain'):
# We are on an organizer's custom domain
if 'organizer' in url.kwargs and url.kwargs['organizer']:
if url.kwargs['organizer'] != request.organizer.slug:
@@ -83,6 +87,10 @@ def _detect_event(request, require_live=True):
if not can_access:
raise PermissionDenied(_('The selected ticket shop is currently not available.'))
if require_plugin:
if require_plugin not in request.event.get_plugins():
raise Http404(_('This feature is not enabled.'))
for receiver, response in process_request.send(request.event, request=request):
if response:
return response
@@ -92,11 +100,13 @@ def _detect_event(request, require_live=True):
except Organizer.DoesNotExist:
raise Http404(_('The selected organizer was not found.'))
request._event_detected = True
def event_view(function=None, require_live=True):
def _event_view(function=None, require_live=True, require_plugin=None):
def event_view_wrapper(func, require_live=require_live):
def wrap(request, *args, **kwargs):
ret = _detect_event(request, require_live=require_live)
ret = _detect_event(request, require_live=require_live, require_plugin=require_plugin)
if ret:
return ret
else:
@@ -104,8 +114,24 @@ def event_view(function=None, require_live=True):
for receiver, r in process_response.send(request.event, request=request, response=response):
response = r
return response
for attrname in dir(func):
# Preserve flags like csrf_exempt
if not attrname.startswith('__'):
setattr(wrap, attrname, getattr(func, attrname))
return wrap
if function:
return event_view_wrapper(function, require_live=require_live)
return event_view_wrapper
def event_view(function=None, require_live=True):
warnings.warn('The event_view decorator is deprecated since it will be automatically applied by the URL routing '
'layer when you use event_urls.',
DeprecationWarning)
def noop(fn):
return fn
return function or noop

View File

@@ -16,7 +16,7 @@ def env():
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
organizer=o, name='Dummy', slug='dummy', plugins='pretix.plugins.paypal',
date_from=now(), live=True
)
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)

View File

@@ -16,7 +16,7 @@ def env():
user = User.objects.create_user('dummy@dummy.dummy', 'dummy')
o = Organizer.objects.create(name='Dummy', slug='dummy')
event = Event.objects.create(
organizer=o, name='Dummy', slug='dummy',
organizer=o, name='Dummy', slug='dummy', plugins='pretix.plugins.stripe',
date_from=now(), live=True
)
t = Team.objects.create(organizer=event.organizer, can_view_orders=True, can_change_orders=True)