diff --git a/integreat_cms/cms/views/error_handler/error_handler.py b/integreat_cms/cms/views/error_handler/error_handler.py index 9f5ee23fce..84e6ab74e6 100644 --- a/integreat_cms/cms/views/error_handler/error_handler.py +++ b/integreat_cms/cms/views/error_handler/error_handler.py @@ -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 _ @@ -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 @@ -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, @@ -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, @@ -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, @@ -95,15 +117,15 @@ 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, @@ -111,16 +133,16 @@ def handler500(request: HttpRequest) -> HttpResponseServerError: "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, @@ -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) diff --git a/integreat_cms/release_notes/current/unreleased/2308.yml b/integreat_cms/release_notes/current/unreleased/2308.yml new file mode 100644 index 0000000000..e25fe99035 --- /dev/null +++ b/integreat_cms/release_notes/current/unreleased/2308.yml @@ -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