From d7956bf8f768166476128e5ec13458ec2dd841aa Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Wed, 5 Aug 2026 09:12:20 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20organisations=C3=BCbergreifende=20Ger?= =?UTF-8?q?=C3=A4teliste=20(Kundenplattform-Admin)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neuer Endpoint GET /api/v1/devices (alle Geräte, Organisationsname gejoint) für den Admin-Bereich "Verwaltung -> Geräte". Co-Authored-By: Claude Sonnet 5 --- app.py | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/app.py b/app.py index 8b7703f..8c0698b 100644 --- a/app.py +++ b/app.py @@ -603,6 +603,41 @@ def fetch_devices_for_organization(organization_id: str): for device_id, hostname, fingerprint, last_checkin in cur.fetchall() ] +def fetch_all_devices(): + """ + Organisationsübergreifende Geräteliste für den Kundenplattform-Admin- + Bereich (Verwaltung -> Geräte) - Pendant zu fetch_devices_for_organization, + ohne Org-Filter, mit Organisationsname gejoint. + """ + + with get_database_connection() as conn: + with conn.cursor() as cur: + cur.execute( + """ + SELECT d.id, d.hostname, d.device_fingerprint, d.agent_last_checkin, + d.organization_id, o.name + FROM devices d + JOIN organizations o ON o.id = d.organization_id + ORDER BY o.name, d.hostname NULLS LAST, d.created_at + """ + ) + return [ + { + "id": str(device_id), + "hostname": hostname, + "device_fingerprint": fingerprint, + "agent_last_checkin": ( + last_checkin.isoformat() if last_checkin is not None else None + ), + "organization_id": str(organization_id), + "organization_name": organization_name, + } + for ( + device_id, hostname, fingerprint, last_checkin, + organization_id, organization_name, + ) in cur.fetchall() + ] + def fetch_organizations(): with get_database_connection() as conn: with conn.cursor() as cur: @@ -962,6 +997,18 @@ def get_organization_devices( return {"success": True, "devices": fetch_devices_for_organization(organization_id)} +@app.get("/api/v1/devices") +def list_all_devices(authorization: str | None = Header(default=None)): + if not require_service_token(authorization): + return { + "success": False, + "error": "unauthorized", + "message": "Fehlendes oder ungültiges Service-Token.", + } + + return {"success": True, "devices": fetch_all_devices()} + + @app.get("/api/v1/organizations") def list_organizations(authorization: str | None = Header(default=None)): if not require_service_token(authorization):