From 6e43fd6e4972555cb571ed7914a80b31e6eabf16 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 22 Jul 2024 02:09:12 +0000 Subject: [PATCH 1/3] feat: updated referer handling --- litestar_vite/inertia/_utils.py | 1 + litestar_vite/inertia/exception_handler.py | 2 +- litestar_vite/inertia/middleware.py | 6 +----- litestar_vite/inertia/request.py | 5 +++++ litestar_vite/inertia/response.py | 7 ++++++- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/litestar_vite/inertia/_utils.py b/litestar_vite/inertia/_utils.py index 0257b3a..3564e08 100644 --- a/litestar_vite/inertia/_utils.py +++ b/litestar_vite/inertia/_utils.py @@ -15,6 +15,7 @@ class InertiaHeaders(str, Enum): PARTIAL_DATA = "X-Inertia-Partial-Data" PARTIAL_COMPONENT = "X-Inertia-Partial-Component" LOCATION = "X-Inertia-Location" + REFERER = "Referer" def get_enabled_header(enabled: bool = True) -> dict[str, Any]: diff --git a/litestar_vite/inertia/exception_handler.py b/litestar_vite/inertia/exception_handler.py index 5c03662..76c1902 100644 --- a/litestar_vite/inertia/exception_handler.py +++ b/litestar_vite/inertia/exception_handler.py @@ -44,7 +44,7 @@ class _HTTPConflictException(HTTPException): status_code = HTTP_409_CONFLICT -def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]: +def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]: # noqa: PLR0911, PLR0912, C901 """Handler for all exceptions subclassed from HTTPException.""" inertia_enabled = getattr(request, "inertia_enabled", False) or getattr(request, "is_inertia", False) if isinstance(exc, NotFoundError): diff --git a/litestar_vite/inertia/middleware.py b/litestar_vite/inertia/middleware.py index 0034a68..2b1f5b7 100644 --- a/litestar_vite/inertia/middleware.py +++ b/litestar_vite/inertia/middleware.py @@ -15,7 +15,7 @@ StateT, UserT, ) - from litestar.types import ASGIApp + from litestar.types import ASGIApp, Receive, Scope, Send async def redirect_on_asset_version_mismatch(request: Request[UserT, AuthT, StateT]) -> InertiaRedirect | None: @@ -32,10 +32,6 @@ async def redirect_on_asset_version_mismatch(request: Request[UserT, AuthT, Stat return InertiaRedirect(request, redirect_to=str(request.url)) -if TYPE_CHECKING: - from litestar.types import Receive, Scope, Send - - class InertiaMiddleware(AbstractMiddleware): def __init__(self, app: ASGIApp) -> None: super().__init__(app) diff --git a/litestar_vite/inertia/request.py b/litestar_vite/inertia/request.py index b20046d..c6c6a71 100644 --- a/litestar_vite/inertia/request.py +++ b/litestar_vite/inertia/request.py @@ -69,6 +69,11 @@ def partial_data(self) -> str | None: """Partial Data Reload.""" return self._get_header_value(InertiaHeaders.PARTIAL_DATA) + @cached_property + def referer(self) -> str | None: + """Partial Data Reload.""" + return self._get_header_value(InertiaHeaders.REFERER) + @cached_property def is_partial_render(self) -> bool: """Is Partial Data Reload.""" diff --git a/litestar_vite/inertia/response.py b/litestar_vite/inertia/response.py index 0695104..f74eded 100644 --- a/litestar_vite/inertia/response.py +++ b/litestar_vite/inertia/response.py @@ -34,6 +34,7 @@ from litestar.connection.base import AuthT, StateT, UserT from litestar.types import ResponseCookies, ResponseHeaders, TypeEncodersMap + from litestar_vite.inertia.request import InertiaRequest from litestar_vite.inertia.routes import Routes from .plugin import InertiaPlugin @@ -339,8 +340,12 @@ def __init__( """Initialize external redirect, Set status code to 409 (required by Inertia), and pass redirect url. """ + referer = request.headers.get("referer", str(request.base_url)) + inertia_enabled = getattr(request, "inertia_enabled", False) or getattr(request, "is_inertia", False) + if inertia_enabled: + referer = cast("InertiaRequest[Any, Any, Any]", request).inertia.referer or referer super().__init__( - path=request.headers.get("referrer", str(request.base_url)), + path=request.headers.get("referer", str(request.base_url)), status_code=HTTP_307_TEMPORARY_REDIRECT if request.method == "GET" else HTTP_303_SEE_OTHER, cookies=request.cookies, **kwargs, From e85fe3713d5f009ad9d04f1dbdd99605cc336aa5 Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 22 Jul 2024 02:09:47 +0000 Subject: [PATCH 2/3] chore(release): bump version to `v0.2.2` --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c9040af..894bf38 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ license = { text = "MIT" } name = "litestar-vite" readme = "README.md" requires-python = ">=3.8" -version = "0.2.1" +version = "0.2.2" [project.urls] Changelog = "https://cofin.github.io/litestar-vite/latest/changelog" From 23e7d679abd37eeb6d0dcc5d06b0e7bc5d0c1b5f Mon Sep 17 00:00:00 2001 From: Cody Fincher Date: Mon, 22 Jul 2024 14:06:21 +0000 Subject: [PATCH 3/3] feat: always try to flash/error --- litestar_vite/inertia/exception_handler.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/litestar_vite/inertia/exception_handler.py b/litestar_vite/inertia/exception_handler.py index 76c1902..38df938 100644 --- a/litestar_vite/inertia/exception_handler.py +++ b/litestar_vite/inertia/exception_handler.py @@ -1,3 +1,4 @@ +import contextlib import re from typing import TYPE_CHECKING, Any, cast @@ -28,7 +29,6 @@ HTTP_422_UNPROCESSABLE_ENTITY, HTTP_500_INTERNAL_SERVER_ERROR, ) -from litestar.types import Empty from litestar_vite.inertia.response import InertiaBack, InertiaRedirect, InertiaResponse, error @@ -44,7 +44,7 @@ class _HTTPConflictException(HTTPException): status_code = HTTP_409_CONFLICT -def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]: # noqa: PLR0911, PLR0912, C901 +def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exception) -> Response[Any]: # noqa: PLR0911 """Handler for all exceptions subclassed from HTTPException.""" inertia_enabled = getattr(request, "inertia_enabled", False) or getattr(request, "is_inertia", False) if isinstance(exc, NotFoundError): @@ -57,7 +57,6 @@ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exce if request.app.debug and http_exc not in (PermissionDeniedException, NotFoundError): return cast("Response[Any]", create_debug_response(request, exc)) return cast("Response[Any]", create_exception_response(request, http_exc(detail=str(exc.__cause__)))) - has_active_session = not (not request.session or request.scope["session"] is Empty) is_inertia = getattr(request, "is_inertia", False) status_code = getattr(exc, "status_code", HTTP_500_INTERNAL_SERVER_ERROR) preferred_type = MediaType.HTML if inertia_enabled and not is_inertia else MediaType.JSON @@ -67,7 +66,7 @@ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exce inertia_plugin = cast("InertiaPlugin", request.app.plugins.get("InertiaPlugin")) if extras: content.update({"extra": extras}) - if has_active_session: + with contextlib.suppress(Exception): flash(request, detail, category="error") if extras and len(extras) >= 1: message = extras[0] @@ -75,8 +74,9 @@ def exception_to_http_response(request: Request[UserT, AuthT, StateT], exc: Exce error_detail = cast("str", message.get("message", detail)) # type: ignore[union-attr] # pyright: ignore[reportUnknownMemberType,reportUnknownArgumentType] match = FIELD_ERR_RE.search(error_detail) field = match.group(1) if match else default_field - if isinstance(message, dict) and has_active_session: - error(request, field, error_detail) + if isinstance(message, dict): + with contextlib.suppress(Exception): + error(request, field, error_detail) if status_code in {HTTP_422_UNPROCESSABLE_ENTITY, HTTP_400_BAD_REQUEST} or isinstance( exc, PermissionDeniedException,