website/conservancy/views.py
Ben Sturmfels fe64a26a72
Move the content templates/files into conservancy/content
These were previously intermingled with the static content in `conservancy/static`.
2024-03-22 09:34:20 +11:00

54 lines
2.6 KiB
Python

import mimetypes
from django.conf import settings
from django.http import FileResponse, Http404, HttpResponse, HttpResponseRedirect
from django.template import RequestContext, Template
from .local_context_processors import fundgoal_lookup
def index(request, *args, **kwargs):
"""Faux CMS: bulk website content stored in templates and document files.
Rationale: Many websites have a CMS and store the majority of their website
content in a relational database eg. WordPress or Wagtail. That's useful
because various people can easily be given access to edit the website. The
downside is that is application complexity - the management of who change
what, when it changed and what changed becomes an application concern. At
the other end of the spectrum, we have files that are checked into a Git
repository - we get the precise who/what/when out of the box with Git, but
require you to have some technical knowledge and appropriate access to
commit. Since you're committing to a code repository, this also opens up the
possibility to break things you couldn't break via a CMS.
This view serves most of the textual pages and documents on
sfconservancy.org. It works a little like Apache serving mixed PHP/static
files - it looks at the URL and tries to find a matching file on the
filesystem. If it finds a template, it renders it via Django's template
infrastructure. If it finds a file but it's not a template, it will serve
the file as-is.
"""
base_path = settings.BASE_DIR / 'content'
path = request.path.lstrip('/')
if path.endswith('/'):
path += 'index.html'
full_path = (base_path / path).resolve()
safe_from_path_traversal = full_path.is_relative_to(base_path)
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:
return FileResponse(open(full_path, 'rb'))
else:
try:
kwargs['fundgoal'] = fundgoal_lookup(kwargs['fundraiser_sought'])
except KeyError:
pass
# These template are intentionally not in the template loader path, so
# we open them directly, rather than using the template loader.
with open(full_path) as t:
template = Template(t.read())
context = RequestContext(request, kwargs)
return HttpResponse(template.render(context))