fix(display): screen UUID lookup, authScreen middleware, JSON encoding
- playerstatus: look up screen by slug before UpsertDisplayState to pass UUID (not slug) and avoid FK violation - router: switch display command route from authOnly to authScreen for proper permission enforcement - display.go: remove redundant GetBySlug + requireScreenAccess (now handled by authScreen middleware), drop store dependency - notifier: replace fmt.Sprintf %q with json.Marshal for correct JSON encoding of display command payload Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
96135266f1
commit
79fcc20b79
4 changed files with 14 additions and 15 deletions
|
|
@ -6,22 +6,13 @@ import (
|
|||
"net/http"
|
||||
|
||||
"git.az-it.net/az/morz-infoboard/server/backend/internal/mqttnotifier"
|
||||
"git.az-it.net/az/morz-infoboard/server/backend/internal/store"
|
||||
)
|
||||
|
||||
// HandleDisplayCommand nimmt {"state":"on"} oder {"state":"off"} entgegen und
|
||||
// schickt den entsprechenden MQTT-Befehl an den Agent.
|
||||
func HandleDisplayCommand(screens *store.ScreenStore, notifier *mqttnotifier.Notifier) http.HandlerFunc {
|
||||
func HandleDisplayCommand(notifier *mqttnotifier.Notifier) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
screenSlug := r.PathValue("screenSlug")
|
||||
screen, err := screens.GetBySlug(r.Context(), screenSlug)
|
||||
if err != nil {
|
||||
http.Error(w, "screen not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !requireScreenAccess(w, r, screen) {
|
||||
return
|
||||
}
|
||||
|
||||
var body struct {
|
||||
State string `json:"state"`
|
||||
|
|
|
|||
|
|
@ -135,8 +135,10 @@ func handlePlayerStatus(store playerStatusStore, screenStore *storePackage.Scree
|
|||
})
|
||||
|
||||
if request.DisplayState != "" && screenStore != nil {
|
||||
if err := screenStore.UpsertDisplayState(r.Context(), request.ScreenID, request.DisplayState); err != nil {
|
||||
slog.Error("upsert display state", "screen_id", request.ScreenID, "err", err)
|
||||
if screen, err := screenStore.GetBySlug(r.Context(), request.ScreenID); err == nil {
|
||||
if err := screenStore.UpsertDisplayState(r.Context(), screen.ID, request.DisplayState); err != nil {
|
||||
slog.Error("upsert display state", "screen_id", screen.ID, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ func registerManageRoutes(mux *http.ServeMux, d RouterDeps) {
|
|||
|
||||
// ── Display control ───────────────────────────────────────────────────
|
||||
mux.Handle("POST /api/v1/screens/{screenSlug}/display",
|
||||
authOnly(http.HandlerFunc(manage.HandleDisplayCommand(d.ScreenStore, notifier))))
|
||||
authScreen(http.HandlerFunc(manage.HandleDisplayCommand(notifier))))
|
||||
|
||||
// ── JSON API — screens ────────────────────────────────────────────────
|
||||
// Self-registration: no auth (player calls this on startup).
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package mqttnotifier
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -103,8 +104,13 @@ func (n *Notifier) SendDisplayCommand(screenSlug, action string) error {
|
|||
return nil
|
||||
}
|
||||
topic := fmt.Sprintf("signage/screen/%s/command", screenSlug)
|
||||
payload := []byte(fmt.Sprintf(`{"action":%q}`, action))
|
||||
token := n.client.Publish(topic, 1, true, payload)
|
||||
b, err := json.Marshal(struct {
|
||||
Action string `json:"action"`
|
||||
}{Action: action})
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal display command: %w", err)
|
||||
}
|
||||
token := n.client.Publish(topic, 1, true, b)
|
||||
if !token.WaitTimeout(5 * time.Second) {
|
||||
return fmt.Errorf("mqtt publish display command: timeout")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue