diff --git a/requirements.txt b/requirements.txt index 4312be0d..bf5f308a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,8 @@ django_recaptcha==3.0.0 Django[argon2]==3.2.17 wagtail==2.16.2 +# Allows subdomains +django-hosts==6.0 # External Libraries requests==2.28.2 diff --git a/src/admin/urls.py b/src/admin/urls.py new file mode 100644 index 00000000..81ec68c7 --- /dev/null +++ b/src/admin/urls.py @@ -0,0 +1,16 @@ +from __future__ import absolute_import, unicode_literals + +from django.conf.urls import include, url + +from wagtail.admin import urls as wagtailadmin_urls + +from moore.urls import urlpatterns as base_urlpatterns + +# Use the same `urlpatterns` as other domains as the base +urlpatterns = base_urlpatterns.copy() + +# Insert `wagtailadmin_urls` at appropriate level +urlpatterns.insert( + len(urlpatterns) - 3, + url(r'', include(wagtailadmin_urls)) +) diff --git a/src/admin/views.py b/src/admin/views.py new file mode 100644 index 00000000..94c6a408 --- /dev/null +++ b/src/admin/views.py @@ -0,0 +1,11 @@ +from django.conf import settings +from django_hosts.resolvers import reverse_host +from django.http import HttpResponseRedirect + + +def redirect_admin(request, path): + protocol = 'https' if request.is_secure() else 'http' + host = reverse_host(host='admin') + if getattr(settings, 'HOST_PORT', None): + host = f"{host}:{settings.HOST_PORT}" + return HttpResponseRedirect(f'{protocol}://{host}/{path}') diff --git a/src/moore/settings/base.py b/src/moore/settings/base.py index b460f1f8..ddc4117a 100644 --- a/src/moore/settings/base.py +++ b/src/moore/settings/base.py @@ -69,6 +69,7 @@ 'captcha', 'jsonschemaform', 'django_select2', # Custom select2 widget + 'django_hosts', # Subdomain for admin site 'django.contrib.admin', # Used for wagtail admin filters 'django.contrib.auth', @@ -79,6 +80,8 @@ ] MIDDLEWARE = [ + # Subdomain for admin site. Needed by django_hosts + 'django_hosts.middleware.HostsRequestMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', @@ -89,6 +92,8 @@ 'django.middleware.locale.LocaleMiddleware', 'wagtail.contrib.redirects.middleware.RedirectMiddleware', + # Subdomain for admin site. Needed by django_hosts + 'django_hosts.middleware.HostsResponseMiddleware', ] DATABASES = { @@ -103,6 +108,10 @@ } ROOT_URLCONF = 'moore.urls' +# Needed for django hosts, enables us to publish wagtail admin on subdomain. +ROOT_HOSTCONF = 'moore.settings.hosts' +DEFAULT_HOST = 'default' + TEMPLATES = [ { diff --git a/src/moore/settings/dev.py b/src/moore/settings/dev.py index d6e2ea99..b25625df 100644 --- a/src/moore/settings/dev.py +++ b/src/moore/settings/dev.py @@ -52,6 +52,9 @@ # trailing slash BASE_URL = 'http://localhost:8000' +ALLOWED_HOSTS = ['admin.localhost', 'localhost'] +PARENT_HOST = 'localhost' +HOST_PORT = '8000' # Email # https://docs.djangoproject.com/en/1.10/ref/settings/#email-backend diff --git a/src/moore/settings/hosts.py b/src/moore/settings/hosts.py new file mode 100644 index 00000000..ff68aa72 --- /dev/null +++ b/src/moore/settings/hosts.py @@ -0,0 +1,8 @@ +from django_hosts import patterns, host +from django.conf import settings + +host_patterns = patterns( + '', + host(r'', settings.ROOT_URLCONF, name='default'), + host(r'admin', 'admin.urls', name='admin'), +) diff --git a/src/moore/settings/production.py b/src/moore/settings/production.py index c8c40ff9..bf5be084 100644 --- a/src/moore/settings/production.py +++ b/src/moore/settings/production.py @@ -40,6 +40,7 @@ BASE_URL = 'https://utn.se' ALLOWED_HOSTS = ['.utn.se', '.utnarm.se'] +PARENT_HOST = 'utn.se' # Email settings DEFAULT_FROM_EMAIL = 'info@utn.se' diff --git a/src/moore/urls.py b/src/moore/urls.py index f901be1f..bab534ba 100644 --- a/src/moore/urls.py +++ b/src/moore/urls.py @@ -2,28 +2,33 @@ from django.conf import settings from django.conf.urls import include, url -from django.urls import path +from django.urls import path, re_path from search import views as search_views -from wagtail.admin import urls as wagtailadmin_urls from wagtail.core import urls as wagtail_urls from wagtail.documents import urls as wagtaildocs_urls +from wagtail.admin import urls as wagtailadmin_urls from .api import api_router +from .urls_utils import delete_urls from members.views import member_check_api +from admin.views import redirect_admin urlpatterns = [ - # Needs to be imported before wagtail urls url(r'^api/', api_router.urls), - # Needs to be imported before wagtail admin url(r'', include('involvement.urls')), url(r'', include('events.urls')), path('member_check_api/', member_check_api, name='member_check_api'), - url(r'^admin/', include(wagtailadmin_urls)), + re_path( + r'^admin/(?P.*)$', + redirect_admin, + name='wagtailadmin_redirect' + ), + url(r'^documents/', include(wagtaildocs_urls)), url(r'^search/$', search_views.search, name='search'), @@ -35,6 +40,10 @@ path('instagram/', include('instagram.urls')), + # We need to include the `wagtailadmin_urls` to support `reverse`. + # Unless running tests, /admin/* will redirect to admin.x/*. + url(r'^admin/', include(wagtailadmin_urls)), + # For anything not caught by a more specific rule above, hand over to # Wagtail's page serving mechanism. This should be the last pattern in # the list: @@ -51,3 +60,11 @@ settings.MEDIA_URL, document_root=settings.MEDIA_ROOT ) + +# We remove the /admin redirect +# if running tests in order to make writing tests easier. +if settings.IS_RUNNING_TEST: + urlpatterns = delete_urls( + urlpatterns, + delete_name='wagtailadmin_redirect' + ) diff --git a/src/moore/urls_utils.py b/src/moore/urls_utils.py new file mode 100644 index 00000000..29ad482a --- /dev/null +++ b/src/moore/urls_utils.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, unicode_literals + + +def delete_urls(urlpatterns: list, delete_name: str): + for index, pattern in enumerate(urlpatterns): + if hasattr(pattern, 'name'): + if pattern.name == delete_name: + # Insert before index + urlpatterns.pop(index) + break + + return urlpatterns