feat: Kategorien-Verwaltung auf der Admin-Seite
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,22 @@ def create_category(data: CategoryIn, session: Session = Depends(get_session)):
|
||||
return CategoryOut.model_validate(cat)
|
||||
|
||||
|
||||
@router.patch("/categories/{category_id}", response_model=CategoryOut)
|
||||
def patch_category(category_id: int, data: CategoryIn,
|
||||
session: Session = Depends(get_session)):
|
||||
cat = session.get(Category, category_id)
|
||||
if cat is None:
|
||||
raise HTTPException(404, "Kategorie nicht gefunden")
|
||||
clash = session.execute(
|
||||
select(Category).where(Category.name == data.name)).scalar()
|
||||
if clash is not None and clash.id != category_id:
|
||||
raise HTTPException(409, "Kategorie existiert bereits")
|
||||
cat.name = data.name
|
||||
session.commit()
|
||||
session.refresh(cat)
|
||||
return CategoryOut.model_validate(cat)
|
||||
|
||||
|
||||
@router.get("/category-rules", response_model=list[CategoryRuleOut])
|
||||
def list_category_rules(session: Session = Depends(get_session)):
|
||||
rules = session.execute(
|
||||
|
||||
Reference in New Issue
Block a user