feat: Rueckfrage, bevor jemand von der Zentrale verdraengt wird

Ein einzelner Klick konnte den aktuellen Besetzer der Zentrale verdraengen.
Sitzt dort jemand anderes, kommt jetzt erst eine Rueckfrage, die die
betroffene Person nennt und sagt, was mit ihr passiert - je nach Lage
Rueckstellung auf das eigene Tuerschild, Vermerk als Stamm-Besetzer, oder
der Hinweis dass sie ohnehin dorthin gehoert. Ist die Zentrale frei, wird
ohne Rueckfrage besetzt.

Eine Rueckgabe zu erzwingen waere die naheliegende Alternative, wurde aber
bewusst nicht gebaut: wer abends ohne Freigabe nach Hause geht, wuerde die
Zentrale damit sperren. Am naechsten Morgen koennte niemand den Empfang
besetzen, weil der Vorgaenger nicht da ist um freizugeben. Genau diese
Sperre soll das Feature vermeiden.

Nebenbei eine Ungenauigkeit behoben: die Seite hat behauptet, der Besetzer
werde "auf das eigene Tuerschild zurueckgesetzt" - auch dann, wenn er gar
keines hat. Die drei Faelle werden jetzt unterschieden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 09:14:45 +00:00
co-authored by Claude Opus 5
parent 0867221a3c
commit 5d2bd8eff8
3 changed files with 82 additions and 12 deletions
+22 -7
View File
@@ -608,7 +608,7 @@ def _zentrale_state(conn, target, user):
st = {
"occupant": None, "is_here": False, "home": None,
"home_blocker": None, "is_owner": False, "owner_waiting": None,
"occupant_is_owner": False,
"occupant_is_owner": False, "occupant_has_home": False,
}
if not target:
return st
@@ -626,10 +626,12 @@ def _zentrale_state(conn, target, user):
# Sitzt der aktuelle Besetzer auf seinem Stammplatz? Dann kommt er nach einer
# Uebernahme von allein zurueck - das gehoert auf den Knopf geschrieben.
if st["occupant"]:
st["occupant_is_owner"] = conn.execute("""
SELECT 1 FROM home_assignments
WHERE user_azure_id = ? AND wled_device_id = ? AND segment = ?
""", (st["occupant"]["azure_id"], target["id"], target["segment"])).fetchone() is not None
occ_home = conn.execute("""
SELECT wled_device_id, segment FROM home_assignments WHERE user_azure_id = ?
""", (st["occupant"]["azure_id"],)).fetchone()
st["occupant_has_home"] = occ_home is not None
st["occupant_is_owner"] = bool(occ_home) and \
(occ_home["wled_device_id"], occ_home["segment"]) == (target["id"], target["segment"])
if not user:
return st
@@ -702,8 +704,13 @@ async def zentrale_page_for_extension(request: Request, extension: str):
@app.post("/api/zentrale/uebernehmen")
async def zentrale_takeover(extension: str = Form(...)):
"""Mitarbeiter setzt sich selbst auf das Busylight der Zentrale."""
async def zentrale_takeover(extension: str = Form(...), confirm: str = Form("")):
"""Mitarbeiter setzt sich selbst auf das Busylight der Zentrale.
Sitzt bereits jemand anderes darauf, braucht es eine ausdrueckliche
Bestaetigung. Eine Rueckgabe zu erzwingen waere die Alternative, wuerde die
Zentrale aber sperren, sobald jemand ohne Freigabe nach Hause geht.
"""
conn = database.get_db()
try:
target = _selfservice_target(conn)
@@ -714,6 +721,14 @@ async def zentrale_takeover(extension: str = Form(...)):
if not user:
return _zentrale_redirect(extension, "err_unbekannt")
if confirm != "ja":
besetzt = conn.execute("""
SELECT 1 FROM assignments
WHERE wled_device_id = ? AND segment = ? AND user_azure_id != ?
""", (target["id"], target["segment"], user["azure_id"])).fetchone()
if besetzt:
return _zentrale_redirect(extension, "bestaetigen")
already = conn.execute("""
SELECT 1 FROM assignments
WHERE user_azure_id = ? AND wled_device_id = ? AND segment = ?