Plugin audit-log: Protokolltabelle, öffentliche API und Admin-Ansicht
- Eigene Migration 0001_audit_eintraege (Tabelle audit_eintraege: Akteur,
Aktion, Objekttyp/-ID, Alt/Neu + Details als JSON, optionale IP, Zeitstempel)
- Öffentliche Plugin-API: await log(actor, action, objekt_typ, objekt_id,
details, ip_adresse) bzw. log_sync() für synchrone Routen; andere Plugins
holen die API über request.app.state.registry.get("audit-log")
- Admin-Ansicht /audit-log (nur Admin): Filter nach Benutzer, Aktionstyp und
Zeitraum, Paginierung (25/Seite), deutsche UI, Alt/Neu-JSON-Darstellung
- Tests: Logging-Funktion (Actor-Varianten, alt/neu-Extraktion), Migration,
Filter-Querys, Paginierung, Nur-Admin-Zugriff (13 neue Tests)
- Loader-Test angepasst: voll implementierte Plugins tragen keinen
Platzhalter-Text mehr
- AGENTS.md: Status aktualisiert
Verifiziert: HEAD + diese Änderungen = 58 Tests grün (uv run pytest)
This commit is contained in:
@@ -8,7 +8,6 @@ from redaktionskern.contracts import BasePlugin, NavEntry
|
||||
from redaktionskern.plugin_loader import PluginError, PluginRegistry
|
||||
|
||||
ERWARTETE_STUBS = {
|
||||
"neuheiten",
|
||||
"dedup",
|
||||
"planung",
|
||||
"archiv",
|
||||
@@ -18,35 +17,53 @@ ERWARTETE_STUBS = {
|
||||
"export",
|
||||
}
|
||||
|
||||
# Voll implementierte Plugins (keine Stubs mehr):
|
||||
ERWARTETE_PLUGINS = ERWARTETE_STUBS | {"neuheiten"}
|
||||
|
||||
def test_alle_stubs_werden_geladen(app):
|
||||
|
||||
def test_alle_plugins_werden_geladen(app):
|
||||
namen = {p.name for p in app.state.registry.all()}
|
||||
assert ERWARTETE_STUBS <= namen
|
||||
assert ERWARTETE_PLUGINS <= namen
|
||||
|
||||
|
||||
def test_on_load_wurde_aufgerufen(app):
|
||||
for plugin in app.state.registry.all():
|
||||
if plugin.name in ERWARTETE_STUBS:
|
||||
if plugin.name in ERWARTETE_PLUGINS:
|
||||
assert plugin.loaded, f"Plugin {plugin.name} ist nicht geladen."
|
||||
assert plugin.context is not None
|
||||
|
||||
|
||||
def test_stubs_haben_navigation(app):
|
||||
for name in ERWARTETE_STUBS:
|
||||
def test_plugins_haben_navigation(app):
|
||||
for name in ERWARTETE_PLUGINS:
|
||||
plugin = app.state.registry.get(name)
|
||||
assert len(plugin.navigation()) == 1
|
||||
|
||||
|
||||
# Voll implementierte Plugins tragen keinen Platzhalter-Text mehr auf ihrer
|
||||
# Seite; die Prüfung läuft weiter für alle übrigen Platzhalter.
|
||||
VOLL_IMPLEMENTIERT = {"audit-log", "neuheiten", "benachrichtigung"}
|
||||
PLATZHALTER_STUBS = ERWARTETE_STUBS - VOLL_IMPLEMENTIERT
|
||||
|
||||
|
||||
def test_plugin_seiten_erreichbar(client):
|
||||
from tests.conftest import melde_an
|
||||
|
||||
melde_an(client)
|
||||
for name in sorted(ERWARTETE_STUBS):
|
||||
for name in sorted(PLATZHALTER_STUBS):
|
||||
antwort = client.get(f"/{name}")
|
||||
assert antwort.status_code == 200, name
|
||||
assert "ist geladen" in antwort.text
|
||||
|
||||
|
||||
def test_audit_log_seite_erreichbar_fuer_admin(client):
|
||||
from tests.conftest import melde_an
|
||||
|
||||
melde_an(client)
|
||||
antwort = client.get("/audit-log")
|
||||
assert antwort.status_code == 200
|
||||
assert "Audit-Log" in antwort.text
|
||||
|
||||
|
||||
def test_on_unload_beim_herunterfahren(app):
|
||||
plugin = app.state.registry.get("neuheiten")
|
||||
with TestClient(app):
|
||||
|
||||
Reference in New Issue
Block a user