From 0b4cae07c456b00b0d5e6f94dff2e1c665d2ce72 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 21 Oct 2015 18:16:17 +0200 Subject: [PATCH] Splitted URL configuration for main and subdomains --- src/pretix/base/middleware.py | 3 +- src/pretix/multidomain/maindomain_urlconf.py | 13 ++++++++ src/pretix/multidomain/middlewares.py | 16 +++++++-- src/pretix/multidomain/subdomain_urlconf.py | 14 ++++++++ src/pretix/multidomain/urlreverse.py | 7 ++-- src/pretix/presale/urls.py | 9 +++--- src/pretix/urls.py | 34 +++++++++++--------- src/tests/multidomain/test_middlewares.py | 6 ++-- 8 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 src/pretix/multidomain/maindomain_urlconf.py create mode 100644 src/pretix/multidomain/subdomain_urlconf.py diff --git a/src/pretix/base/middleware.py b/src/pretix/base/middleware.py index 14c6c4fe96..55b2756d01 100644 --- a/src/pretix/base/middleware.py +++ b/src/pretix/base/middleware.py @@ -3,7 +3,6 @@ from collections import OrderedDict import pytz from django.conf import settings from django.core.urlresolvers import get_script_prefix -from django.middleware.locale import LocaleMiddleware as BaseLocaleMiddleware from django.utils import timezone, translation from django.utils.cache import patch_vary_headers from django.utils.translation import LANGUAGE_SESSION_KEY @@ -15,7 +14,7 @@ from django.utils.translation.trans_real import ( _supported = None -class LocaleMiddleware(BaseLocaleMiddleware): +class LocaleMiddleware: """ This middleware sets the correct locale and timezone diff --git a/src/pretix/multidomain/maindomain_urlconf.py b/src/pretix/multidomain/maindomain_urlconf.py new file mode 100644 index 0000000000..0a25a49b68 --- /dev/null +++ b/src/pretix/multidomain/maindomain_urlconf.py @@ -0,0 +1,13 @@ +from django.conf.urls import include, url + +from pretix.presale.urls import event_patterns, locale_patterns +from pretix.urls import common_patterns + +presale_patterns_main = [ + url(r'', include(locale_patterns + [ + url(r'^(?P[^/]+)/(?P[^/]+)/', include(event_patterns)) + ], namespace='presale')) +] + +# The presale namespace comes last, because it contains a wildcard catch +urlpatterns = common_patterns + presale_patterns_main diff --git a/src/pretix/multidomain/middlewares.py b/src/pretix/multidomain/middlewares.py index 362fa89228..7d34b99bc5 100644 --- a/src/pretix/multidomain/middlewares.py +++ b/src/pretix/multidomain/middlewares.py @@ -5,6 +5,7 @@ from django.conf import settings from django.contrib.sessions.middleware import \ SessionMiddleware as BaseSessionMiddleware from django.core.exceptions import DisallowedHost +from django.core.urlresolvers import set_urlconf from django.http.request import split_domain_port from django.middleware.csrf import CsrfViewMiddleware as BaseCsrfMiddleware from django.utils.cache import patch_vary_headers @@ -37,13 +38,24 @@ class MultiDomainMiddleware: request.domain = kd except: if settings.DEBUG or domain in ('testserver', 'localhost') or domain == default_domain: - return # TODO: Select main page - raise DisallowedHost("Unknown host: %r" % host) + request.urlconf = "pretix.multidomain.maindomain_urlconf" + else: + raise DisallowedHost("Unknown host: %r" % host) else: request.organizer = kd.organizer + request.urlconf = "pretix.multidomain.subdomain_urlconf" else: raise DisallowedHost("Invalid HTTP_HOST header: %r." % host) + # We need to manually set the urlconf for the whole thread. Normally, Django's basic request + # would do this for us, but we already need it in place for the other middlewares. + set_urlconf(request.urlconf) + + def process_response(self, request, response): + if getattr(request, "urlconf", None): + patch_vary_headers(response, ('Host',)) + return response + class SessionMiddleware(BaseSessionMiddleware): def process_response(self, request, response): diff --git a/src/pretix/multidomain/subdomain_urlconf.py b/src/pretix/multidomain/subdomain_urlconf.py new file mode 100644 index 0000000000..cda000ef88 --- /dev/null +++ b/src/pretix/multidomain/subdomain_urlconf.py @@ -0,0 +1,14 @@ +from django.conf.urls import include, url + +from pretix.presale.urls import event_patterns, locale_patterns +from pretix.urls import common_patterns + +print(event_patterns) +presale_patterns = [ + url(r'', include(locale_patterns + [ + url(r'^(?P[^/]+)/', include(event_patterns)) + ], namespace='presale')) +] + +# The presale namespace comes last, because it contains a wildcard catch +urlpatterns = common_patterns + presale_patterns diff --git a/src/pretix/multidomain/urlreverse.py b/src/pretix/multidomain/urlreverse.py index 208326a2bd..bab622f67e 100644 --- a/src/pretix/multidomain/urlreverse.py +++ b/src/pretix/multidomain/urlreverse.py @@ -21,20 +21,23 @@ def eventreverse(event, name, kwargs=None): Works similar to django.core.urlresolvers.reverse but takes into account that some organizers might have their own (sub)domain instead of a subpath. """ + from pretix.multidomain import subdomain_urlconf, maindomain_urlconf + kwargs = kwargs or {} kwargs['event'] = event.slug domain = get_domain(event) if domain: if 'organizer' in kwargs: del kwargs['organizer'] - path = reverse(name, kwargs=kwargs) + + path = reverse(name, kwargs=kwargs, urlconf=subdomain_urlconf) siteurlsplit = urlsplit(settings.SITE_URL) if siteurlsplit.port and siteurlsplit.port not in (80, 443): domain = '%s:%d' % (domain, siteurlsplit.port) return urljoin('%s://%s' % (siteurlsplit.scheme, domain), path) kwargs['organizer'] = event.organizer.slug - return reverse(name, kwargs=kwargs) + return reverse(name, kwargs=kwargs, urlconf=maindomain_urlconf) def build_absolute_uri(event, urlname, kwargs=None): diff --git a/src/pretix/presale/urls.py b/src/pretix/presale/urls.py index edafbabf69..4bf5d0519d 100644 --- a/src/pretix/presale/urls.py +++ b/src/pretix/presale/urls.py @@ -6,7 +6,10 @@ import pretix.presale.views.event import pretix.presale.views.locale import pretix.presale.views.order -eventurls = [ +# This is not a valid Django URL configuration, as the final +# configuration is done by the pretix.multidomain package. + +event_patterns = [ url(r'^cart/add$', pretix.presale.views.cart.CartAdd.as_view(), name='event.cart.add'), url(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'), url(r'^checkout/start$', pretix.presale.views.checkout.CheckoutView.as_view(), name='event.checkout.start'), @@ -34,8 +37,6 @@ eventurls = [ url(r'^$', pretix.presale.views.event.EventIndex.as_view(), name='event.index'), ] -urlpatterns = [ +locale_patterns = [ url(r'^locale/set$', pretix.presale.views.locale.LocaleSet.as_view(), name='locale.set'), - url(r'^(?P[^/]+)/', include(eventurls)), - url(r'^(?P[^/]+)/(?P[^/]+)/', include(eventurls)), ] diff --git a/src/pretix/urls.py b/src/pretix/urls.py index 19fc87aeab..3882d0fe09 100644 --- a/src/pretix/urls.py +++ b/src/pretix/urls.py @@ -9,33 +9,35 @@ import pretix.base.views.cachedfiles import pretix.control.urls import pretix.presale.urls -urlpatterns = [ +# This is not a valid Django URL configuration, as the final +# configuration is done by the pretix.multidomain package. + +base_patterns = [ url(r'^download/(?P[^/]+)/$', pretix.base.views.cachedfiles.DownloadView.as_view(), - name='cachedfile.download'), - url(r'^control/', include(pretix.control.urls, namespace='control')), - # The pretixpresale namespace is configured at the bottom of this file, because it - # contains a wildcard-style URL which has to be configured _after_ debug settings. + name='cachedfile.download') ] +control_patterns = [ + url(r'^control/', include(pretix.control.urls, namespace='control')), +] + +debug_patterns = [] if settings.DEBUG: import debug_toolbar - urlpatterns.append( - url(r'^__debug__/', include(debug_toolbar.urls)), - ) -pluginpatterns = [] + debug_patterns.append(url(r'^__debug__/', include(debug_toolbar.urls))) + +raw_plugin_patterns = [] for app in apps.get_app_configs(): if hasattr(app, 'PretixPluginMeta'): if importlib.util.find_spec(app.name + '.urls'): urlmod = importlib.import_module(app.name + '.urls') - pluginpatterns.append( + raw_plugin_patterns.append( url(r'', include(urlmod, namespace=app.label)) ) -urlpatterns.append( - url(r'', include(pluginpatterns, namespace='plugins')) -) +plugin_patterns = [ + url(r'', include(raw_plugin_patterns, namespace='plugins')) +] -urlpatterns.append( - url(r'', include(pretix.presale.urls, namespace='presale')) -) +common_patterns = base_patterns + control_patterns + debug_patterns + plugin_patterns diff --git a/src/tests/multidomain/test_middlewares.py b/src/tests/multidomain/test_middlewares.py index 1c2d931c87..0d56f5fef9 100644 --- a/src/tests/multidomain/test_middlewares.py +++ b/src/tests/multidomain/test_middlewares.py @@ -1,6 +1,6 @@ import pytest from django.conf import settings -from django.template import Context, Template +from django.http import Http404 from django.utils.timezone import now from pretix.base.models import Event, Organizer @@ -55,8 +55,8 @@ def test_event_on_custom_domain_only_with_wrong_organizer(env, client): date_from=now() ) KnownDomain.objects.create(domainname='foobar', organizer=env[0]) - r = client.get('/dummy/1234/', HTTP_HOST='foobar') - assert r.status_code == 404 + with pytest.raises(Http404): + client.get('/dummy/1234/', HTTP_HOST='foobar') @pytest.mark.django_db