Commit Graph

54 Commits

Author SHA1 Message Date
Erik Thiele
cbadf096fd fix: Loeschen entfernt auch den Playlist-Eintrag der Datei
Der Filter in delete_file verglich nur item["url"], traf damit aber nur
URL-Eintraege. Bei Dateien wurde die Datei vom Datentraeger geloescht,
der Eintrag {"name": ...} blieb als Karteileiche in der config.json
stehen - in der Priority-Playlist wie in jeder Screen-Playlist.
Vergleich laeuft jetzt ueber playlist_item_name(), das alle drei
Eintragsformen abdeckt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:09:37 +02:00
Erik Thiele
ccfd90d4b5 chore: Version auf 6.2.6 heben 2026-09-08 09:04:38 +02:00
Erik Thiele
03ae5bf4ad feat: Priority-Eintraege in den Screen-Playlisten anzeigen
Die Priority-Playlist gilt fuer alle Screens eines Standorts, liegt aber
in einem eigenen Menuepunkt und wurde beim Bearbeiten der normalen
Playlisten leicht uebersehen. Sie erscheint jetzt oberhalb jeder
Screen-Playlist als abgesetzte, ausgegraute Liste mit Prio-Badge.

Reine Anzeige: keine Checkbox, keine Buttons, kein Drag. Die Zeilen
liegen bewusst in einer eigenen ul ausserhalb von #playlist-<screen>,
damit savePlaylist() sie nicht mit einsammelt. Sichtbar nur, wenn die
Priority-Playlist des Standorts aktiviert ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 09:04:38 +02:00
Erik Thiele
aeab158e47 fix: Aktiv-Haken zeigt gespeicherten Status statt Zeitfenster
Die Admin-Ansicht hat der Checkbox das Ergebnis von is_item_active()
uebergeben. Ausserhalb des Zeitfensters erschien ein zeitgesteuerter
Eintrag dadurch als deaktiviert, und beim naechsten Speichern der
Reihenfolge schrieb der Client diesen Anzeigezustand als enabled=false
zurueck - der Eintrag war danach dauerhaft stillgelegt.

Die Checkbox spiegelt jetzt das gespeicherte enabled-Flag. Der
Live-Zustand steckt in einem neuen Feld active und faerbt nur noch das
Zeit-Badge (grau, wenn das Fenster gerade zu ist). Der Player filtert
entsprechend ueber beide Felder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 08:47:43 +02:00
Erik Thiele
c56006c18d fix: Trusted Device bei MFA zuverlaessig speichern und pruefen
- Dropdown fuer die Merk-Dauer aktiviert jetzt die Checkbox mit; bisher
  wurde die Auswahl ohne gesetzten Haken verworfen und trotzdem nach
  jedem Login ein Code verlangt.
- Abgelaufene oder defekte Trusted-Device-Eintraege fuehrten beim Login
  zu einem NameError (users_data war nicht geladen); Bereinigung neu
  geschrieben.
- Cookie erhaelt das Secure-Flag, wenn die Verbindung HTTPS ist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:46:09 +02:00
Erik Thiele
ac343cef67 chore: Version auf 6.2.3 heben
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 12:18:22 +02:00
Erik Thiele
af308535fe fix: Standort ueber Seiten ohne Standortbezug hinweg merken
Wer von Stuttgart aus das Admin-Dashboard oeffnete, sah im Header
ploetzlich Karlsruhe - und landete beim Zurueckgehen ueber die
Standortauswahl dort. Grund: Dashboard, Hilfe, User-Verwaltung und die
MFA-Seiten setzten current_site fest auf get_site_list(cfg)[0], also den
global ersten Standort. Der Context-Processor tat dasselbe, fuer
angemeldete User sogar unabhaengig davon, ob sie auf diesen Standort
ueberhaupt zugreifen duerfen.

- remember_site() legt den zuletzt besuchten Standort in der Session ab;
  aufgerufen aus admin(), admin_priority() und add_customer().
- current_site_for() liefert diesen Standort, sonst den ersten
  *zugaenglichen*. Verwendet vom Context-Processor und den genannten
  Seiten.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 11:59:58 +02:00
Erik Thiele
d2938f87f3 fix: Priority-Playlist je Standort statt global
Die Priority-Playlist lag unter config["priority"] und wirkte damit auf
*alle* Standorte. In der Praxis lief so ein Stuttgart-spezifischer
Eintrag (wbxroompresence...find=Stuttgart) auch auf den Karlsruher
Screens.

Sie liegt jetzt unter sites.<site>.priority, die Medien unter
media/<site>/priority/:
- get_priority_config(cfg, site) liefert die Konfiguration des
  Standorts. Ist dort nichts hinterlegt, wird ein globaler Altbestand
  einmalig uebernommen - per deepcopy, damit spaetere Aenderungen nicht
  zwischen Standorten durchschlagen.
- load_priority_files(site), priority_dir(site) sowie Player, Hash,
  Upload, Loeschen, URL-Anlegen, Umsortieren und Einzeleintrag-
  Bearbeitung arbeiten durchgaengig standortbezogen.
- Route /media/priority/<datei> -> /media/<site>/priority/<datei>,
  Templates entsprechend.
- Der Ordnername "priority" ist wie "logos" in der Screen-Erkennung
  ausgenommen. media/<site>/priority/ waere sonst als Screen in der
  Konfiguration gelandet; "priority" ist in den Routen ohnehin als
  Kennzeichen belegt, ein Screen dieses Namens war nie moeglich.

Migration der vorhandenen Konfiguration: der globale Block wurde in alle
drei Standorte uebernommen und der globale Schluessel entfernt. Der
leere globale Ordner media/priority/ ist entfallen.

README, AGENTS.md und Hilfeseite nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 10:32:27 +02:00
Erik Thiele
1dbb88538d chore: Version auf 6.2.2 heben
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 17:59:53 +02:00
Erik Thiele
fe2846dfa6 chore: Upload-Diagnose im Willkommensseiten-Formular
Protokolliert je Kundenfeld, ob eine Datei angekommen ist. Ein
fehlendes enctype im Formular - etwa wenn der Browser eine aeltere
Fassung der Seite aus dem Cache liefert - sieht serverseitig sonst
genauso aus wie "kein Logo hochgeladen", und der Unterschied war aus
dem Log nicht erkennbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 15:37:44 +02:00
Erik Thiele
a3b9fe59b7 fix: hochgeladene Logos nicht mehr in einem Screen-Ordner ablegen
Hochgeladene Logos landeten unter media/<site>/logos/. admin() behandelt
aber jeden Unterordner von media/<site>/ als Screen und schreibt ihn per
get_screen_config() dauerhaft in die Konfiguration. Der Logo-Ordner
erschien dadurch als Screen in der Oberflaeche, bekam beim Generieren
eine eigene welcome.html und liess sich wie ein Screen bespielen - und
die darin liegenden Logos wie Screen-Medien loeschen. Genau so ist eines
der hochgeladenen Logos verschwunden.

Logos liegen jetzt als media/<site>/logo_<slot>.png direkt im
Standort-Verzeichnis, so wie das Hintergrundbild als
media/<site>/background.* - aus demselben Grund. Die URL bleibt
/media/<site>/logos/<datei>, die Route liest aus dem
Standort-Verzeichnis; bestehende welcome.html funktionieren damit
unveraendert weiter.

Zusaetzlich wird der Ordnername "logos" bei der Screen-Erkennung
uebersprungen, damit Altbestaende nicht erneut als Screen auftauchen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 15:14:20 +02:00
Erik Thiele
9dae841461 feat: Schalter platziert die Willkommensseite sofort
Die Willkommensseite ist je Standort identisch. Bisher musste man nach
dem Einschalten des Schalters "Willkommensseite hier anzeigen" erneut
generieren, damit sie auf dem Screen ankam - ein Handgriff ohne anderes
Ergebnis, und ohne Rueckmeldung, dass er noetig ist.

- sync_welcome_for_screen() kopiert beim Einschalten eine vorhandene
  welcome.html in den Screen und setzt sie vorne in die Playlist; beim
  Ausschalten werden Eintrag und Datei entfernt. Aufgerufen aus
  update_screen(), nur wenn sich der Schalter wirklich aendert.
- save_welcome_page() legt zusaetzlich eine Standort-Kopie unter
  media/<site>/welcome.html an, die nie geloescht wird. Ohne sie waere
  nach dem Abschalten aller Screens keine Quelle mehr vorhanden und der
  Schalter wuerde wieder stillschweigend nichts tun.

Nebenbei behoben: beim Generieren wurde welcome.html aus abgewaehlten
Screens nur aus der Playlist entfernt, die Datei blieb liegen. Bei
leerer Playlist spielt player() noch nicht verzeichnete Dateien aus dem
Ordner ab - die Begruessung waere dort also weiter zu sehen gewesen.

README, AGENTS.md und Hilfeseite nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 14:54:44 +02:00
Erik Thiele
64db742d31 feat: Logo-Upload mit automatischem Freistellen
Findet die automatische Suche kein Logo, kann pro Kunde eine Bilddatei
hochgeladen werden. Ein Upload hat Vorrang vor der Suche.

Freistellen:
- remove_logo_background() entfernt den Hintergrund per Flood Fill von
  den Bildraendern her. Bewusst kein globaler Farbvergleich - sonst
  verschwindet auch Weiss innerhalb des Logos (etwa Text in einer
  Flaeche). Weiche Kante gegen Treppeneffekte.
- Umgesetzt mit Pillow, das ueber qrcode[pil] ohnehin vorhanden ist.
  Bewusst kein ML-Modell wie rembg: der Container laeuft mit read-only
  Root-FS, ein Modell-Cache zur Laufzeit waere dort nicht moeglich.
- Bereits transparente Bilder bleiben unangetastet. Ist der Bildrand
  nicht einfarbig, wird nicht freigestellt und die Oberflaeche weist
  darauf hin, statt ein beschaedigtes Logo zu liefern.
- Checkbox "Hintergrund behalten" schaltet das Freistellen pro Kunde ab.
- Gespeichert wird immer als PNG (JPEG kann keine Transparenz), grosse
  Bilder werden auf 800px verkleinert.

Ablage unter media/<site>/logos/logo_<slot>.png, neue Route
/media/<site>/logos/<datei>. Die URL traegt einen Zeitstempel, damit
Player kein altes Logo aus dem Cache zeigen.

Nebenbei behoben: welcome_data speicherte nur die erfolgreichen Kunden
statt der Felder 1-3. Fiel Kunde 1 aus, rutschte Kunde 2 beim naechsten
Aufruf in Feld 1 und Logo wie Ansprechpartner verschoben sich mit. Jetzt
feldweise - dadurch bleibt auch ein hochgeladenes Logo beim erneuten
Generieren erhalten, solange der Kundenname im selben Feld steht.

Die drei Kundenbloecke im Formular sind zu einer Schleife
zusammengefasst, damit die Upload-Felder nicht dreifach gepflegt werden
muessen.

README, AGENTS.md und Hilfeseite nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 13:55:40 +02:00
Erik Thiele
94bfe865ef chore: Version auf 6.2.1 heben
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 12:49:19 +02:00
Erik Thiele
848bcf93ab feat: Willkommensseite auf mehreren Screens anzeigen
Die Willkommensseite ging bisher fest in die Lobby-Playlist. Welche
Screens Begruessungsschirme sind, ist aber eine Eigenschaft der
Installation und nicht des einzelnen Kundenbesuchs - deshalb ein Flag
pro Screen statt einer Auswahl bei jedem Vorgang.

- Neue Screen-Einstellung "welcome_enabled" (Checkbox im Tab
  Einstellungen). Die generierte welcome.html wird in jeden markierten
  Screen des Standorts geschrieben und dort an Position 0 gesetzt.
- welcome_target_screens() faellt nur auf "lobby" zurueck, wenn kein
  Screen des Standorts den Schluessel besitzt. Bestehende Standorte
  verhalten sich damit ohne Konfigurationsaufwand unveraendert.
- add_customer_to_playlists() (frueher add_customer_to_lobby_playlist)
  raeumt welcome.html aus allen Screens des Standorts und fuegt sie nur
  in den Zielscreens wieder ein. Ein abgewaehlter Screen bleibt so nicht
  mit einer alten Begruessung stehen.
- Eingefuegt wird ein Dict statt eines Strings, damit der Eintrag
  enabled und schedule tragen kann.
- Optionales "Anzeigen bis" im Formular: setzt eine Zeitsteuerung, die
  Seite verschwindet danach auf allen Screens von selbst.
- Das Formular zeigt die aktuellen Zielscreens an und meldet
  verstaendlich, wenn keiner markiert ist.
- screens.setdefault("lobby", {}) entfernt - das legte an Standorten
  ohne Lobby stillschweigend einen Screen an. Es werden nur noch
  vorhandene Screens bespielt.

Die Seite referenziert alle Bilder absolut (/static/..., /media/...),
ist also ortsunabhaengig; je Screen liegt eine identische Kopie.

README, AGENTS.md und die Hilfeseite nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 12:26:22 +02:00
Erik Thiele
3761497421 chore: Version auf 6.2.0 heben
Die Zeitsteuerung fuer Playlist-Eintraege ist seit 6.1.0 dazugekommen.
AGENTS.md versieht Feature-Abschnitte mit einer Versionsangabe - der
Abschnitt "Zeitsteuerung" traegt sie jetzt nach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 20:51:24 +02:00
Erik Thiele
f540458b74 fix: Zeitsteuerung reparieren und vervollstaendigen
Der vorige Commit 26efed8 war nicht lauffaehig - fehlgeschlagene
Patch-Anwendungen hatten Zeilen aus ihren Bloecken geschoben.

Reparaturen:
- admin(): zerschossene Playlist-Schleife neu aufgebaut
- player(): return render_template war in den else-Zweig gerutscht,
  wodurch die View bei aktiver Priority-Playlist None lieferte (HTTP 500)
- playlist_item_enabled() existierte nicht mehr (umbenannt zu
  is_item_active), zwei Aufrufe im Player blieben stehen -> NameError
- update_playlist_item(): Absturz bei new_url=null, und der
  enabled-Status ging beim Bearbeiten verloren
- Dateityp-Erkennung mit else-Fallback, ftype konnte ungebunden bleiben

Zeitsteuerung:
- Zeitfenster ueber Mitternacht (22:00-02:00) funktionieren; bei weekly
  gehoert ein solches Fenster zum Wochentag seines Starts
- Optionaler Gueltigkeitszeitraum (valid_from/valid_until) fuer daily
  und weekly, beide Grenzen einzeln optional und inklusiv
- daily/weekly speichern nur noch die Uhrzeit ("08:00") statt eines
  Zeitstempels mit bedeutungslosem Datumsanteil; _schedule_time() liest
  weiterhin auch Altbestaende mit vollem ISO-Zeitstempel
- playlist_hash() bezieht den ausgewerteten Aktiv-Zustand ein, sonst
  bemerkt der Player ein ablaufendes Zeitfenster erst beim naechsten
  Reload aus anderem Grund
- Zeitsteuerung auch fuer Datei-Eintraege, nicht nur URLs
- Neuer Filter schedule_text fuer den Tooltip am "Zeit"-Badge

Oberflaeche:
- required lag auf ausgeblendeten Feldern und blockierte das Absenden
  des Formulars "URL hinzufuegen" ohne sichtbare Meldung
- updateScheduleDaysVisibility() war innerhalb von DOMContentLoaded
  definiert, der Edit-Handler darueber -> ReferenceError bei jedem Klick
- data-schedule mit tojson zerlegte das Attribut, da tojson " nicht
  escaped
- Zeitsteuerungs-Block als schlichte Formularzeilen statt als card, die
  global den roten Rand und grauen Header erhaelt
- Zeitsteuerung auch in der Priority-Playlist

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-29 19:42:03 +02:00
Erik Thiele
26efed87a5 feat: Add time-based scheduling for playlist items 2026-08-29 16:29:40 +02:00
Erik Thiele
22104b54cd Query-Parameter-Passthrough per URL steuerbar (Checkbox im Edit-Modal), Standard aus, sichtbar via Link-Icon in Playlist
- Neue Config-Felder: passthrough_params (true/false) pro URL-Item
- Edit-Modal in admin.html + priority.html mit Checkbox
- Player checkt item.passthrough === true vor appendParams()
- Default: false (keine Parameter-Übergabe ohne Checkbox)
- Link-Icon (ti-link / ti-link-off) in Playlist-Zeile als Status-Indikator
- Doku: help.html, README.md, AGENTS.md
2026-07-10 17:44:57 +02:00
Erik Thiele
5ee9e0b373 Query-Parameter der Player-URL an Playlist-URLs übergeben
- player_params als dict(request.args) an player.html übergeben
- appendParams() fügt Parameter an iframe.src + Overlay-URLs an
- Funktioniert mit & ohne bestehende Query-Parameter in der Ziel-URL
- Beispiel: /player/stuttgart/lobby?customer=acme → https://dashboard?customer=acme
2026-07-10 17:20:37 +02:00
Erik Thiele
ce4cd4486b URLs in Playlist inline bearbeiten (Edit-Button + Modal)
- Neue Route POST /admin/<site>/update-playlist-item/<screen>
- Bearbeiten-Button (✎) für URL-Items in admin.html + priority.html
- Modal mit URL + Zoom-Feld, Validierung und Speichern
- Grid um Edit-Spalte erweitert (28px|1fr|90px|80px|40px|50px|32px)
2026-07-10 16:24:47 +02:00
Erik Thiele
106ec2d897 Fix: Trusted-Device-Cookie überlebt jetzt den Logout
- resp.delete_cookie('mfa_trust') aus /logout entfernt
- Cookie wird nur noch bei MFA-Deaktivierung/Passwort-Reset gelöscht
- Debug-Prints entfernt, users.json aufgeräumt
2026-07-10 16:17:08 +02:00
Erik Thiele
b9e7b2e074 Fix: Trusted-Device-Cookie wurde nicht korrekt gespeichert
- Cookie path explizit auf '/' gesetzt
- login_user() vor Cookie-Setzung aufgerufen (konsistenter Zustand)
- Kein Überschreiben der Response mehr bei must_change_password
2026-07-10 15:44:00 +02:00
Erik Thiele
bfbd970f3b Fix: Passwort-Reset deaktiviert jetzt auch MFA
Beim Admin-Passwort-Reset werden mfa_enabled, mfa_secret,
mfa_recovery_codes und trusted_devices zurückgesetzt.
2026-07-10 15:33:37 +02:00
Erik Thiele
23a33955aa MFA: Trusted Device Feature — Gerät für X Tage merken, überspringt MFA
- User kann nach TOTP-Eingabe das Gerät für 1–30 Tage speichern
- Cookie mfa_trust mit zufälligem Token, gespeichert in trusted_devices[]
- Nächstes POST /login: Cookie prüfen → gültiges Token → MFA überspringen
- Abgelaufene Einträge werden beim Login automatisch bereinigt
- Logout + MFA-Deaktivierung löschen Cookie + trusted_devices
- mfa_verify.html: checkbox + days-select (1/3/7/14/30 Tage)
2026-07-10 15:27:17 +02:00
Erik Thiele
a0753ea4c3 Willkommensseite: Kontaktinfo linksbündig mit Aufzählungen, Portrait-Modus verbessert
- md_to_html: Listen-Support (- /*) und Zeilenumbrüche erhalten
- Kein Firmenname mehr unter den Logos (customer-name entfernt)
- text-align: left + align-items: stretch für linksbündige Texte
- Feste Logo-Höhe 120px für gleiche Text-Startposition
- Portrait-Modus: Text links vom Logo (via order), gap 40px
- Schrift 1.3rem, margin-top 24px, Listeneinzug entfernt
- Reset-Button im Willkommensseite-Formular
- Markdown-Hilfetext aktualisiert
2026-07-04 10:31:02 +02:00
Erik Thiele
c1a043fc75 Ansprechpartner-Felder für Willkommensseite mit Markdown-Support 2026-07-04 09:14:38 +02:00
Erik Thiele
b1f525c714 proxyfix 2026-06-30 19:11:44 +02:00
Erik Thiele
297b52e50c Info Tab und MFA 2026-06-28 15:14:06 +02:00
Erik Thiele
1243910d4b Ergänzung Active Button 2026-06-26 15:10:38 +02:00
Erik Thiele
ab83c19997 Fehler bei Stay on first site 2026-06-22 17:01:32 +02:00
Erik Thiele
6eed62d990 Darkmode Problem gelöst 2026-06-22 08:42:18 +02:00
Erik Thiele
928ea92aed Admin Dashboard, Hilfe-Seite, Dockerfile Fixes (gunicorn, UID 1000, HOME) 2026-06-21 16:46:06 +02:00
Erik Thiele
3eb5cf9d8d neues dockerfile mit gunicorn Server 2026-06-20 16:49:48 +02:00
Erik Thiele
e18414ab79 Admin Dashboard und Hilfeseite 2026-06-20 16:40:02 +02:00
Erik Thiele
39aed78b91 Userverwaltung hinzugefügt 2026-06-20 12:09:02 +02:00
Erik Thiele
35e22718e3 Positionen Action Button und DVA Button hinzugefügt 2026-06-19 12:09:50 +02:00
Erik Thiele
f5f1d52239 Hintergrundbild Willkommensseite 2026-06-10 10:32:04 +02:00
Erik Thiele
0e192a615d Hilfetexte ergänzt 2026-06-07 12:35:10 +02:00
Erik Thiele
0efc5bb346 Tabs in der Admin UI 2026-06-07 12:27:19 +02:00
Erik Thiele
4b29d9a27f Standort löschen hinzugefügt 2026-06-05 14:01:05 +02:00
Erik Thiele
d7bebf1226 Standortauswahl und Multi Logo und Action Button 2026-06-05 12:55:01 +02:00
Erik Thiele
d131948c13 Kundenlogo von ICON auf Logo gestellt 2026-05-10 19:48:57 +02:00
Erik Thiele
31ea3107e6 Version 4.1.0 2026-05-10 14:08:59 +02:00
Erik Thiele
a1b48e35d6 Checkbox für Playliste hinzugefügt 2026-05-10 13:49:05 +02:00
Erik Thiele
296e59e709 Admin html Ergänzungen Überschriften 2026-05-09 10:06:31 +02:00
Erik Thiele
0a39ac69de Versin 4.0.2 CANCOM in rot 2026-05-05 13:09:56 +02:00
Erik Thiele
61ee174cff Version 4.0 2026-05-03 18:23:03 +02:00
Erik Thiele
1cb260fa80 Automatische Willkommensseite hinzugefügt 2026-05-03 18:20:21 +02:00
Erik Thiele
0fa3c00319 Version 3.6 mit URL Zoom Funktion
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 13:03:45 +02:00