60 lines
3.1 KiB
Go
60 lines
3.1 KiB
Go
package store
|
|
|
|
import "fmt"
|
|
|
|
// R-1199 reopened (2026-10-22). Controller 0.338.0 made a box with no locally saved notification list push its
|
|
// DEFAULT list at every start, so the hub mails by what the box's page shows. On a REBUILT box that overwrote the list
|
|
// the household had saved on its old box — measured the same morning: demo-felhom's own 13-event list, written by an
|
|
// earlier box, became the 17-event default at 07:54:55 UTC. The hub could not refuse it, because nothing in the row
|
|
// said who wrote it: the claim seeds a row (SeedNotificationPrefs), a box push upserts it (SaveNotificationPrefs), and
|
|
// a one-time migration adds event types (SeedEventTypesOnce).
|
|
//
|
|
// household_saved is that mark. It is set ONLY by a push the box declares as the household's own save (the settings
|
|
// page, or the re-push of a list saved on the box) and is never cleared; a default push never overwrites a row that
|
|
// carries it (api.handleSavePreferences). Pinned by TestR1199Reopened_* (api) and TestHouseholdSaved_* (store).
|
|
|
|
// householdSavedBackfillKey guards the one-time backfill of existing rows.
|
|
const householdSavedBackfillKey = "r1199_household_saved_backfill"
|
|
|
|
// migrateHouseholdSaved adds the column and, once, marks every existing row a box ever wrote. The rule: a row whose
|
|
// updated_at differs from its created_at was written after its creation — by a box push (a seed is an insert and
|
|
// never updates). Read on the live hub 2026-10-22 before the change: Tester-2 and Tester4 (seeded, never pushed) →
|
|
// false; demo-felhom, demo-hp, tester-1 and _resend-rotation-test (pushed) → true. Each row's verdict is logged.
|
|
// (SeedEventTypesOnce also bumps updated_at; on 2026-10-22 every row it touched had been pushed, so the rule holds for
|
|
// the rows that exist. A row created after this backfill is never judged by it.)
|
|
func (s *Store) migrateHouseholdSaved() error {
|
|
s.db.Exec(`ALTER TABLE customer_notifications ADD COLUMN household_saved INTEGER NOT NULL DEFAULT 0`)
|
|
var done string
|
|
if err := s.db.QueryRow(`SELECT value FROM hub_settings WHERE key = ?`, householdSavedBackfillKey).Scan(&done); err == nil && done != "" {
|
|
return nil
|
|
}
|
|
rows, err := s.db.Query(`SELECT customer_id, COALESCE(created_at, ''), COALESCE(updated_at, '') FROM customer_notifications`)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
type r struct{ id, created, updated string }
|
|
var all []r
|
|
for rows.Next() {
|
|
var x r
|
|
if err := rows.Scan(&x.id, &x.created, &x.updated); err != nil {
|
|
rows.Close()
|
|
return err
|
|
}
|
|
all = append(all, x)
|
|
}
|
|
rows.Close()
|
|
for _, x := range all {
|
|
saved := x.created != "" && x.updated != "" && x.created != x.updated
|
|
if saved {
|
|
if _, err := s.db.Exec(`UPDATE customer_notifications SET household_saved = 1 WHERE customer_id = ?`, x.id); err != nil {
|
|
return fmt.Errorf("mark %s: %w", x.id, err)
|
|
}
|
|
}
|
|
if s.logger != nil {
|
|
s.logger.Printf("[INFO] R-1199 backfill: notification list of %s household_saved=%t (created %s, updated %s)", x.id, saved, x.created, x.updated)
|
|
}
|
|
}
|
|
_, err = s.db.Exec(`INSERT INTO hub_settings (key, value) VALUES (?, datetime('now')) ON CONFLICT(key) DO UPDATE SET value = excluded.value`, householdSavedBackfillKey)
|
|
return err
|
|
}
|