diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 6641d8d..3f4b54f 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -9,7 +9,6 @@ dict(e=exceptions.FieldError("test")), dict(e=exceptions.NamingThingsError("test")), dict(e=exceptions.NotFound("test")), - dict(e=exceptions.PermissionsError("test")), dict(e=exceptions.WorfError("test")), ) def test_exception(e): diff --git a/worf/exceptions.py b/worf/exceptions.py index 89428ef..c2217cf 100644 --- a/worf/exceptions.py +++ b/worf/exceptions.py @@ -31,11 +31,6 @@ class NotFound(WorfError): message: str = "Not found" -@dataclass(frozen=True) -class PermissionsError(WorfError): - message: str - - @dataclass(frozen=True) class FieldError(WorfError, ValueError): message: str diff --git a/worf/renderers.py b/worf/renderers.py index 6246054..1d503cd 100644 --- a/worf/renderers.py +++ b/worf/renderers.py @@ -8,13 +8,14 @@ def browsable_response(request, response, status_code, view): template = "worf/api.html" - serializer = view.get_serializer() + serializer = hasattr(view, "bundle") and view.get_serializer() - include = field_list(view.bundle.get("include", [])) - search = field_list(view.bundle.get("search", []), delimiter="__") + bundle = getattr(view, "bundle", {}) + include = field_list(bundle.get("include", [])) + search = field_list(bundle.get("search", []), delimiter="__") filter_fields = [ - (transform_field(field), bool(field in view.bundle)) + (transform_field(field), bool(field in bundle)) for field in getattr(view, "filter_fields", []) ] include_fields = [ @@ -42,11 +43,11 @@ def browsable_response(request, response, status_code, view): ( "Search", sorted(search_fields), - len(search or search_fields) if view.bundle.get("q") else 0, + len(search or search_fields) if bundle.get("q") else 0, ), ], lookup_kwargs=getattr(view, "lookup_kwargs", {}), - payload=view.bundle, + payload=bundle, response=response, serializer=serializer, serializer_name=type(serializer).__name__, diff --git a/worf/views/__init__.py b/worf/views/__init__.py index 455476d..b19661d 100644 --- a/worf/views/__init__.py +++ b/worf/views/__init__.py @@ -3,5 +3,6 @@ from worf.views.create import CreateAPI # noqa: F401 from worf.views.delete import DeleteAPI # noqa: F401 from worf.views.detail import DetailAPI, DetailUpdateAPI # noqa: F401 +from worf.views.errors import NotFound # noqa: F401 from worf.views.list import ListAPI, ListCreateAPI # noqa: F401 from worf.views.update import UpdateAPI # noqa: F401 diff --git a/worf/views/base.py b/worf/views/base.py index f864abe..373e2be 100644 --- a/worf/views/base.py +++ b/worf/views/base.py @@ -22,7 +22,6 @@ DataConflict, FieldError, NotFound, - PermissionsError, WorfError, ) from worf.renderers import render_response @@ -44,9 +43,9 @@ def render_to_response(self, data=None, status_code=200): data = self.serialize() if data is None: - msg = f"{self.codepath} did not pass an object to " - msg += "render_to_response, nor did its serializer method" - raise ImproperlyConfigured(msg) + message = f"{self.codepath} did not pass an object to " + message += "render_to_response, nor did its serializer method" + raise ImproperlyConfigured(message) return render_response(self.request, data, status_code, self) @@ -59,9 +58,6 @@ class AbstractBaseAPI(SerializeModels, ValidateFields, APIResponse): def __init__(self, *args, **kwargs): self.codepath = f"{self.__module__}.{self.__class__.__name__}" - if self.model is None: # pragma: no cover - raise ImproperlyConfigured(f"Model is not set on {self.codepath}") - if not isinstance(self.permissions, list): # pragma: no cover raise ImproperlyConfigured( f"{self.codepath}.permissions must be type: list" @@ -127,10 +123,9 @@ def check_permissions(self): perm()(self.request, **self.kwargs) except WorfError as e: if settings.WORF_DEBUG: # pragma: no cover - raise PermissionsError( - f"Permission check {perm.__module__}.{perm.__name__} raised {e.__class__.__name__}. " - f"You'd normally see a 4xx here but WORF_DEBUG=True." - ) from e + check = f"{perm.__module__}.{perm.__name__}" + error = e.__class__.__name__ + raise type(e)(f"{e.message}: Permission {check} raised {error}") from e raise e def get_handler(self, request, *args, **kwargs): diff --git a/worf/views/errors.py b/worf/views/errors.py new file mode 100644 index 0000000..62f4812 --- /dev/null +++ b/worf/views/errors.py @@ -0,0 +1,11 @@ +from django.utils.decorators import method_decorator +from django.views.decorators.csrf import csrf_exempt + +from worf import exceptions +from worf.views.base import AbstractBaseAPI + + +@method_decorator(csrf_exempt, name="dispatch") +class NotFound(AbstractBaseAPI): + def perform_dispatch(self, *args, **kwargs): + raise exceptions.NotFound()