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()