from fastapi import APIRouter, Depends, Form, HTTPException, Request from fastapi.responses import RedirectResponse from anode_client import anode_request from auth import get_current_user from templating import templates router = APIRouter() def fetch_gruppen(organization_id: str) -> list[dict]: result = anode_request("GET", f"/api/v1/organizations/{organization_id}/gruppen") return result.get("gruppen", []) if result.get("success") else [] def find_gruppe_in_organization(gruppe_id: str, organization_id: str) -> dict | None: """ Besitz-Validierung analog zu find_oe_in_organization() in routers/struktur.py (siehe ADR-0011): eine gruppe_id aus der URL wird nur akzeptiert, wenn sie tatsächlich in der Gruppenliste der eigenen Organisation auftaucht. """ for gruppe in fetch_gruppen(organization_id): if gruppe["id"] == gruppe_id: return gruppe return None @router.get("/gruppen") def gruppen_liste(request: Request, user=Depends(get_current_user)): gruppen = fetch_gruppen(user.organization_id) return templates.TemplateResponse(request, "gruppen_liste.html", {"user": user, "gruppen": gruppen}) @router.post("/gruppen") def gruppe_anlegen(name: str = Form(...), user=Depends(get_current_user)): anode_request("POST", f"/api/v1/organizations/{user.organization_id}/gruppen", json={"name": name}) return RedirectResponse("/gruppen", status_code=303) @router.get("/gruppen/{gruppe_id}/umbenennen") def gruppe_umbenennen_form(request: Request, gruppe_id: str, user=Depends(get_current_user)): gruppe = find_gruppe_in_organization(gruppe_id, user.organization_id) if gruppe is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") return templates.TemplateResponse(request, "gruppe_umbenennen.html", {"user": user, "gruppe": gruppe}) @router.post("/gruppen/{gruppe_id}/umbenennen") def gruppe_umbenennen(gruppe_id: str, name: str = Form(...), user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("PATCH", f"/api/v1/gruppen/{gruppe_id}", json={"name": name}) return RedirectResponse("/gruppen", status_code=303) @router.get("/gruppen/{gruppe_id}/loeschen") def gruppe_loeschen_form(request: Request, gruppe_id: str, user=Depends(get_current_user)): gruppe = find_gruppe_in_organization(gruppe_id, user.organization_id) if gruppe is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") return templates.TemplateResponse(request, "gruppe_loeschen.html", {"user": user, "gruppe": gruppe}) @router.post("/gruppen/{gruppe_id}/loeschen") def gruppe_loeschen(gruppe_id: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("DELETE", f"/api/v1/gruppen/{gruppe_id}") return RedirectResponse("/gruppen", status_code=303) @router.get("/gruppen/{gruppe_id}") def gruppe_detail(request: Request, gruppe_id: str, user=Depends(get_current_user)): gruppe = find_gruppe_in_organization(gruppe_id, user.organization_id) if gruppe is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") merkmale_result = anode_request("GET", f"/api/v1/gruppen/{gruppe_id}/merkmale") merkmale = merkmale_result.get("merkmale", []) if merkmale_result.get("success") else [] kategorien: dict[str, list[dict]] = {} for eintrag in merkmale: kategorie_name = eintrag["kategorie"]["name"] if eintrag["kategorie"] else "Ohne Kategorie" kategorien.setdefault(kategorie_name, []).append(eintrag) devices_result = anode_request("GET", f"/api/v1/organizations/{user.organization_id}/devices") devices = devices_result.get("devices", []) if devices_result.get("success") else [] # anode bietet keinen direkten "Geräte einer Gruppe"-Endpunkt an, nur # "Gruppen eines Geräts" (GET /devices/{id}/gruppen) - daher hier für # jedes Gerät der Organisation dessen Gruppen abfragen und filtern # (gleiches Muster wie admin_kunden.py:gruppe_detail()). mitglied_ids = set() for device in devices: dg_result = anode_request("GET", f"/api/v1/devices/{device['id']}/gruppen") device_gruppen = dg_result.get("gruppen", []) if dg_result.get("success") else [] if any(g["id"] == gruppe_id for g in device_gruppen): mitglied_ids.add(device["id"]) return templates.TemplateResponse( request, "gruppe_detail.html", { "user": user, "gruppe": gruppe, "kategorien": kategorien, "devices": devices, "mitglied_ids": mitglied_ids, }, ) @router.post("/gruppen/{gruppe_id}/merkmale/{merkmal_key}/select") def gruppe_merkmal_select(gruppe_id: str, merkmal_key: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("POST", f"/api/v1/gruppen/{gruppe_id}/merkmale/{merkmal_key}/select") return RedirectResponse(f"/gruppen/{gruppe_id}", status_code=303) @router.post("/gruppen/{gruppe_id}/merkmale/{merkmal_key}/deselect") def gruppe_merkmal_deselect(gruppe_id: str, merkmal_key: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("POST", f"/api/v1/gruppen/{gruppe_id}/merkmale/{merkmal_key}/deselect") return RedirectResponse(f"/gruppen/{gruppe_id}", status_code=303) @router.post("/gruppen/{gruppe_id}/merkmale/{merkmal_key}/unset") def gruppe_merkmal_unset(gruppe_id: str, merkmal_key: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("POST", f"/api/v1/gruppen/{gruppe_id}/merkmale/{merkmal_key}/unset") return RedirectResponse(f"/gruppen/{gruppe_id}", status_code=303) @router.post("/gruppen/{gruppe_id}/geraete/{device_id}/hinzufuegen") def gruppe_geraet_hinzufuegen(gruppe_id: str, device_id: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") # Besitz-Validierung fürs Gerät reicht hier über den bestehenden # find_device_in_organization()-Umweg nicht direkt, aber anode prüft # bei add_device_to_gruppe() bereits serverseitig, dass Gerät und # Gruppe zur selben Organisation gehören (siehe app.py) - ein Zugriff # auf ein fremdes device_id würde dort mit invalid_membership abgelehnt. anode_request("POST", f"/api/v1/devices/{device_id}/gruppen/{gruppe_id}") return RedirectResponse(f"/gruppen/{gruppe_id}", status_code=303) @router.post("/gruppen/{gruppe_id}/geraete/{device_id}/entfernen") def gruppe_geraet_entfernen(gruppe_id: str, device_id: str, user=Depends(get_current_user)): if find_gruppe_in_organization(gruppe_id, user.organization_id) is None: raise HTTPException(status_code=404, detail="Gruppe wurde nicht gefunden.") anode_request("DELETE", f"/api/v1/devices/{device_id}/gruppen/{gruppe_id}") return RedirectResponse(f"/gruppen/{gruppe_id}", status_code=303)