middleware: Handle method not allowed errors and redirect

- These could happen when a user tries to reload a page that only allows POST
requests.

- Or when the generic exception handling logic in the middleware redirects the
user to a page that only allows POST.

Tests:

- Insert a exception in the diagnose() of the 'users' app. Without the patch,
running diagnostics on the users app leads to a blank page. With the patch, the
user is redirected to Diagnostics app page and the original error is shown as a
alert message.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: Veiko Aasa <veiko17@disroot.org>
This commit is contained in:
Sunil Mohan Adapa 2024-12-28 13:19:05 -08:00 committed by Veiko Aasa
parent 407fccba2f
commit 38829a3cfa
No known key found for this signature in database
GPG Key ID: 478539CAE680674E
2 changed files with 27 additions and 1 deletions

View File

@ -11,6 +11,7 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.db.utils import OperationalError
from django.http import HttpResponseNotAllowed
from django.shortcuts import redirect, render
from django.template.response import SimpleTemplateResponse
from django.utils.deprecation import MiddlewareMixin
@ -154,6 +155,20 @@ class CommonErrorMiddleware(MiddlewareMixin):
return None
@staticmethod
def process_response(request, response):
"""Handle 405 method not allowed errors.
These errors may happen when we redirect to a page that does not allow
GET.
"""
if isinstance(response, HttpResponseNotAllowed):
redirect_url = CommonErrorMiddleware._get_redirect_url_on_error(
request)
return redirect(redirect_url)
return response
@staticmethod
def _get_redirect_url_on_error(request):
"""Return the URL to redirect to after an error."""

View File

@ -9,7 +9,8 @@ import pytest
from django.contrib.auth.models import AnonymousUser, Group, User
from django.core.exceptions import PermissionDenied
from django.db.utils import OperationalError
from django.http import HttpResponse, HttpResponseRedirect
from django.http import (HttpResponse, HttpResponseNotAllowed,
HttpResponseRedirect)
from django.test.client import RequestFactory
from django.urls import resolve
from stronghold.decorators import public
@ -327,3 +328,13 @@ class TestCommonErrorMiddleware:
response = middleware.process_exception(web_request, other_error)
assert not response
messages_error.assert_not_called()
@staticmethod
@patch('django.contrib.messages.error')
def test_405_error(messages_error, middleware, web_request, test_menu):
"""Test that method not allowed errors are handled."""
response = middleware.process_response(
web_request, HttpResponseNotAllowed(['POST']))
assert isinstance(response, HttpResponseRedirect)
assert response.url == '/apps/'
messages_error.assert_not_called()