From 38829a3cfac168f36c21a7c166e0d6a6c0d8ae4a Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Sat, 28 Dec 2024 13:19:05 -0800 Subject: [PATCH] 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 Reviewed-by: Veiko Aasa --- plinth/middleware.py | 15 +++++++++++++++ plinth/tests/test_middleware.py | 13 ++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/plinth/middleware.py b/plinth/middleware.py index a22533016..a88963a68 100644 --- a/plinth/middleware.py +++ b/plinth/middleware.py @@ -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.""" diff --git a/plinth/tests/test_middleware.py b/plinth/tests/test_middleware.py index 0b489a22f..b025996cd 100644 --- a/plinth/tests/test_middleware.py +++ b/plinth/tests/test_middleware.py @@ -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()