"""Welche Einträge der Seitenleiste jemand ausgeblendet hat. Zwei Ebenen: die **Vorgabe des Administrators** gilt für alle (``user_id`` NULL), die **eigene Auswahl** eines Kontos kommt obendrauf. Beide Listen gelten zusammen — wer etwas versteckt, versteckt es zusätzlich; einblenden, was der Administrator ausgeblendet hat, kann niemand. Die eigene Auswahl darf jeder für sich ändern (es betrifft nur seine Ansicht), die Vorgabe nur ein Administrator. Versteckt wird ausschliesslich der **Eintrag**, nicht die Seite: Lesezeichen, Dashboard-Karten und Lagerort-QR verweisen weiter auf Routen, die hier abgewählt sein können, und sollen weiter funktionieren. """ import json from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from ..database import get_db from ..deps import get_current_user, require_admin from ..models import NavigationSichtbarkeit, User from ..schemas import NavigationOut, NavigationSetzen router = APIRouter(prefix="/navigation", tags=["navigation"]) def _liste(zeile: NavigationSichtbarkeit | None) -> list[str]: """Die gespeicherte Liste – kaputter Inhalt gilt als leer. Lieber eine vollständige Leiste als eine Fehlermeldung: Ein unlesbarer Eintrag darf niemanden aussperren. """ if zeile is None: return [] try: werte = json.loads(zeile.versteckt) except ValueError: return [] return [w for w in werte if isinstance(w, str)] if isinstance(werte, list) else [] def _zeile(db: Session, user_id: int | None) -> NavigationSichtbarkeit | None: return ( db.query(NavigationSichtbarkeit) .filter(NavigationSichtbarkeit.user_id.is_(None) if user_id is None else NavigationSichtbarkeit.user_id == user_id) .first() ) def _schreiben(db: Session, user_id: int | None, versteckt: list[str]) -> None: """Die Zeile setzen oder anlegen. Doppelte und leere Einträge fallen weg; die Reihenfolge ist bedeutungslos und wird sortiert, damit zwei gleiche Auswahlen auch gleich aussehen. """ sauber = sorted({w.strip() for w in versteckt if w and w.strip()}) zeile = _zeile(db, user_id) if zeile is None: zeile = NavigationSichtbarkeit(user_id=user_id, versteckt=json.dumps(sauber)) db.add(zeile) else: zeile.versteckt = json.dumps(sauber) db.commit() def _antwort(db: Session, user: User) -> NavigationOut: vorgabe = _liste(_zeile(db, None)) eigen = _liste(_zeile(db, user.id)) return NavigationOut( vorgabe=vorgabe, eigen=eigen, versteckt=sorted(set(vorgabe) | set(eigen)) ) @router.get("", response_model=NavigationOut) def navigation_lesen( db: Session = Depends(get_db), user: User = Depends(get_current_user), ) -> NavigationOut: """Vorgabe, eigene Auswahl und die fertige Vereinigung.""" return _antwort(db, user) @router.put("", response_model=NavigationOut) def eigene_auswahl_setzen( payload: NavigationSetzen, db: Session = Depends(get_db), user: User = Depends(get_current_user), ) -> NavigationOut: """Die eigene Auswahl – betrifft nur die eigene Ansicht.""" _schreiben(db, user.id, payload.versteckt) return _antwort(db, user) @router.put("/vorgabe", response_model=NavigationOut) def vorgabe_setzen( payload: NavigationSetzen, db: Session = Depends(get_db), user: User = Depends(require_admin), ) -> NavigationOut: """Die Vorgabe für alle.""" _schreiben(db, None, payload.versteckt) return _antwort(db, user)