fix: Upsert löscht override_on_until nicht mehr; README + Auth-Kommentar
- ScreenScheduleStore.Upsert: override_on_until aus INSERT und ON CONFLICT entfernt — verhindert stillen Datenverlust beim Speichern eines Zeitplans. SetOverrideOnUntil bleibt alleinig zuständig für diese Spalte. - README.md: GlobalOverrideStore, vier neue API-Routen, Wochenend-Sperre und Migration 006_override.sql dokumentiert. - override.go: Auth-Scope-Kommentar über HandleSetGlobalOverride ergänzt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
db68c84d45
commit
2bf82eed53
3 changed files with 33 additions and 9 deletions
|
|
@ -17,7 +17,7 @@ Dieses Verzeichnis enthaelt das zentrale Go-Backend fuer das Info-Board-System.
|
|||
- `internal/app/` — App-Initialisierung und Lifecycle
|
||||
- `internal/config/` — Konfiguration via Umgebungsvariablen
|
||||
- `internal/db/` — PostgreSQL-Anbindung und Migrations-Runner
|
||||
- `internal/store/` — Datenbankzugriff (TenantStore, ScreenStore, MediaStore, PlaylistStore, AuthStore)
|
||||
- `internal/store/` — Datenbankzugriff (TenantStore, ScreenStore, MediaStore, PlaylistStore, AuthStore, ScreenScheduleStore, GlobalOverrideStore)
|
||||
- `internal/fileutil/` — Upload-Hilfsfunktionen (SaveUploadedFile mit Tenant-Isolation)
|
||||
- `internal/httpapi/` — HTTP-Routing, Middleware und Handler
|
||||
- `internal/httpapi/csrf.go` — Double-Submit-Cookie CSRF-Schutz
|
||||
|
|
@ -42,6 +42,10 @@ Uhrzeit übereinstimmt — per MQTT den Befehl `display_on` bzw. `display_off` s
|
|||
Der Scheduler wird in `internal/app/app.go` als Goroutine gestartet und laeuft bis zum
|
||||
Kontext-Abbruch beim Server-Shutdown.
|
||||
|
||||
**Wochenend-Sperre:** An Samstagen und Sonntagen werden Zeitplaene ignoriert — der Reconciler
|
||||
sendet dann keine automatischen Ein-/Ausschalt-Kommandos. Manuelle Overrides (global oder
|
||||
per-Screen) wirken jedoch auch am Wochenende.
|
||||
|
||||
## Datenbank-Stores
|
||||
|
||||
### AuthStore (`internal/store/auth.go`)
|
||||
|
|
@ -60,6 +64,16 @@ Kontext-Abbruch beim Server-Shutdown.
|
|||
- `EnsureAdminUser(ctx, tenantSlug, password)` — Admin-User beim Start anlegen
|
||||
- `VerifyPassword(ctx, userID, password)` — Passwort gegen bcrypt-Hash pruefen
|
||||
|
||||
### GlobalOverrideStore (`internal/store/store.go`)
|
||||
|
||||
Verwaltet einen systemweiten Display-Override (max. 1 Zeile in `global_override`):
|
||||
|
||||
- `Get(ctx)` — aktuellen globalen Override laden (nil wenn keiner gesetzt)
|
||||
- `Upsert(ctx, type, until)` — Override setzen oder ueberschreiben (`type`: `"on"` | `"off"`)
|
||||
- `Delete(ctx)` — Override entfernen
|
||||
|
||||
Der Reconciler im Scheduler wertet den globalen Override aus und wendet ihn auf alle Screens an.
|
||||
|
||||
### ScreenStore (`internal/store/screen.go`)
|
||||
|
||||
**Screen-User Zugriffskontrolle:**
|
||||
|
|
@ -117,6 +131,10 @@ Kontext-Abbruch beim Server-Shutdown.
|
|||
| GET | `/api/v1/screens/{screenId}/screenshot` | Screenshot eines Screens abrufen |
|
||||
| POST | `/api/v1/screens/{screenSlug}/display` | Display ein-/ausschalten (MQTT) |
|
||||
| POST | `/api/v1/screens/{screenSlug}/schedule` | Display-Zeitplan speichern |
|
||||
| GET | `/api/v1/global-override` | Globalen Override abrufen (204 = kein aktiver Override) |
|
||||
| POST | `/api/v1/global-override` | Globalen Override setzen (type + until); sendet sofort MQTT |
|
||||
| DELETE | `/api/v1/global-override` | Globalen Override loeschen |
|
||||
| POST | `/api/v1/screens/{screenSlug}/override` | Per-Screen-Override setzen oder loeschen (on_until: null = loeschen) |
|
||||
|
||||
### Nur Admins (`RequireAuth` + `RequireAdmin`)
|
||||
|
||||
|
|
@ -182,8 +200,9 @@ Middleware zur rollenbasierten Zugriffskontrolle auf Screen-Ressourcen.
|
|||
|
||||
## Migrationen
|
||||
|
||||
- `001_core.sql` — initiales Schema (Tenants, Screens, Playlists, Media, etc.)
|
||||
- `001_initial.sql` — initiales Schema (Tenants, Screens, Playlists, Media, etc.)
|
||||
- `002_auth.sql` — Auth-Tabellen (`users`, `sessions`)
|
||||
- `003_user_screen_permissions.sql` — Screen-User Management (`user_screen_permissions`)
|
||||
- `004_screen_status.sql` — Display-Zustand pro Screen (`screen_status`: screen_id, display_state, reported_at)
|
||||
- `005_screen_schedules.sql` — Zeitplan pro Screen (`screen_schedules`: screen_id, schedule_enabled, power_on_time, power_off_time)
|
||||
- `006_override.sql` — Spalte `override_on_until` in `screen_schedules` (per-Screen-Override) und Tabelle `global_override` (systemweiter Display-Override)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ func HandleGetGlobalOverride(overrides globalOverrideStore) http.HandlerFunc {
|
|||
}
|
||||
|
||||
// HandleSetGlobalOverride setzt den globalen Override und schickt sofort MQTT an alle Screens.
|
||||
// Hinweis: Der Override wird global gespeichert und vom Reconciler auf alle Screens angewendet.
|
||||
// Über authOnly haben alle eingeloggten Nutzer Zugriff; die sofortigen MQTT-Kommandos gehen
|
||||
// jedoch nur an ihre zugänglichen Screens. Soll der Zugriff auf Admins beschränkt werden,
|
||||
// authOnly durch authAdmin ersetzen.
|
||||
func HandleSetGlobalOverride(overrides globalOverrideStore, screens *store.ScreenStore, notifier *mqttnotifier.Notifier) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var body struct {
|
||||
|
|
|
|||
|
|
@ -667,16 +667,17 @@ func (s *ScreenScheduleStore) Get(ctx context.Context, screenID string) (*Screen
|
|||
}
|
||||
|
||||
// Upsert speichert oder aktualisiert den Zeitplan eines Screens.
|
||||
// Hinweis: override_on_until wird hier bewusst nicht angefasst – das ist
|
||||
// ausschließlich Aufgabe von SetOverrideOnUntil (saubere Trennung, kein Datenverlust).
|
||||
func (s *ScreenScheduleStore) Upsert(ctx context.Context, sc *ScreenSchedule) error {
|
||||
_, err := s.pool.Exec(ctx,
|
||||
`insert into screen_schedules (screen_id, schedule_enabled, power_on_time, power_off_time, override_on_until)
|
||||
values ($1, $2, $3, $4, $5)
|
||||
`insert into screen_schedules (screen_id, schedule_enabled, power_on_time, power_off_time)
|
||||
values ($1, $2, $3, $4)
|
||||
on conflict (screen_id) do update
|
||||
set schedule_enabled = excluded.schedule_enabled,
|
||||
power_on_time = excluded.power_on_time,
|
||||
power_off_time = excluded.power_off_time,
|
||||
override_on_until = excluded.override_on_until`,
|
||||
sc.ScreenID, sc.ScheduleEnabled, sc.PowerOnTime, sc.PowerOffTime, sc.OverrideOnUntil)
|
||||
set schedule_enabled = excluded.schedule_enabled,
|
||||
power_on_time = excluded.power_on_time,
|
||||
power_off_time = excluded.power_off_time`,
|
||||
sc.ScreenID, sc.ScheduleEnabled, sc.PowerOnTime, sc.PowerOffTime)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue