package sqlite import ( "context" "database/sql" "encoding/json" "switchboard-core/models" ) type GlobalConfigStore struct{} func NewGlobalConfigStore() *GlobalConfigStore { return &GlobalConfigStore{} } func (s *GlobalConfigStore) Get(ctx context.Context, key string) (models.JSONMap, error) { var valueJSON string err := DB.QueryRowContext(ctx, "SELECT value FROM global_settings WHERE key = ?", key).Scan(&valueJSON) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } var result models.JSONMap json.Unmarshal([]byte(valueJSON), &result) return result, nil } func (s *GlobalConfigStore) Set(ctx context.Context, key string, value models.JSONMap, updatedBy string) error { valueJSON := ToJSON(value) _, err := DB.ExecContext(ctx, ` INSERT INTO global_settings (key, value, updated_by, updated_at) VALUES (?, ?, ?, datetime('now')) ON CONFLICT (key) DO UPDATE SET value = excluded.value, updated_by = excluded.updated_by, updated_at = datetime('now')`, key, valueJSON, updatedBy) return err } func (s *GlobalConfigStore) GetAll(ctx context.Context) (map[string]models.JSONMap, error) { rows, err := DB.QueryContext(ctx, "SELECT key, value FROM global_settings") if err != nil { return nil, err } defer rows.Close() result := make(map[string]models.JSONMap) for rows.Next() { var key, valueJSON string if err := rows.Scan(&key, &valueJSON); err != nil { continue } var m models.JSONMap json.Unmarshal([]byte(valueJSON), &m) result[key] = m } return result, rows.Err() } // ── OIDC state ──────────────────────────────────────────── func (s *GlobalConfigStore) SaveOIDCState(ctx context.Context, state, nonce, redirectTo string) error { _, err := DB.ExecContext(ctx, ` INSERT INTO oidc_auth_state (state, nonce, redirect_to) VALUES (?, ?, ?) `, state, nonce, redirectTo) return err } func (s *GlobalConfigStore) ConsumeOIDCState(ctx context.Context, state string) (string, string, error) { var nonce, redirectTo string err := DB.QueryRowContext(ctx, ` SELECT nonce, COALESCE(redirect_to, '') FROM oidc_auth_state WHERE state = ? `, state).Scan(&nonce, &redirectTo) if err != nil { return "", "", err } _, _ = DB.ExecContext(ctx, `DELETE FROM oidc_auth_state WHERE state = ?`, state) return nonce, redirectTo, nil } func (s *GlobalConfigStore) CleanupOIDCState(ctx context.Context) error { _, err := DB.ExecContext(ctx, `DELETE FROM oidc_auth_state WHERE created_at < datetime('now', '-10 minutes')`) return err } // ── CS6 additions ───────────────────────────────────────────── func (s *GlobalConfigStore) GetString(ctx context.Context, key string) (string, error) { var val string err := DB.QueryRowContext(ctx, "SELECT value FROM global_settings WHERE key = ?", key).Scan(&val) return val, err }