Ausgegebene Medien löschen, Gerät löschen deprovisioniert zusätzlich
DELETE /api/v1/organizations/<org>/enrollment-sessions/<id> entfernt nur nicht mehr nutzbare Medien (widerrufen, abgelaufen, aufgebraucht). archive_device() entzieht jetzt auch das Agent-Secret: ein gelöschtes Gerät checkte bisher weiter ein (Liebherr-47, 03.10.2026). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5284bb470b
commit
2f6dfd585b
1 file changed
+61
-1
@@ -3830,6 +3830,11 @@ def archive_device(device_id: str) -> bool:
|
|||||||
aus fetch_devices_for_organization()/fetch_all_devices(), Datensatz und
|
aus fetch_devices_for_organization()/fetch_all_devices(), Datensatz und
|
||||||
Historie (hardware_snapshots, device_merkmal_events) bleiben in der DB
|
Historie (hardware_snapshots, device_merkmal_events) bleiben in der DB
|
||||||
erhalten.
|
erhalten.
|
||||||
|
|
||||||
|
Seit 23.10.2026 zugleich deprovisioniert (wie deprovision_device()):
|
||||||
|
Vorher checkte ein gelöschtes Gerät weiter ein und wurde unsichtbar
|
||||||
|
weiterverwaltet (Liebherr-47, gelöscht 03.10. 13:56, Check-in 16:24).
|
||||||
|
Eine Neuinstallation (/api/v1/activate) setzt beides wieder zurück.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
with get_database_connection() as conn:
|
with get_database_connection() as conn:
|
||||||
@@ -3837,7 +3842,9 @@ def archive_device(device_id: str) -> bool:
|
|||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
UPDATE devices
|
UPDATE devices
|
||||||
SET archived_at = CURRENT_TIMESTAMP
|
SET archived_at = CURRENT_TIMESTAMP,
|
||||||
|
deprovisioned_at = COALESCE(deprovisioned_at, CURRENT_TIMESTAMP),
|
||||||
|
agent_secret_hash = NULL, agent_secret_issued_at = NULL
|
||||||
WHERE id = %s AND archived_at IS NULL
|
WHERE id = %s AND archived_at IS NULL
|
||||||
RETURNING id
|
RETURNING id
|
||||||
""",
|
""",
|
||||||
@@ -5736,6 +5743,35 @@ def revoke_enrollment_session(session_id: str):
|
|||||||
)
|
)
|
||||||
return cur.fetchone() is not None
|
return cur.fetchone() is not None
|
||||||
|
|
||||||
|
def delete_enrollment_session(organization_id: str, session_id: str) -> str:
|
||||||
|
"""
|
||||||
|
GUI-Runde 23.10.2026: "Ausgegebene Medien" verwalten. Gelöscht wird nur,
|
||||||
|
was ohnehin nicht mehr installieren kann (widerrufen, abgelaufen oder
|
||||||
|
Kontingent aufgebraucht) - ein noch gültiges Medium muss erst
|
||||||
|
deaktiviert werden. Nichts verweist per Fremdschlüssel auf die Session;
|
||||||
|
installierte Geräte bleiben unberührt. Rückgabe: "geloescht",
|
||||||
|
"nicht_gefunden" oder "noch_gueltig".
|
||||||
|
"""
|
||||||
|
|
||||||
|
with get_database_connection() as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
DELETE FROM enrollment_sessions
|
||||||
|
WHERE id = %s AND organization_id = %s
|
||||||
|
AND (revoked_at IS NOT NULL OR expires_at <= CURRENT_TIMESTAMP OR devices_used >= max_devices)
|
||||||
|
RETURNING id
|
||||||
|
""",
|
||||||
|
(session_id, organization_id),
|
||||||
|
)
|
||||||
|
if cur.fetchone() is not None:
|
||||||
|
return "geloescht"
|
||||||
|
cur.execute(
|
||||||
|
"SELECT 1 FROM enrollment_sessions WHERE id = %s AND organization_id = %s",
|
||||||
|
(session_id, organization_id),
|
||||||
|
)
|
||||||
|
return "noch_gueltig" if cur.fetchone() is not None else "nicht_gefunden"
|
||||||
|
|
||||||
def recharge_enrollment_session(session_id: str, additional_devices: int, expires_at: str | None):
|
def recharge_enrollment_session(session_id: str, additional_devices: int, expires_at: str | None):
|
||||||
"""
|
"""
|
||||||
Phase 5 (Kundenplattform-Selfservice): eine bereits ausgeteilte,
|
Phase 5 (Kundenplattform-Selfservice): eine bereits ausgeteilte,
|
||||||
@@ -8829,6 +8865,30 @@ def revoke_enrollment_session_endpoint(session_id: str, authorization: str | Non
|
|||||||
return {"success": True}
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/api/v1/organizations/{organization_id}/enrollment-sessions/{session_id}")
|
||||||
|
def delete_enrollment_session_endpoint(
|
||||||
|
organization_id: str, session_id: str, authorization: str | None = Header(default=None)
|
||||||
|
):
|
||||||
|
if not require_service_token(authorization):
|
||||||
|
return {"success": False, "error": "unauthorized", "message": "Fehlendes oder ungültiges Service-Token."}
|
||||||
|
|
||||||
|
try:
|
||||||
|
UUID(session_id)
|
||||||
|
except ValueError:
|
||||||
|
return {"success": False, "error": "not_found", "message": "Installationsmedium wurde nicht gefunden."}
|
||||||
|
|
||||||
|
ergebnis = delete_enrollment_session(organization_id, session_id)
|
||||||
|
if ergebnis == "nicht_gefunden":
|
||||||
|
return {"success": False, "error": "not_found", "message": "Installationsmedium wurde nicht gefunden."}
|
||||||
|
if ergebnis == "noch_gueltig":
|
||||||
|
return {
|
||||||
|
"success": False, "error": "noch_gueltig",
|
||||||
|
"message": "Das Medium ist noch gültig. Deaktiviere es zuerst, dann kannst du es löschen.",
|
||||||
|
}
|
||||||
|
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
|
||||||
@app.patch("/api/v1/enrollment-sessions/{session_id}")
|
@app.patch("/api/v1/enrollment-sessions/{session_id}")
|
||||||
def recharge_enrollment_session_endpoint(
|
def recharge_enrollment_session_endpoint(
|
||||||
session_id: str,
|
session_id: str,
|
||||||
|
|||||||
Reference in new issue
Block a user