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, encoding='utf-8') as t: template = Template(t.read()) context = RequestContext(request, kwargs) return HttpResponse(template.render(context))