Kunden-Admins pflegen Mail, Nextcloud, ownCloud, WebDAV, SMB und Web-Proxy ihrer Organisation (Formulare aus den Typ-Definitionen des Servers, keine Zugangsdaten), Wirkung fuer die ganze Org, OEs oder Gruppen. Unterseite erscheint nur fuer freigeschaltete Organisationen; root pflegt immer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
91 lines
3.9 KiB
Python
91 lines
3.9 KiB
Python
# Org-Ressourcen (15.10.2026, platform-docs roadmap/org-ressourcen-konzept.md):
|
||
# gemeinsamer Teil von Kunden-Seite (/organisation/ressourcen) und Admin-
|
||
# Reiter (/admin/kunden/<org>/ressourcen). Die Typen und ihre Felder
|
||
# definiert allein der Server (ORG_RESSOURCEN_TYPEN in provisioning-server),
|
||
# das Formular wird daraus erzeugt.
|
||
|
||
from urllib.parse import urlencode
|
||
|
||
from anode_client import anode_request
|
||
|
||
|
||
def lade_ressourcen_kontext(organization_id: str) -> dict:
|
||
"""Alles, was templates/_ressourcen.html braucht."""
|
||
|
||
typen = anode_request("GET", "/api/v1/org-ressourcen/typen").get("typen", {})
|
||
liste = anode_request("GET", f"/api/v1/organizations/{organization_id}/ressourcen")
|
||
|
||
oes_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/organisationseinheiten")
|
||
oes = oes_result.get("organisationseinheiten", []) if oes_result.get("success") else []
|
||
gruppen_result = anode_request("GET", f"/api/v1/organizations/{organization_id}/gruppen")
|
||
gruppen = gruppen_result.get("gruppen", []) if gruppen_result.get("success") else []
|
||
|
||
# OE-Pfad statt nur Name ("Schule › Haus A"), sortiert wie der Baum.
|
||
by_id = {oe["id"]: oe for oe in oes}
|
||
|
||
def pfad(oe):
|
||
teile, current, gesehen = [], oe, set()
|
||
while current is not None and current["id"] not in gesehen:
|
||
gesehen.add(current["id"])
|
||
teile.append(current["name"])
|
||
current = by_id.get(current.get("parent_id"))
|
||
return " › ".join(reversed(teile))
|
||
|
||
oe_auswahl = sorted(({"id": oe["id"], "name": pfad(oe)} for oe in oes), key=lambda o: o["name"].lower())
|
||
|
||
return {
|
||
"ressourcen_typen": typen,
|
||
"ressourcen": liste.get("ressourcen", []) if liste.get("success") else [],
|
||
"ressourcen_freigeschaltet": bool(liste.get("freigeschaltet")),
|
||
"ressourcen_oes": oe_auswahl,
|
||
"ressourcen_gruppen": gruppen,
|
||
}
|
||
|
||
|
||
def ressourcen_freigeschaltet(organization_id: str) -> bool:
|
||
liste = anode_request("GET", f"/api/v1/organizations/{organization_id}/ressourcen")
|
||
return bool(liste.get("success") and liste.get("freigeschaltet"))
|
||
|
||
|
||
def payload_aus_formular(form, typen: dict) -> dict:
|
||
"""Formularfelder (typ, name, daten.<key>, ganze_organisation,
|
||
oe_ids, gruppe_ids) in die Server-Anfrage übersetzen. Nur Felder, die der
|
||
Typ kennt; prüfen tut der Server."""
|
||
|
||
typ = form.get("typ", "")
|
||
felder = typen.get(typ, {}).get("felder", [])
|
||
daten = {f["key"]: form.get(f"daten.{f['key']}", "") for f in felder}
|
||
ganze_organisation = form.get("ganze_organisation") == "on"
|
||
|
||
return {
|
||
"typ": typ,
|
||
"name": form.get("name", ""),
|
||
"daten": daten,
|
||
"ganze_organisation": ganze_organisation,
|
||
"oe_ids": [] if ganze_organisation else form.getlist("oe_ids"),
|
||
"gruppe_ids": [] if ganze_organisation else form.getlist("gruppe_ids"),
|
||
}
|
||
|
||
|
||
def speichern(organization_id: str, ressource_id: str | None, form, ziel: str) -> str:
|
||
"""Anlegen oder ändern, liefert die Weiterleitungs-URL (mit ?fehler=…
|
||
bei einer Ablehnung durch den Server)."""
|
||
|
||
typen = anode_request("GET", "/api/v1/org-ressourcen/typen").get("typen", {})
|
||
payload = payload_aus_formular(form, typen)
|
||
if ressource_id is None:
|
||
result = anode_request("POST", f"/api/v1/organizations/{organization_id}/ressourcen", json=payload)
|
||
else:
|
||
result = anode_request("PUT", f"/api/v1/organizations/{organization_id}/ressourcen/{ressource_id}", json=payload)
|
||
|
||
if not result.get("success"):
|
||
return ziel + "?" + urlencode({"fehler": result.get("message", "Die Ressource konnte nicht gespeichert werden.")})
|
||
return ziel
|
||
|
||
|
||
def loeschen(organization_id: str, ressource_id: str, ziel: str) -> str:
|
||
result = anode_request("DELETE", f"/api/v1/organizations/{organization_id}/ressourcen/{ressource_id}")
|
||
if not result.get("success"):
|
||
return ziel + "?" + urlencode({"fehler": result.get("message", "Die Ressource konnte nicht gelöscht werden.")})
|
||
return ziel
|