From 719fcae322e1ad1660a9078256abd0450c6145d3 Mon Sep 17 00:00:00 2001 From: Klaas van Schelven Date: Thu, 28 Nov 2024 12:43:14 +0100 Subject: [PATCH] Friendly 400 page that shows the error, even when DEBUG=False when people run into ALLOWED_HOSTS troubles, they should get info on-screen ASAP --- bugsink/context_processors.py | 3 ++- bugsink/urls.py | 1 + bugsink/views.py | 23 +++++++++++++++++++++-- projects/context_processors.py | 14 +++++++------- templates/400.html | 12 ++++++++++++ 5 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 templates/400.html diff --git a/bugsink/context_processors.py b/bugsink/context_processors.py index 8634659..73e19c7 100644 --- a/bugsink/context_processors.py +++ b/bugsink/context_processors.py @@ -83,5 +83,6 @@ def useful_settings_processor(request): def logged_in_user_processor(request): return { - 'logged_in_user': request.user, + # getattr, because if there's a failure "very early" in the request handling, we don't have an AnonymousUser + 'logged_in_user': getattr(request, "user", None), } diff --git a/bugsink/urls.py b/bugsink/urls.py index c2ac375..ba4a32a 100644 --- a/bugsink/urls.py +++ b/bugsink/urls.py @@ -65,4 +65,5 @@ if settings.DEBUG: ] +handler400 = "bugsink.views.bad_request" handler500 = "bugsink.views.server_error" diff --git a/bugsink/views.py b/bugsink/views.py index 6768113..4699ca6 100644 --- a/bugsink/views.py +++ b/bugsink/views.py @@ -1,9 +1,9 @@ import sys -from django.http import HttpResponseServerError +from django.http import HttpResponseServerError, HttpResponseBadRequest from django.template import TemplateDoesNotExist, loader from django.views.decorators.csrf import requires_csrf_token -from django.views.defaults import ERROR_500_TEMPLATE_NAME, ERROR_PAGE_TEMPLATE +from django.views.defaults import ERROR_500_TEMPLATE_NAME, ERROR_PAGE_TEMPLATE, ERROR_400_TEMPLATE_NAME from django.shortcuts import redirect from django.conf import settings @@ -116,6 +116,25 @@ def settings_view(request): }) +@requires_csrf_token +def bad_request(request, exception, template_name=ERROR_400_TEMPLATE_NAME): + # verbatim copy of Django's default bad_request view, but with "exception" in the context + # doing this for any-old-Django-site is probably a bad idea, but here the security/convenience tradeoff is fine, + # especially because we only show str(exception) in the template. + try: + template = loader.get_template(template_name) + except TemplateDoesNotExist: + if template_name != ERROR_400_TEMPLATE_NAME: + # Reraise if it's a missing custom template. + raise + return HttpResponseBadRequest( + ERROR_PAGE_TEMPLATE % {"title": "Bad Request (400)", "details": ""}, + ) + + _, exception, _ = sys.exc_info() + return HttpResponseBadRequest(template.render({"exception": exception}, request)) + + @requires_csrf_token def server_error(request, template_name=ERROR_500_TEMPLATE_NAME): # verbatim copy of Django's default server_error view, but with "exception" in the context diff --git a/projects/context_processors.py b/projects/context_processors.py index 204ff41..42b012a 100644 --- a/projects/context_processors.py +++ b/projects/context_processors.py @@ -1,9 +1,9 @@ def user_projects_processor(request): - if not request.user.is_authenticated: - return { - 'user_projects': [], - } + if not hasattr(request, "user"): + # check, because if there's a failure "very early" in the request handling, we don't have an AnonymousUser + return {"user_projects": []} - return { - 'user_projects': request.user.project_set.all(), - } + if not request.user.is_authenticated: + return {'user_projects': []} + + return {'user_projects': request.user.project_set.all()} diff --git a/templates/400.html b/templates/400.html new file mode 100644 index 0000000..9e14fe6 --- /dev/null +++ b/templates/400.html @@ -0,0 +1,12 @@ +{% extends "bare_base.html" %} + +{% block title %}400 Server Error{% endblock %} + +{% block content %} +
+

400 Server Error

+ +
+ {{ exception }} +
+{% endblock %}