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"
|
"net/http"
|
||||||
|
|
||||||
"git.az-it.net/az/morz-infoboard/server/backend/internal/mqttnotifier"
|
"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
|
// HandleDisplayCommand nimmt {"state":"on"} oder {"state":"off"} entgegen und
|
||||||
// schickt den entsprechenden MQTT-Befehl an den Agent.
|
// 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) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
screenSlug := r.PathValue("screenSlug")
|
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 {
|
var body struct {
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,10 @@ func handlePlayerStatus(store playerStatusStore, screenStore *storePackage.Scree
|
||||||
})
|
})
|
||||||
|
|
||||||
if request.DisplayState != "" && screenStore != nil {
|
if request.DisplayState != "" && screenStore != nil {
|
||||||
if err := screenStore.UpsertDisplayState(r.Context(), request.ScreenID, request.DisplayState); err != nil {
|
if screen, err := screenStore.GetBySlug(r.Context(), request.ScreenID); err == nil {
|
||||||
slog.Error("upsert display state", "screen_id", request.ScreenID, "err", err)
|
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 ───────────────────────────────────────────────────
|
// ── Display control ───────────────────────────────────────────────────
|
||||||
mux.Handle("POST /api/v1/screens/{screenSlug}/display",
|
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 ────────────────────────────────────────────────
|
// ── JSON API — screens ────────────────────────────────────────────────
|
||||||
// Self-registration: no auth (player calls this on startup).
|
// Self-registration: no auth (player calls this on startup).
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
package mqttnotifier
|
package mqttnotifier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -103,8 +104,13 @@ func (n *Notifier) SendDisplayCommand(screenSlug, action string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
topic := fmt.Sprintf("signage/screen/%s/command", screenSlug)
|
topic := fmt.Sprintf("signage/screen/%s/command", screenSlug)
|
||||||
payload := []byte(fmt.Sprintf(`{"action":%q}`, action))
|
b, err := json.Marshal(struct {
|
||||||
token := n.client.Publish(topic, 1, true, payload)
|
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) {
|
if !token.WaitTimeout(5 * time.Second) {
|
||||||
return fmt.Errorf("mqtt publish display command: timeout")
|
return fmt.Errorf("mqtt publish display command: timeout")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue