Signed-in users get their preferences (hidden feeds, weather location, weather toggle) stored server-side keyed by their OIDC subject and synced across devices. Anonymous visitors keep using browser localStorage, so the site stays public. First sign-in migrates existing localStorage prefs up. - config: [web.auth] section (issuer, client_id/secret, redirect, session_secret) - storage: user_preferences table + Get/PutUserPrefs - web/auth: OIDC code flow, HMAC-signed session cookie, CSRF state + nonce - web/prefs_api: GET/PUT /api/preferences (auth-gated, 64KB cap) - frontend: prefs.js sync layer seeds localStorage from server, pushes on write - header: sign-in / account control OIDC discovery is non-fatal at boot: if Authentik is down, Pete serves anonymously rather than refusing to start.
45 lines
1.1 KiB
Go
45 lines
1.1 KiB
Go
package storage
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestUserPrefsRoundTrip(t *testing.T) {
|
|
if err := Init(filepath.Join(t.TempDir(), "prefs.db")); err != nil {
|
|
t.Fatalf("init db: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = Close() })
|
|
|
|
// Missing user → empty, no error.
|
|
got, err := GetUserPrefs("nobody")
|
|
if err != nil {
|
|
t.Fatalf("get missing: %v", err)
|
|
}
|
|
if got != "" {
|
|
t.Fatalf("expected empty for missing user, got %q", got)
|
|
}
|
|
|
|
blob := `{"pete.weather.loc.v1":"{\"postal\":\"1000\"}"}`
|
|
if err := PutUserPrefs("ak-sub-1", blob, "misaki", "m@example.com"); err != nil {
|
|
t.Fatalf("put: %v", err)
|
|
}
|
|
got, err = GetUserPrefs("ak-sub-1")
|
|
if err != nil {
|
|
t.Fatalf("get: %v", err)
|
|
}
|
|
if got != blob {
|
|
t.Fatalf("blob mismatch:\n got %q\nwant %q", got, blob)
|
|
}
|
|
|
|
// Upsert: second put for same sub replaces the blob.
|
|
blob2 := `{"pete-weather-off":"1"}`
|
|
if err := PutUserPrefs("ak-sub-1", blob2, "misaki", "m@example.com"); err != nil {
|
|
t.Fatalf("upsert: %v", err)
|
|
}
|
|
got, _ = GetUserPrefs("ak-sub-1")
|
|
if got != blob2 {
|
|
t.Fatalf("upsert mismatch: got %q want %q", got, blob2)
|
|
}
|
|
}
|