package web import ( "encoding/json" "net/url" "strings" "testing" ) // R-521 controller half (operator ruling 2026-10-12, S32, `09` ยง3 decision 227): the household's own // notification settings carry a lost-drive option (`storage_disconnected`), saved and sent to the hub in // `enabled_events` exactly like the others โ€” and ONLY when the household has it on. The hub mails a lost // drive only when this setting carries it. // // RED-PROOF (REPORT.md): drop "storage_disconnected" from the single-event list in // settingsNotificationsHandler โ†’ the "on" half fails (the option is silently not saved and not sent). func TestR521_StorageDisconnectedOptionRoundTrips(t *testing.T) { eventsOf := func(t *testing.T, body map[string]json.RawMessage) []string { t.Helper() var ev []string if err := json.Unmarshal(body["enabled_events"], &ev); err != nil { t.Fatalf("enabled_events is not a list: %s", body["enabled_events"]) } return ev } has := func(list []string, e string) bool { for _, x := range list { if x == e { return true } } return false } // ON: saved, sent, and the page shows it ticked. s, sett, hub := r922Server(t) s.loadTemplates() rr := postNotifications(t, s, url.Values{ "notification_email": {"household@example.hu"}, "cooldown_hours": {"6"}, "event_backup_failed": {"on"}, "event_storage_disconnected": {"on"}, }) if p := sett.GetNotificationPrefs(); !has(p.EnabledEvents, "storage_disconnected") { t.Fatalf("on: storage_disconnected not saved (stored %v)", p.EnabledEvents) } if ev := eventsOf(t, hub.last(t)); !has(ev, "storage_disconnected") { t.Fatalf("on: storage_disconnected not sent to the hub (enabled_events %v)", ev) } if !strings.Contains(rr.Body.String(), `name="event_storage_disconnected" checked`) { t.Error("on: the saved option does not render ticked") } // OFF: the same household switches it off โ€” not saved, not sent, not ticked. rr = postNotifications(t, s, url.Values{ "notification_email": {"household@example.hu"}, "cooldown_hours": {"6"}, "event_backup_failed": {"on"}, }) if p := sett.GetNotificationPrefs(); has(p.EnabledEvents, "storage_disconnected") { t.Fatalf("off: storage_disconnected still saved (stored %v)", p.EnabledEvents) } if ev := eventsOf(t, hub.last(t)); has(ev, "storage_disconnected") { t.Fatalf("off: storage_disconnected still sent to the hub (enabled_events %v)", ev) } if strings.Contains(rr.Body.String(), `name="event_storage_disconnected" checked`) { t.Error("off: the option still renders ticked") } }