P1: Rollenbasiertes Dashboard mit Plugin-Karten

- Plugin-Vertrag erweitert: optionaler Hook dashboard_karten(user) +
  DashboardKarte-Dataclass (Kern bleibt schlank, Fachlogik im Plugin)
- Karten: Neuheiten+System-Status (neuheiten), Planungs-Stats bzw.
  eigene Einträge (planung), offene Dedup-Konflikte (dedup), nächste
  Redaktionsschlüsse (erinnerung), ungelesene Benachrichtigungen
  (benachrichtigung), letzte Audit-Einträge (audit-log, nur Admin),
  Benutzer-Anzahl (Kern, nur Admin)
- 'Geladene Plugins' als aufklappbarer Admin-Technikbereich
This commit is contained in:
Flo Hartmann
2026-08-26 08:48:30 +00:00
parent 742c265df8
commit 9bd3b700c4
9 changed files with 326 additions and 17 deletions

View File

@@ -33,7 +33,7 @@ from sqlalchemy.orm import Session
from redaktionskern.auth.deps import AccessDenied, get_db, require_user
from redaktionskern.auth.models import Role, User
from redaktionskern.contracts import BasePlugin, Migration, NavEntry
from redaktionskern.contracts import BasePlugin, DashboardKarte, Migration, NavEntry
from redaktionskern.db import Base
from .models import (
@@ -134,6 +134,55 @@ class PlanungPlugin(BasePlugin):
def navigation(self) -> list[NavEntry]:
return [NavEntry(label=self.title, url="/planung")]
def dashboard_karten(self, user: User) -> list[DashboardKarte]:
"""Dashboard: Planungs-Stats — Rezensenten ihre eigenen, die
Redaktion die Gesamtzahlen je Status."""
with self.context.session_factory() as db:
zaehler = dict(
db.execute(
select(Planungseintrag.status, func.count())
.group_by(Planungseintrag.status)
).all()
)
if user.role in REDAKTION:
return [
DashboardKarte(
titel="Planung",
wert=str(zaehler.get("offen", 0)),
beschreibung="offene Einträge",
zeilen=tuple(
f"{STATUS_ANZEIGE[s]}: {zaehler.get(s, 0)}"
for s in GUELTIGE_STATUS
),
link_url="/planung",
link_label="Zur Planung",
ton="neutral",
)
]
eigene = dict(
db.execute(
select(Planungseintrag.status, func.count())
.where(Planungseintrag.rezensent_id == user.id)
.group_by(Planungseintrag.status)
).all()
)
return [
DashboardKarte(
titel="Meine offenen Planungseinträge",
wert=str(eigene.get("offen", 0)),
link_url="/planung?status=offen",
link_label="Anzeigen",
ton="neutral",
),
DashboardKarte(
titel="Meine Einträge in Bearbeitung",
wert=str(eigene.get("in_bearbeitung", 0)),
link_url="/planung?status=in_bearbeitung",
link_label="Anzeigen",
ton="neutral",
),
]
# ---------- Hilfsfunktionen ----------
@staticmethod