From 426e36905df79b675273ec26941ef0fe03b08366 Mon Sep 17 00:00:00 2001 From: Christian Mueller Date: Fri, 21 Aug 2026 09:19:59 +0000 Subject: [PATCH] fix: alles auf eine Adresse, Rueckfrage wieder entfernt Die Zustandsseite /zentrale/{durchwahl} war ein Fehlgriff. Sie wurde als "Adresse fuer den Alltag" eingefuehrt und war damit eine zweite URL, die man sich merken muss. Wer sie nicht hatte, kam nicht mehr aus der Zentrale heraus: auf /zentrale sah man nur, dass jemand anderes eingetragen ist, ohne einen Weg zum Freigeben. Jetzt gibt es genau eine Adresse. Auf /zentrale die eigene Durchwahl eintragen, und die Seite zeigt die Knoepfe, die fuer diese Person gerade gelten - derselbe Weg fuehrt zum Uebernehmen und zum Freigeben. Das Durchwahl-Feld ist immer da, auch wenn die Zentrale besetzt ist, und der Hilfetext nennt beide Wege. - /zentrale/{durchwahl} bleibt als Kurzform fuer QR-Codes, leitet aber nur auf /zentrale?durchwahl=... um - alle Aktionen leiten auf /zentrale zurueck statt auf eine Unterseite - der Knopf heisst "Zentrale freigeben" statt "Zurueck auf mein Tuerschild", weil das die Sicht des Bedienenden ist - kein Hinweis mehr, sich eine persoenliche Adresse als Lesezeichen zu merken - das war die Ursache der Verwirrung Die Bestaetigungsstufe vor dem Verdraengen ist wieder raus, sie war nicht gewuenscht. Die Unterscheidung der drei Faelle am Knopf bleibt, damit sichtbar ist, was mit dem bisherigen Besetzer passiert. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 189 +++++++++++++++++++++++++++++++++++++++- app.py | 60 +++++-------- templates/zentrale.html | 107 +++++++++-------------- 3 files changed, 251 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 4ec237b..ba6e52b 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,187 @@ erreichbar ist und die Durchwahl als Kennung nutzt. ### Bedienung +Es gibt genau **eine** Adresse: + +``` +http://SERVER:8080/zentrale +``` + +Durchwahl eintragen, **Weiter** klicken - die Seite zeigt dann, was fuer diese Person +gerade gilt. Derselbe Weg fuehrt zum Uebernehmen und zum Freigeben, es muss sich also +niemand eine zweite, persoenliche Adresse gemerkt haben, um die Zentrale wieder +loszuwerden. + +| Lage | Angebot | +|------|---------| +| Zentrale frei | **Zentrale besetzen** | +| jemand anderes sitzt darauf | **Zentrale uebernehmen**, mit Hinweis was mit dieser Person passiert | +| man sitzt selbst darauf | **Zentrale freigeben** | +| es ist der eigene Stammplatz | kein Knopf, nur der Hinweis dass nichts zu tun ist | + +Wer gerade auf der Zentrale sitzt, steht immer oben auf der Seite - auch ohne +Durchwahl. Wartet jemand auf seine Rueckkehr, steht das ebenfalls dort. + +Jede Aktion leitet auf `/zentrale` zurueck (POST/Redirect/GET). Man landet also nie auf +einer Formular-Antwort, die beim Neuladen die Aktion wiederholen wuerde. + +Fuer QR-Codes pro Person gibt es die Kurzform `/zentrale/{durchwahl}`. Sie leitet +lediglich auf `/zentrale?durchwahl=...` um - es bleibt bei der einen Seite. + +### Verhalten + +- `callstart`: Setzt WLED auf Telefon-Farbe (Standard: Rot), aber **nur** wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist +- `callend`: Setzt WLED zurueck auf den Zeiterfassungs-Status. Der Teams-Status wird beim naechsten Polling-Zyklus (15s) automatisch aktualisiert +- Waehrend eines aktiven Telefonats ueberschreibt das Teams-Polling die Farbe nicht +- Die Telefon-Farbe (`phone_active`) ist unter **Farb-Regeln** konfigurierbar + +## Logo + +Unter **Einstellungen > Logo** kann ein kundenspezifisches Logo hochgeladen werden. Es +erscheint in der Seitenleiste, auf der Login-Seite und auf der Zentrale-Seite. + +- Formate: PNG, JPG, SVG, WEBP, GIF, maximal 2 MB +- Dargestellt wird eine Hoehe von etwa 40 Pixeln. Die Seitenleiste ist dunkel, ein Logo + mit heller Schrift oder transparentem Hintergrund wirkt dort am besten - die + Einstellungsseite zeigt eine Vorschau auf hellem und dunklem Grund. +- Die Datei liegt unter `static/custom/` und ist per `.gitignore` von der Versionierung + ausgenommen. **Ein `git pull` ueberschreibt das Kundenlogo nicht.** +- Mit **Zurueck zum Standardlogo** wird die Datei entfernt und wieder + `static/logo.png` aus dem Repository verwendet. + +## Zentrale (Self-Service) + +Ein Busylight im Empfangsbereich wird wechselnd besetzt. Damit die Mitarbeiter das +selbst umstellen koennen, gibt es eine eigene Seite, die **ohne Admin-Passwort** +erreichbar ist und die Durchwahl als Kennung nutzt. + +### Einrichtung + +1. Unter **Benutzer** die **Durchwahl** pro Mitarbeiter eintragen (dieselbe wie fuer den Telefon-Webhook) +2. Unter **Einstellungen > Zentrale (Self-Service)** das Busylight des Empfangs und das Segment auswaehlen +3. Die Seite `http://SERVER:8080/zentrale` an die Mitarbeiter geben + +### Bedienung + +``` +http://SERVER:8080/zentrale - Durchwahl eingeben +http://SERVER:8080/zentrale/{durchwahl} - Zustandsseite pro Person, als Lesezeichen + oder QR-Code +``` + +Die Bedienung laeuft in zwei Schritten. Auf `/zentrale` gibt man seine Durchwahl ein +und landet auf der eigenen Zustandsseite `/zentrale/{durchwahl}`. Dort steht, wer +gerade auf der Zentrale sitzt und welche Knoepfe zur Verfuegung stehen - geaendert +wird erst per Klick. + +Die Zustandsseite ist die eigentliche Adresse fuer den Alltag und als Lesezeichen +gedacht. Sie zeigt immer den echten Zustand, passt die Knoepfe daran an und ist +gefahrlos neu ladbar: + +| Lage | Angebot | +|------|---------| +| Zentrale frei | **Zentrale besetzen**, ohne Rueckfrage | +| jemand anderes sitzt darauf | **Zentrale uebernehmen** mit Rueckfrage, siehe unten | +| man sitzt selbst darauf | **Zurueck auf mein Tuerschild** | +| es ist der eigene Stammplatz | kein Knopf, nur der Hinweis dass nichts zu tun ist | + +### Verhalten + +- `callstart`: Setzt WLED auf Telefon-Farbe (Standard: Rot), aber **nur** wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist +- `callend`: Setzt WLED zurueck auf den Zeiterfassungs-Status. Der Teams-Status wird beim naechsten Polling-Zyklus (15s) automatisch aktualisiert +- Waehrend eines aktiven Telefonats ueberschreibt das Teams-Polling die Farbe nicht +- Die Telefon-Farbe (`phone_active`) ist unter **Farb-Regeln** konfigurierbar + +## Logo + +Unter **Einstellungen > Logo** kann ein kundenspezifisches Logo hochgeladen werden. Es +erscheint in der Seitenleiste, auf der Login-Seite und auf der Zentrale-Seite. + +- Formate: PNG, JPG, SVG, WEBP, GIF, maximal 2 MB +- Dargestellt wird eine Hoehe von etwa 40 Pixeln. Die Seitenleiste ist dunkel, ein Logo + mit heller Schrift oder transparentem Hintergrund wirkt dort am besten - die + Einstellungsseite zeigt eine Vorschau auf hellem und dunklem Grund. +- Die Datei liegt unter `static/custom/` und ist per `.gitignore` von der Versionierung + ausgenommen. **Ein `git pull` ueberschreibt das Kundenlogo nicht.** +- Mit **Zurueck zum Standardlogo** wird die Datei entfernt und wieder + `static/logo.png` aus dem Repository verwendet. + +## Zentrale (Self-Service) + +Ein Busylight im Empfangsbereich wird wechselnd besetzt. Damit die Mitarbeiter das +selbst umstellen koennen, gibt es eine eigene Seite, die **ohne Admin-Passwort** +erreichbar ist und die Durchwahl als Kennung nutzt. + +### Einrichtung + +1. Unter **Benutzer** die **Durchwahl** pro Mitarbeiter eintragen (dieselbe wie fuer den Telefon-Webhook) +2. Unter **Einstellungen > Zentrale (Self-Service)** das Busylight des Empfangs und das Segment auswaehlen +3. Die Seite `http://SERVER:8080/zentrale` an die Mitarbeiter geben + +### Bedienung + +Es gibt genau **eine** Adresse: + +``` +http://SERVER:8080/zentrale +``` + +Durchwahl eintragen, **Weiter** klicken - die Seite zeigt dann, was fuer diese Person +gerade gilt. Derselbe Weg fuehrt zum Uebernehmen und zum Freigeben, es muss sich also +niemand eine zweite, persoenliche Adresse gemerkt haben, um die Zentrale wieder +loszuwerden. + +| Lage | Angebot | +|------|---------| +| Zentrale frei | **Zentrale besetzen** | +| jemand anderes sitzt darauf | **Zentrale uebernehmen**, mit Hinweis was mit dieser Person passiert | +| man sitzt selbst darauf | **Zentrale freigeben** | +| es ist der eigene Stammplatz | kein Knopf, nur der Hinweis dass nichts zu tun ist | + +Wer gerade auf der Zentrale sitzt, steht immer oben auf der Seite - auch ohne +Durchwahl. Wartet jemand auf seine Rueckkehr, steht das ebenfalls dort. + +Jede Aktion leitet auf `/zentrale` zurueck (POST/Redirect/GET). Man landet also nie auf +einer Formular-Antwort, die beim Neuladen die Aktion wiederholen wuerde. + +Fuer QR-Codes pro Person gibt es die Kurzform `/zentrale/{durchwahl}`. Sie leitet +lediglich auf `/zentrale?durchwahl=...` um - es bleibt bei der einen Seite. + +### Verhalten + +- `callstart`: Setzt WLED auf Telefon-Farbe (Standard: Rot), aber **nur** wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist +- `callend`: Setzt WLED zurueck auf den Zeiterfassungs-Status. Der Teams-Status wird beim naechsten Polling-Zyklus (15s) automatisch aktualisiert +- Waehrend eines aktiven Telefonats ueberschreibt das Teams-Polling die Farbe nicht +- Die Telefon-Farbe (`phone_active`) ist unter **Farb-Regeln** konfigurierbar + +## Logo + +Unter **Einstellungen > Logo** kann ein kundenspezifisches Logo hochgeladen werden. Es +erscheint in der Seitenleiste, auf der Login-Seite und auf der Zentrale-Seite. + +- Formate: PNG, JPG, SVG, WEBP, GIF, maximal 2 MB +- Dargestellt wird eine Hoehe von etwa 40 Pixeln. Die Seitenleiste ist dunkel, ein Logo + mit heller Schrift oder transparentem Hintergrund wirkt dort am besten - die + Einstellungsseite zeigt eine Vorschau auf hellem und dunklem Grund. +- Die Datei liegt unter `static/custom/` und ist per `.gitignore` von der Versionierung + ausgenommen. **Ein `git pull` ueberschreibt das Kundenlogo nicht.** +- Mit **Zurueck zum Standardlogo** wird die Datei entfernt und wieder + `static/logo.png` aus dem Repository verwendet. + +## Zentrale (Self-Service) + +Ein Busylight im Empfangsbereich wird wechselnd besetzt. Damit die Mitarbeiter das +selbst umstellen koennen, gibt es eine eigene Seite, die **ohne Admin-Passwort** +erreichbar ist und die Durchwahl als Kennung nutzt. + +### Einrichtung + +1. Unter **Benutzer** die **Durchwahl** pro Mitarbeiter eintragen (dieselbe wie fuer den Telefon-Webhook) +2. Unter **Einstellungen > Zentrale (Self-Service)** das Busylight des Empfangs und das Segment auswaehlen +3. Die Seite `http://SERVER:8080/zentrale` an die Mitarbeiter geben + +### Bedienung + ``` http://SERVER:8080/zentrale - Durchwahl eingeben http://SERVER:8080/zentrale/{durchwahl} - Zustandsseite pro Person, als Lesezeichen @@ -387,11 +568,11 @@ busylight/ - Unter Tuerschilder den Status pruefen ("Alle jetzt pruefen") - Netzwerkverbindung pruefen: `curl http://HOSTNAME/json/info` -### Auf /zentrale fehlt der Knopf zum Zurueckgeben +### Wie gibt man die Zentrale wieder frei? -Der ist absichtlich erst auf der Zustandsseite `/zentrale/{durchwahl}` zu sehen, denn -vorher weiss die Anwendung nicht, wer zurueckgeben will. Durchwahl eingeben, **Weiter** -klicken - dann erscheint der passende Knopf. +Auf `/zentrale` die eigene Durchwahl eintragen und **Weiter** klicken - dann erscheint +**Zentrale freigeben**. Es ist derselbe Weg wie beim Uebernehmen, eine gemerkte Adresse +braucht es nicht. ### Zentrale-Seite sagt "noch nicht eingerichtet" diff --git a/app.py b/app.py index e189d2b..8823b30 100644 --- a/app.py +++ b/app.py @@ -666,51 +666,47 @@ def _zentrale_page(request, conn, target, extension="", user=None, done=None): def _zentrale_redirect(extension, done): - """Nach jeder Aktion zurueck auf die Zustandsseite (POST/Redirect/GET).""" + """Nach jeder Aktion zurueck auf /zentrale (POST/Redirect/GET). + + Es gibt absichtlich nur diese eine Adresse: wer die Zentrale freigeben will, + soll sich keine zweite URL gemerkt haben muessen. + """ ext = quote((extension or "").strip(), safe="") if not ext: return RedirectResponse(f"/zentrale?done={done}", status_code=303) - return RedirectResponse(f"/zentrale/{ext}?done={done}", status_code=303) + return RedirectResponse(f"/zentrale?durchwahl={ext}&done={done}", status_code=303) @app.get("/zentrale", response_class=HTMLResponse) async def zentrale_page(request: Request): - """Self-Service-Seite fuer den Empfangsbereich. Absichtlich ohne Admin-Login.""" - # Das Formular schickt die Durchwahl per GET - auf die Personenseite umleiten, - # damit die Adresse merkbar und neu ladbar ist. + """Self-Service-Seite fuer den Empfangsbereich. Absichtlich ohne Admin-Login. + + Die eine Adresse fuer alles: Durchwahl eintragen, und die Seite zeigt die + Knoepfe, die fuer diese Person gerade gelten - Uebernehmen oder Freigeben. + """ typed = (request.query_params.get("durchwahl") or "").strip() - if typed: - return RedirectResponse(f"/zentrale/{quote(typed, safe='')}", status_code=303) + done = request.query_params.get("done") - conn = database.get_db() - try: - return _zentrale_page(request, conn, _selfservice_target(conn), - done=request.query_params.get("done")) - finally: - conn.close() - - -@app.get("/zentrale/{extension}", response_class=HTMLResponse) -async def zentrale_page_for_extension(request: Request, extension: str): - """Zustandsseite pro Mitarbeiter. Zeigt nur an, geaendert wird per Knopf.""" conn = database.get_db() try: target = _selfservice_target(conn) - user = _user_by_extension(extension, conn) - done = request.query_params.get("done") if user else "err_unbekannt" - return _zentrale_page(request, conn, target, extension=extension, user=user, done=done) + user = _user_by_extension(typed, conn) if typed else None + if typed and not user and not done: + done = "err_unbekannt" + return _zentrale_page(request, conn, target, extension=typed, user=user, done=done) finally: conn.close() -@app.post("/api/zentrale/uebernehmen") -async def zentrale_takeover(extension: str = Form(...), confirm: str = Form("")): - """Mitarbeiter setzt sich selbst auf das Busylight der Zentrale. +@app.get("/zentrale/{extension}") +async def zentrale_page_for_extension(extension: str): + """Kurzform fuer QR-Codes. Leitet auf die eine Adresse um.""" + return RedirectResponse(f"/zentrale?durchwahl={quote(extension, safe='')}", status_code=303) - 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. - """ + +@app.post("/api/zentrale/uebernehmen") +async def zentrale_takeover(extension: str = Form(...)): + """Mitarbeiter setzt sich selbst auf das Busylight der Zentrale.""" conn = database.get_db() try: target = _selfservice_target(conn) @@ -721,14 +717,6 @@ async def zentrale_takeover(extension: str = Form(...), confirm: 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 = ? diff --git a/templates/zentrale.html b/templates/zentrale.html index 1d9865b..19d9894 100644 --- a/templates/zentrale.html +++ b/templates/zentrale.html @@ -70,8 +70,8 @@ {{ target.name }} (Segment {{ target.segment }})
+ Aktuell besetzt von {% if occupant %} - Aktuell besetzt von {{ occupant.display_name }} {%- if is_here %} das bist du{% endif %} @@ -80,7 +80,6 @@
Das ist der Stammplatz dieser Person.
{% endif %} {% else %} - Aktuell besetzt von niemand - die Zentrale ist frei {% endif %} {% if owner_waiting %} @@ -93,30 +92,37 @@ {% if not user %} - {# ── Schritt 1: Wer bist du? ──────────────────────────────────── #} + {# ── Eintritt: Durchwahl. Derselbe Weg fuer Uebernehmen und Freigeben. ── #}
- + - Im naechsten Schritt siehst du, was du tun kannst - es wird noch nichts geaendert. + {% if occupant %} + Damit uebernimmst du die Zentrale - oder gibst sie frei, wenn du selbst + eingetragen bist. Im naechsten Schritt siehst du, was fuer dich gilt. + {% else %} + Damit besetzt du die Zentrale. Im naechsten Schritt siehst du, was fuer + dich gilt - geaendert wird noch nichts. + {% endif %}
+ {% else %} - {# ── Schritt 2: Zustand und passende Aktionen ──────────────────── #} + {# ── Zustand dieser Person und die passenden Knoepfe ──────────────── #}
Durchwahl {{ user.phone_extension }} {{ user.display_name }}
{% if is_owner and is_here %} -
+
Die Zentrale ist dein eigener Platz und du sitzt darauf. Hier ist nichts zu tun - jemand anderes kann sie jederzeit uebernehmen, @@ -136,50 +142,17 @@
{% if home_blocker %} -
+
Achtung: dein Tuerschild ist derzeit {{ home_blocker }} zugeordnet. Die Rueckkehr wird abgelehnt, solange das so ist.
{% endif %} - {% elif done == 'bestaetigen' and occupant %} - {# Zweiter Schritt: verdraengen ist nie ein Versehen #} -
- Wirklich uebernehmen? -
- {{ occupant.display_name }} ist derzeit auf der Zentrale - eingetragen. Bitte nur uebernehmen, wenn diese Person den Empfang - tatsaechlich verlassen hat. -
- {% if occupant_is_owner %} - {{ occupant.display_name }} gehoert auf die Zentrale und kommt automatisch - zurueck, sobald du sie wieder freigibst. - {% elif occupant_has_home %} - {{ occupant.display_name }} wird dabei auf das eigene Tuerschild - zurueckgesetzt. - {% else %} - {{ occupant.display_name }} hat kein eigenes Tuerschild und gehoert damit - auf die Zentrale. Die Person wird als Stamm-Besetzer vermerkt und kommt - automatisch zurueck, sobald du wieder freigibst. - {% endif %} -
-
-
- - - -
- - Abbrechen - - {% else %}
@@ -189,16 +162,14 @@ {% if occupant and occupant_is_owner %} - {{ occupant.display_name }} sitzt darauf und gehoert dorthin. Nach einer - Uebernahme kommt sie oder er automatisch zurueck, sobald du freigibst. - Du wirst noch um Bestaetigung gebeten. + {{ occupant.display_name }} gehoert auf die Zentrale und kommt automatisch + zurueck, sobald du wieder freigibst. {% elif occupant and occupant_has_home %} - {{ occupant.display_name }} sitzt darauf und wird dabei auf das eigene - Tuerschild zurueckgesetzt. Du wirst noch um Bestaetigung gebeten. + {{ occupant.display_name }} wird dabei auf das eigene Tuerschild + zurueckgesetzt. {% elif occupant %} - {{ occupant.display_name }} sitzt darauf und gehoert auf die Zentrale, - kommt also automatisch zurueck, sobald du freigibst. - Du wirst noch um Bestaetigung gebeten. + {{ occupant.display_name }} hat kein eigenes Tuerschild und gehoert damit + auf die Zentrale - kommt also automatisch zurueck, sobald du freigibst. {% else %} Die Zentrale ist frei. {% endif %} @@ -206,11 +177,11 @@ {% if home %} -
+ + - Gemerkt: {{ home.name or home.hostname }}, Segment {{ home.segment }}. @@ -218,23 +189,29 @@ {% endif %} {% endif %} - -
- - Diese Seite als Lesezeichen: /zentrale/{{ user.phone_extension }} - -
- {% endif %} + {# ── Andere Person: dasselbe Formular, dieselbe Adresse ──────────── #} +
+ +
+ + +
+
+ +
+
{% endif %}
- © cynfo GmbH + + Zentrale-Seite neu laden + +
+ © cynfo GmbH +
+ {% endif %}