diff --git a/tildes/tildes/views/api/web/exceptions.py b/tildes/tildes/views/api/web/exceptions.py index 265a548..e72911e 100644 --- a/tildes/tildes/views/api/web/exceptions.py +++ b/tildes/tildes/views/api/web/exceptions.py @@ -18,6 +18,7 @@ from pyramid.response import Response from tildes.resources.comment import comment_by_id36 from tildes.resources.topic import topic_by_id36 from tildes.views.decorators import ic_view_config +from tildes.views.exceptions import errors_from_validationerror def _422_response_with_errors(errors: Sequence[str]) -> Response: @@ -44,15 +45,7 @@ def unprocessable_entity(request: Request) -> Response: if not validation_error: return _422_response_with_errors([str(request.exception)]) - errors_by_field = validation_error.messages - - error_strings = [] - for field, errors in errors_by_field.items(): - joined_errors = " ".join(errors) - if field != "_schema": - error_strings.append(f"{field}: {joined_errors}") - else: - error_strings.append(joined_errors) + error_strings = errors_from_validationerror(validation_error) return _422_response_with_errors(error_strings) diff --git a/tildes/tildes/views/exceptions.py b/tildes/tildes/views/exceptions.py index 7556e1d..9d9f947 100644 --- a/tildes/tildes/views/exceptions.py +++ b/tildes/tildes/views/exceptions.py @@ -3,7 +3,15 @@ """Views used by Pyramid when an exception is raised.""" -from pyramid.httpexceptions import HTTPError, HTTPForbidden, HTTPNotFound +from typing import Sequence + +from marshmallow import ValidationError +from pyramid.httpexceptions import ( + HTTPError, + HTTPForbidden, + HTTPNotFound, + HTTPUnprocessableEntity, +) from pyramid.request import Request from pyramid.view import ( exception_view_config, @@ -15,6 +23,21 @@ from sqlalchemy import cast, desc, func, Text from tildes.models.group import Group +def errors_from_validationerror(validation_error: ValidationError) -> Sequence[str]: + """Extract errors from a marshmallow ValidationError into a displayable format.""" + errors_by_field = validation_error.messages + + error_strings = [] + for field, errors in errors_by_field.items(): + joined_errors = " ".join(errors) + if field != "_schema": + error_strings.append(f"{field}: {joined_errors}") + else: + error_strings.append(joined_errors) + + return error_strings + + @exception_view_config( HTTPNotFound, route_name="group", renderer="error_group_not_found.jinja2" ) @@ -44,6 +67,11 @@ def generic_error_page(request: Request) -> dict: if isinstance(request.exception, HTTPForbidden): description = "You don't have access to this page" + if isinstance(request.exception, HTTPUnprocessableEntity) and isinstance( + request.exception.__context__, ValidationError + ): + errors = errors_from_validationerror(request.exception.__context__) + description = " ".join(errors) else: description = request.exception.explanation