bifroest/app/identity/admin_routes.py
2026-10-27 08:34:17 +01:00

138 lines
7 KiB
Python

"""Administration: Teams und Nutzer."""
from typing import Annotated
from fastapi import APIRouter, Form, Request
from fastapi.responses import HTMLResponse, Response
from app import web
from app.core.database import now
from app.core.errors import Invalid
from app.identity import admin
from app.uploads import service as uploads
Text = Annotated[str, Form()]
Flag = Annotated[bool, Form()]
def router() -> APIRouter:
r = APIRouter()
def teams_page(request: Request, principal, error: str = "", status: int = 200) -> HTMLResponse:
admin.require(principal)
with web.db(request).session() as session:
rows = admin.teams(session)
return web.render(request, "admin_teams.html", {"rows": rows, "error": error}, status)
def team_page(request: Request, principal, team_id: int, error: str = "", notice: str = "",
status: int = 200) -> HTMLResponse:
admin.require(principal)
settings = web.settings(request)
with web.db(request).session() as session:
workspaces = admin.team_workspaces(session, team_id)
context = {"team": admin.get_team(session, team_id), "members": admin.team_members(session, team_id),
"workspaces": workspaces, "error": error, "notice": notice,
"storage": {w.id: uploads.storage(session, settings, w) for w in workspaces},
"default_storage_mb": settings.workspace_storage_mb}
return web.render(request, "admin_team.html", context, status)
def users_page(request: Request, principal, error: str = "", notice: str = "", status: int = 200,
issued: tuple[str, str] | None = None) -> HTMLResponse:
admin.require(principal)
with web.db(request).session() as session:
context = {"users": admin.users(session), "teams_by_user": admin.teams_by_user(session),
"error": error, "notice": notice, "issued": issued, "now": now()}
return web.render(request, "admin_users.html", context, status)
@r.get("/admin/teams")
def teams(request: Request, principal: web.User) -> HTMLResponse:
return teams_page(request, principal)
@r.post("/admin/teams")
def create_team(request: Request, principal: web.Checked, slug: Text, name: Text) -> Response:
try:
with web.db(request).session() as session:
team = admin.save_team(session, principal, None, slug=slug, name=name)
except Invalid as e:
return teams_page(request, principal, str(e), 400)
return web.redirect(f"/admin/teams/{team.id}")
@r.get("/admin/teams/{team_id}")
def team(request: Request, principal: web.User, team_id: int) -> HTMLResponse:
return team_page(request, principal, team_id)
def team_action(request: Request, principal, team_id: int, action, notice: str) -> Response:
try:
with web.db(request).session() as session:
action(session)
except Invalid as e:
return team_page(request, principal, team_id, error=str(e), status=400)
return team_page(request, principal, team_id, notice=notice)
@r.post("/admin/teams/{team_id}")
def update_team(request: Request, principal: web.Checked, team_id: int, slug: Text, name: Text) -> Response:
return team_action(request, principal, team_id,
lambda s: admin.save_team(s, principal, team_id, slug=slug, name=name), "Gespeichert.")
@r.post("/admin/teams/{team_id}/delete")
def delete_team(request: Request, principal: web.Checked, team_id: int) -> Response:
try:
with web.db(request).session() as session:
admin.delete_team(session, principal, team_id)
except Invalid as e:
return team_page(request, principal, team_id, error=str(e), status=400)
return web.redirect("/admin/teams")
@r.post("/admin/teams/{team_id}/workspaces/{workspace_id}/storage")
def set_storage(request: Request, principal: web.Checked, team_id: int, workspace_id: int,
limit_mb: Text = "") -> Response:
return team_action(request, principal, team_id,
lambda s: admin.set_storage_limit(s, principal, workspace_id, limit_mb),
"Speicherkontingent gespeichert.")
@r.post("/admin/teams/{team_id}/members")
def add_member(request: Request, principal: web.Checked, team_id: int, username: Text) -> Response:
return team_action(request, principal, team_id,
lambda s: admin.add_member(s, principal, team_id, username), "Mitglied hinzugefügt.")
@r.post("/admin/teams/{team_id}/members/{user_id}/remove")
def remove_member(request: Request, principal: web.Checked, team_id: int, user_id: int) -> Response:
return team_action(request, principal, team_id,
lambda s: admin.remove_member(s, principal, team_id, user_id),
"Entfernt, inklusive aller Workspace-Mitgliedschaften in diesem Team.")
@r.get("/admin/users")
def users(request: Request, principal: web.User) -> HTMLResponse:
return users_page(request, principal)
@r.post("/admin/users")
def create_user(request: Request, principal: web.Checked, username: Text, display_name: Text = "",
is_admin: Flag = False, email: Text = "") -> Response:
try:
with web.db(request).session() as session:
user, secret = admin.create_user(session, principal, username, display_name, is_admin, email)
except Invalid as e:
return users_page(request, principal, error=str(e), status=400)
return users_page(request, principal, issued=(user.username, secret),
notice="Nutzer angelegt. Jetzt einem Team zuordnen.")
@r.post("/admin/users/{user_id}/reset-password")
def reset_password(request: Request, principal: web.Checked, user_id: int) -> Response:
with web.db(request).session() as session:
user, secret = admin.reset_password(session, principal, user_id)
return users_page(request, principal, issued=(user.username, secret),
notice="Passwort zurückgesetzt; alle Sitzungen des Nutzers sind beendet.")
@r.post("/admin/users/{user_id}")
def update_user(request: Request, principal: web.Checked, user_id: int, display_name: Text = "",
is_admin: Flag = False, active: Flag = False, is_global_approver: Flag = False,
email: Text = "") -> Response:
try:
with web.db(request).session() as session:
admin.update_user(session, principal, user_id, display_name=display_name, is_admin=is_admin,
active=active, is_global_approver=is_global_approver, email=email)
except Invalid as e:
return users_page(request, principal, error=str(e), status=400)
return users_page(request, principal, notice="Gespeichert.")
return r