diff options
| author | 2026-07-30 16:03:32 +0200 | |
|---|---|---|
| committer | 2026-07-30 16:03:32 +0200 | |
| commit | 2d22158dd95f76399f5716d556be60c77da04a46 (patch) | |
| tree | 15fca3adae0f44674fe06bc141879804659c3664 /management/endpoints.py | |
| parent | aa56bc05285981d57c5adb2cee3c4e898fb2a702 (diff) | |
| download | server-2d22158dd95f76399f5716d556be60c77da04a46.tar.gz server-2d22158dd95f76399f5716d556be60c77da04a46.tar.bz2 server-2d22158dd95f76399f5716d556be60c77da04a46.zip | |
Admin uiv3
Diffstat (limited to 'management/endpoints.py')
| -rw-r--r-- | management/endpoints.py | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/management/endpoints.py b/management/endpoints.py index 47602d6..ef44114 100644 --- a/management/endpoints.py +++ b/management/endpoints.py | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | from functools import wraps | ||
| 2 | from urllib.parse import urlencode | ||
| 3 | |||
| 1 | from fastapi import FastAPI, Request | 4 | from fastapi import FastAPI, Request |
| 2 | from sqlalchemy import func | 5 | from sqlalchemy import func |
| 3 | from sqlmodel import select | 6 | from sqlmodel import select |
| 4 | from starlette.authentication import requires | ||
| 5 | from starlette.middleware.authentication import AuthenticationMiddleware | 7 | from starlette.middleware.authentication import AuthenticationMiddleware |
| 6 | from starlette.middleware.sessions import SessionMiddleware | 8 | from starlette.middleware.sessions import SessionMiddleware |
| 7 | from starlette.responses import RedirectResponse | 9 | from starlette.responses import RedirectResponse |
| @@ -21,6 +23,20 @@ templates = Jinja2Templates(directory=[ | |||
| 21 | 'management/templates' | 23 | 'management/templates' |
| 22 | ]) | 24 | ]) |
| 23 | 25 | ||
| 26 | |||
| 27 | def requires_session(func): | ||
| 28 | """Redirects to an absolute login URL instead of Starlette's `requires(redirect=...)`, | ||
| 29 | which resolves the redirect target via `request.url_for()` against whichever router is | ||
| 30 | bound into `request.scope` -- a lookup that only reaches `authentication`'s routes when | ||
| 31 | `management` happens to be mounted under a shared root app.""" | ||
| 32 | @wraps(func) | ||
| 33 | async def wrapper(request: Request, *args, **kwargs): | ||
| 34 | if not {'authenticated', 'session'}.issubset(request.auth.scopes): | ||
| 35 | next_param = urlencode({'next': str(request.url)}) | ||
| 36 | return RedirectResponse(f'/auth/login/?{next_param}', status_code=303) | ||
| 37 | return await func(request, *args, **kwargs) | ||
| 38 | return wrapper | ||
| 39 | |||
| 24 | @management.get('/') | 40 | @management.get('/') |
| 25 | async def index(request: Request): | 41 | async def index(request: Request): |
| 26 | with get_session_context() as session: | 42 | with get_session_context() as session: |
| @@ -34,12 +50,12 @@ async def index(request: Request): | |||
| 34 | 50 | ||
| 35 | 51 | ||
| 36 | @management.get('/dashboard/') | 52 | @management.get('/dashboard/') |
| 37 | @requires(['authenticated', 'session'], redirect='get_login') | 53 | @requires_session |
| 38 | async def dashboard(request: Request): | 54 | async def dashboard(request: Request): |
| 39 | return templates.TemplateResponse(request, 'dashboard.html') | 55 | return templates.TemplateResponse(request, 'dashboard.html') |
| 40 | 56 | ||
| 41 | @management.get('/users/') | 57 | @management.get('/users/') |
| 42 | @requires(['authenticated', 'session'], redirect='get_login') | 58 | @requires_session |
| 43 | async def users(request: Request): | 59 | async def users(request: Request): |
| 44 | with get_session_context() as session: | 60 | with get_session_context() as session: |
| 45 | query = select(User) | 61 | query = select(User) |
