feat: Kategorien-Verwaltung auf der Admin-Seite

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 14:17:48 +02:00
parent b21d7b9839
commit 4431640eb2
6 changed files with 125 additions and 8 deletions

View File

@@ -1,8 +1,10 @@
from fastapi import APIRouter, Depends, Form, Request
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.auth import require_auth
from app.db import get_session
from app.models.tables import Category
from app.routers.gui import gui_session, templates
from app.services.admin import apply_rules_retroactively, change_password
@@ -10,8 +12,12 @@ router = APIRouter()
@router.get("/admin", dependencies=[Depends(gui_session)])
def admin_page(request: Request):
return templates.TemplateResponse(request, "admin.html", {"error": None, "success": None})
def admin_page(request: Request, session: Session = Depends(get_session)):
return templates.TemplateResponse(request, "admin.html", {
"error": None,
"success": None,
"categories": session.execute(select(Category)).scalars().all(),
})
@router.post("/admin/passwort", dependencies=[Depends(gui_session)])
@@ -20,18 +26,24 @@ def admin_change_password(
alt: str = Form(...),
neu: str = Form(...),
neu2: str = Form(...),
session: Session = Depends(get_session),
):
categories = session.execute(select(Category)).scalars().all()
# UX-Regel: das Formular selbst bleibt immer sichtbar/bedienbar; Fehler
# werden inline auf derselben Seite gemeldet statt still zu verwerfen.
# Der Kategorien-Abschnitt bleibt aus demselben Grund in JEDEM Render-Pfad
# (Fehler wie Erfolg) im Kontext, statt nur bei der GET-Route.
if len(neu) < 8:
return templates.TemplateResponse(request, "admin.html", {
"error": "Das neue Passwort muss mindestens 8 Zeichen lang sein.",
"success": None,
"categories": categories,
}, status_code=400)
if neu != neu2:
return templates.TemplateResponse(request, "admin.html", {
"error": "Die Wiederholung stimmt nicht mit dem neuen Passwort überein.",
"success": None,
"categories": categories,
}, status_code=400)
try:
change_password(alt, neu)
@@ -39,11 +51,13 @@ def admin_change_password(
return templates.TemplateResponse(request, "admin.html", {
"error": str(exc),
"success": None,
"categories": categories,
}, status_code=400)
return templates.TemplateResponse(request, "admin.html", {
"error": None,
"success": "Passwort erfolgreich geändert (gilt für GUI und Grafana). "
"Bestehende Sitzungen bleiben angemeldet.",
"categories": categories,
})