summaryrefslogtreecommitdiffstats
path: root/management/endpoints.py
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2026-07-30 16:03:32 +0200
committerGravatar Tom van der Lee <tom@vanderlee.io>2026-07-30 16:03:32 +0200
commit2d22158dd95f76399f5716d556be60c77da04a46 (patch)
tree15fca3adae0f44674fe06bc141879804659c3664 /management/endpoints.py
parentaa56bc05285981d57c5adb2cee3c4e898fb2a702 (diff)
downloadserver-v3.tar.gz
server-v3.tar.bz2
server-v3.zip
Admin uiv3
Diffstat (limited to 'management/endpoints.py')
-rw-r--r--management/endpoints.py22
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 @@
1from functools import wraps
2from urllib.parse import urlencode
3
1from fastapi import FastAPI, Request 4from fastapi import FastAPI, Request
2from sqlalchemy import func 5from sqlalchemy import func
3from sqlmodel import select 6from sqlmodel import select
4from starlette.authentication import requires
5from starlette.middleware.authentication import AuthenticationMiddleware 7from starlette.middleware.authentication import AuthenticationMiddleware
6from starlette.middleware.sessions import SessionMiddleware 8from starlette.middleware.sessions import SessionMiddleware
7from starlette.responses import RedirectResponse 9from starlette.responses import RedirectResponse
@@ -21,6 +23,20 @@ templates = Jinja2Templates(directory=[
21 'management/templates' 23 'management/templates'
22]) 24])
23 25
26
27def 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('/')
25async def index(request: Request): 41async 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
38async def dashboard(request: Request): 54async 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
43async def users(request: Request): 59async 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)