middleware.py 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. from urllib import parse
  2. from django.conf import settings
  3. from django.db import ProgrammingError
  4. from django.http import Http404, HttpResponseRedirect
  5. from django.urls import reverse
  6. from .views import server_error
  7. BASE_PATH = getattr(settings, 'BASE_PATH', False)
  8. LOGIN_REQUIRED = getattr(settings, 'LOGIN_REQUIRED', False)
  9. class LoginRequiredMiddleware(object):
  10. """
  11. If LOGIN_REQUIRED is True, redirect all non-authenticated users to the login page.
  12. """
  13. def __init__(self, get_response):
  14. self.get_response = get_response
  15. def __call__(self, request):
  16. if LOGIN_REQUIRED and not request.user.is_authenticated:
  17. # Redirect unauthenticated requests to the login page. API requests are exempt from redirection as the API
  18. # performs its own authentication. Also metrics can be read without login.
  19. api_path = reverse('api-root')
  20. if not request.path_info.startswith((api_path, '/metrics')) and request.path_info != settings.LOGIN_URL:
  21. return HttpResponseRedirect(
  22. '{}?next={}'.format(
  23. settings.LOGIN_URL,
  24. parse.quote(request.get_full_path_info())
  25. )
  26. )
  27. return self.get_response(request)
  28. class APIVersionMiddleware(object):
  29. """
  30. If the request is for an API endpoint, include the API version as a response header.
  31. """
  32. def __init__(self, get_response):
  33. self.get_response = get_response
  34. def __call__(self, request):
  35. api_path = reverse('api-root')
  36. response = self.get_response(request)
  37. if request.path_info.startswith(api_path):
  38. response['API-Version'] = settings.REST_FRAMEWORK_VERSION
  39. return response
  40. class ExceptionHandlingMiddleware(object):
  41. """
  42. Intercept certain exceptions which are likely indicative of installation issues and provide helpful instructions
  43. to the user.
  44. """
  45. def __init__(self, get_response):
  46. self.get_response = get_response
  47. def __call__(self, request):
  48. return self.get_response(request)
  49. def process_exception(self, request, exception):
  50. # Don't catch exceptions when in debug mode
  51. if settings.DEBUG:
  52. return
  53. # Ignore Http404s (defer to Django's built-in 404 handling)
  54. if isinstance(exception, Http404):
  55. return
  56. # Determine the type of exception. If it's a common issue, return a custom error page with instructions.
  57. custom_template = None
  58. if isinstance(exception, ProgrammingError):
  59. custom_template = 'exceptions/programming_error.html'
  60. elif isinstance(exception, ImportError):
  61. custom_template = 'exceptions/import_error.html'
  62. elif isinstance(exception, PermissionError):
  63. custom_template = 'exceptions/permission_error.html'
  64. # Return a custom error message, or fall back to Django's default 500 error handling
  65. if custom_template:
  66. return server_error(request, template_name=custom_template)