package storage import ( "database/sql" "errors" "fmt" ) // UserPrefs is one signed-in user's stored state. Prefs is an opaque JSON blob // owned by the web frontend (disabled feeds, weather location, toggles, …) — // the backend just persists and returns it, keyed by the OIDC subject. type UserPrefs struct { Sub string Prefs string Username string Email string UpdatedAt int64 } // GetUserPrefs returns the stored prefs blob for an OIDC subject. It returns // ("", nil) when the user has no record yet (first sign-in). func GetUserPrefs(sub string) (string, error) { var prefs string err := Get().QueryRow(`SELECT prefs FROM user_preferences WHERE user_sub = ?`, sub).Scan(&prefs) if errors.Is(err, sql.ErrNoRows) { return "", nil } if err != nil { return "", fmt.Errorf("get user prefs: %w", err) } return prefs, nil } // PutUserPrefs upserts a user's prefs blob along with identity hints (username, // email) for later features. The prefs string is stored verbatim. func PutUserPrefs(sub, prefs, username, email string) error { _, err := Get().Exec(` INSERT INTO user_preferences (user_sub, prefs, username, email, updated_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(user_sub) DO UPDATE SET prefs = excluded.prefs, username = excluded.username, email = excluded.email, updated_at = excluded.updated_at`, sub, prefs, username, email, nowUnix()) if err != nil { return fmt.Errorf("put user prefs: %w", err) } return nil }