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:
@@ -35,7 +35,13 @@ from sqlalchemy import func, or_, select
|
||||
|
||||
from redaktionskern.auth.deps import require_roles, require_user
|
||||
from redaktionskern.auth.models import Role, User
|
||||
from redaktionskern.contracts import BasePlugin, Migration, NavEntry, PluginContext
|
||||
from redaktionskern.contracts import (
|
||||
BasePlugin,
|
||||
DashboardKarte,
|
||||
Migration,
|
||||
NavEntry,
|
||||
PluginContext,
|
||||
)
|
||||
|
||||
from .bgg import BggClient, BggFehler
|
||||
from .models import Neuheit, QuellenStatus
|
||||
@@ -394,6 +400,43 @@ class NeuheitenPlugin(BasePlugin):
|
||||
def navigation(self) -> list[NavEntry]:
|
||||
return [NavEntry(label=self.title, url="/neuheiten")]
|
||||
|
||||
def dashboard_karten(self, user: User) -> list[DashboardKarte]:
|
||||
"""Dashboard: Neuheiten-Übersicht (Redaktion) + System-Status (Admin)."""
|
||||
if user.role not in (Role.ADMIN.value, Role.REDAKTEUR.value):
|
||||
return []
|
||||
with self.context.session_factory() as db:
|
||||
neu = db.scalar(
|
||||
select(func.count())
|
||||
.select_from(Neuheit)
|
||||
.where(Neuheit.status == "neuheit")
|
||||
) or 0
|
||||
karten = [
|
||||
DashboardKarte(
|
||||
titel="Neuheiten",
|
||||
wert=str(neu),
|
||||
beschreibung="Offene Einträge in der Neuheitenliste",
|
||||
link_url="/neuheiten",
|
||||
link_label="Zu den Neuheiten",
|
||||
ton="ok" if neu else "neutral",
|
||||
)
|
||||
]
|
||||
if user.role == Role.ADMIN.value:
|
||||
token = self._aktives_bgg_token()
|
||||
sync_aktiv = self._scheduler is not None and self._scheduler.running
|
||||
karten.append(
|
||||
DashboardKarte(
|
||||
titel="System-Status",
|
||||
zeilen=(
|
||||
f"BGG-API-Token: {'konfiguriert' if token else 'fehlt'}",
|
||||
f"Hintergrund-Sync: {'aktiv' if sync_aktiv else 'aus'}",
|
||||
),
|
||||
ton="ok" if token else "fehler",
|
||||
link_url="/neuheiten",
|
||||
link_label="Neuheiten synchronisieren",
|
||||
)
|
||||
)
|
||||
return karten
|
||||
|
||||
def on_load(self, context: PluginContext) -> None:
|
||||
super().on_load(context)
|
||||
import os
|
||||
|
||||
Reference in New Issue
Block a user