Files @ 1cfe805689a2
Branch filter:

Location: website/conservancy/views.py

bsturmfels
Handle trailing slashes in static content
import mimetypes

from django.conf import settings
from django.http import FileResponse, Http404, HttpResponseRedirect
from django.template.response import TemplateResponse

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.
    """
    # The name "static" has no connection to Django staticfiles.
    base_path = settings.BASE_DIR / 'static'
    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:
        context = kwargs.copy()
        try:
            context['fundgoal'] = fundgoal_lookup(kwargs['fundraiser_sought'])
        except KeyError:
            pass
        # Maybe this should open() the template file directly so that these
        # don't have to be included in the global template TEMPLATES.DIRS?
        return TemplateResponse(request, path, context)