Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 43 additions & 21 deletions integreat_cms/cms/views/error_handler/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@
from typing import TYPE_CHECKING

from django.conf import settings
from django.http import (
HttpResponseBadRequest,
HttpResponseForbidden,
HttpResponseNotFound,
HttpResponseServerError,
)
from django.http import HttpResponse, JsonResponse
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _

Expand All @@ -23,6 +18,19 @@
logger = logging.getLogger(__name__)


def is_api_request(request: HttpRequest) -> bool:
"""
Check whether the given request is directed at the API

:param request: Object representing the user call
:return: Whether the request belongs to the API namespace
"""
if request.resolver_match:
return request.resolver_match.app_name == "api"
# If the url could not be resolved at all, fall back to the url prefix of the API
return request.path.startswith("/api/")


def render_error_template(context: dict[str, Any]) -> SafeString:
"""
Render the HTTP error template
Expand All @@ -41,13 +49,27 @@ def render_error_template(context: dict[str, Any]) -> SafeString:
return render_to_string("error_handler/http_error.html", context)


def handler400(request: HttpRequest, exception: BadRequest) -> HttpResponseBadRequest:
def render_error_response(context: dict[str, Any]) -> HttpResponse:
"""
Render the HTTP error response

Requests to the API always return JSON, all other requests return the rendered HTML error template.

:param context: The context data for the error
:return: The error response
"""
if is_api_request(context["request"]):
return JsonResponse({"error": context["message"]}, status=context["code"])
return HttpResponse(render_error_template(context), status=context["code"])


def handler400(request: HttpRequest, exception: BadRequest) -> HttpResponse:
"""
Render a HTTP 400 Error code

:param request: Object representing the user call
:param exception: Exception (unused)
:return: The rendered template response
:return: The error response
"""
context = {
"request": request,
Expand All @@ -56,19 +78,19 @@ def handler400(request: HttpRequest, exception: BadRequest) -> HttpResponseBadRe
"message": _("There was an error in your request."),
}
logger.debug(exception)
return HttpResponseBadRequest(render_error_template(context))
return render_error_response(context)


def handler403(
request: HttpRequest,
exception: PermissionDenied,
) -> HttpResponseForbidden:
) -> HttpResponse:
"""
Render a HTTP 403 Error code

:param request: Object representing the user call
:param exception: Exception (unused)
:return: The rendered template response
:return: The error response
"""
context = {
"request": request,
Expand All @@ -77,16 +99,16 @@ def handler403(
"message": _("You don't have the permission to access this page."),
}
logger.debug(exception)
return HttpResponseForbidden(render_error_template(context))
return render_error_response(context)


def handler404(request: HttpRequest, exception: Http404) -> HttpResponseNotFound:
def handler404(request: HttpRequest, exception: Http404) -> HttpResponse:
"""
Render a HTTP 404 Error code

:param request: Object representing the user call
:param exception: Exception (unused)
:return: The rendered template response
:return: The error response
"""
context = {
"request": request,
Expand All @@ -95,32 +117,32 @@ def handler404(request: HttpRequest, exception: Http404) -> HttpResponseNotFound
"message": _("The page you requested could not be found."),
}
logger.debug(exception)
return HttpResponseNotFound(render_error_template(context))
return render_error_response(context)


def handler500(request: HttpRequest) -> HttpResponseServerError:
def handler500(request: HttpRequest) -> HttpResponse:
"""
Render a HTTP 500 Error code

:param request: Object representing the user call
:return: The rendered template response
:return: The error response
"""
context = {
"request": request,
"code": 500,
"title": _("Internal Server Error"),
"message": _("An unexpected error has occurred."),
}
return HttpResponseServerError(render_error_template(context))
return render_error_response(context)


def csrf_failure(request: HttpRequest, reason: str) -> HttpResponseForbidden:
def csrf_failure(request: HttpRequest, reason: str) -> HttpResponse:
"""
Render a CSRF failure notice

:param request: Object representing the user call
:param reason: Description of reason for CSRF failure
:return: The rendered template response
:return: The error response
"""
context = {
"request": request,
Expand All @@ -129,4 +151,4 @@ def csrf_failure(request: HttpRequest, reason: str) -> HttpResponseForbidden:
"message": _("Please try to reload the page."),
}
logger.debug(reason)
return HttpResponseForbidden(render_error_template(context))
return render_error_response(context)
2 changes: 2 additions & 0 deletions integreat_cms/release_notes/current/unreleased/2308.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
en: Fix errors not being returned as JSON for the API
de: Behebe Fehler, die für die API nicht als JSON zurückgegeben wurden
Loading