diff --git a/TODO.md b/TODO.md index e965271d8f46e639bc728e56e9c03d3c1a0a9141..c551d272af1251f19587236bf0d31ebbd1147be1 100644 --- a/TODO.md +++ b/TODO.md @@ -1,15 +1,19 @@ # To-do +* split the template/content files out from `conservancy/static` into their own + `content` directory (avoid mixing static and non-static content) * ask Denver about why so many license files * serve a 400 in Apache for a hostname we don't explicitly support -* use `` elements for supporter page hidden sections, rather than complex jQuery - or consider Alpine.js +* use `` elements for supporter page hidden sections, rather than + complex jQuery - or consider Alpine.js * replace `internalNavigate` with inline flexbox layout * add tests for main pages returning 200 # Done -* remove `ForceCanonicalHostnameMiddleware` by ensuring canonical redirect and HTTPS redirect is done by Apache +* remove `ForceCanonicalHostnameMiddleware` by ensuring canonical redirect and + HTTPS redirect is done by Apache * standardise settings to replace `settings.py` and `djangocommonsettings.py` with `settings/prod.py` and move `SECRET_KEY` to an environment variable * migrate to Django 4.2 LTS diff --git a/conservancy/urls.py b/conservancy/urls.py index 4cfb37c91fc96b7c2a9be35f58c1f986d9ea575e..5ef492b871e6c4747f3decfc40c2690421f92c6f 100644 --- a/conservancy/urls.py +++ b/conservancy/urls.py @@ -45,7 +45,7 @@ urlpatterns = [ re_path(r'^learn/', static_views.index), re_path(r'^press/', static_views.index), re_path(r'^projects/', static_views.index), - re_path(r'^GiveUpGitHub', static_views.index), + re_path(r'^GiveUpGitHub/', static_views.index), re_path(r'^npoacct/', static_views.index, {'fundraiser_sought': 'npoacct'}), path('contractpatch/', include('conservancy.contractpatch.urls')), re_path(r'^overview/', static_views.index), diff --git a/conservancy/views.py b/conservancy/views.py index fe4de08d2d9a3e7fd37590cc7f7ce18778192b1c..21059710f9d131c2ca22a827bf4026c079f418a5 100644 --- a/conservancy/views.py +++ b/conservancy/views.py @@ -1,8 +1,7 @@ import mimetypes from django.conf import settings -from django.http import Http404 -from django.http import FileResponse +from django.http import FileResponse, Http404, HttpResponseRedirect from django.template.response import TemplateResponse from .local_context_processors import fundgoal_lookup @@ -35,7 +34,10 @@ def index(request, *args, **kwargs): path += 'index.html' full_path = (base_path / path).resolve() safe_from_path_traversal = full_path.is_relative_to(base_path) - if not full_path.exists() or not safe_from_path_traversal: + if full_path.is_dir(): + # Should have been accessed with a trailing slash. + return HttpResponseRedirect(request.path + '/') + elif not full_path.exists() or not safe_from_path_traversal: raise Http404() is_template = mimetypes.guess_type(full_path)[0] == 'text/html' if not is_template: