Source code for cobalt.middleware

"""This middleware checks for the presence of an environment variable that puts the
site into maintenance mode. In maintenance mode normal users are shown a maintenance
screen, but admin users can still login and use the system as normal.

This must be added to the middleware variable in settings and must come after
"django.contrib.auth.middleware.AuthenticationMiddleware" as it needs access to
the authenticated user.
"""

from django.core.exceptions import MiddlewareNotUsed

import sys
import traceback as traceback_lib

from django.http import RawPostDataException, Http404, HttpResponseServerError
from django.shortcuts import render
from django.template.loader import render_to_string

from cobalt import settings
from utils.models import Error500


[docs] class MaintenanceModeMiddleware: def __init__(self, get_response): """This is called when the webserver starts. If we are not in maintenance mode then we can disable ourselves""" if settings.MAINTENANCE_MODE != "ON": raise MiddlewareNotUsed print( "\n\n*** Maintenance mode is on. Disable by changing environment variable MAINTENANCE_MODE ***" ) print("*** Only superusers can access the system in maintenance mode. ***\n\n") # Maintenance mode is on - store get_response self.get_response = get_response def __call__(self, request): """This is called for every request if we are in maintenance mode""" response = self.get_response(request) # Allow superusers plus access to the login page and ses webhook (or it sends a million error emails) if request.user.is_superuser or request.META["PATH_INFO"] in [ "/accounts/login/", "/notifications/ses/event-webhook/", ]: return response else: return render(request, "errors/503.html", status=503)
[docs] class CobaltLog500ErrorsMiddleware: """Middleware to record 500 errors on non-production environments""" def __init__(self, get_response): self.get_response = get_response def __call__(self, request): return self.get_response(request)
[docs] def process_exception(self, request, exception): # Get the traceback info error_type, error_value, traceback = sys.exc_info() # Skip if not a 500 error # if type(error_type) is not HttpResponseServerError: # return # Get further details of the traceback traceback_list = traceback_lib.format_exception( error_type, error_value, traceback ) try: headline_1 = traceback_list[-2] except IndexError: headline_1 = "Not available" try: headline_2 = traceback_list[-1] except IndexError: headline_2 = "Not available" # Try to get the details try: details = f"BODY: {request.body}" except RawPostDataException: details = "BODY: UNAVAILABLE" context = { "user": request.user, "error_type": f"{error_type}", "value_str": error_value, "traceback": traceback, "traceback_list": traceback_list, "request_post": request.POST, "request_get": request.GET, "request_path": request.path, "details": details, "headline_1": headline_1, "headline_2": headline_2, } # Turn into HTML email_body = render_to_string("errors/server_error_500.html", context) Error500( user=f"{request.user}"[:100], error=email_body, summary=error_value.__str__()[:200], ).save()