package repository import ( "context" "fmt" "github.com/prabhupadasays/spsays-bff/internal/model" ) // PushRepo stores Web Push subscriptions (one per browser/device endpoint). type PushRepo struct{ pg *Postgres } func NewPushRepo(pg *Postgres) *PushRepo { return &PushRepo{pg: pg} } // Upsert records (or refreshes) a subscription. The endpoint is unique, so a // browser re-subscribing — possibly under a different user — rebinds cleanly. func (r *PushRepo) Upsert(ctx context.Context, userID, endpoint, p256dh, auth, userAgent string) error { _, err := r.pg.Pool.Exec(ctx, ` INSERT INTO push_subscriptions (user_id, endpoint, p256dh, auth, user_agent) VALUES ($1, $2, $3, $4, $5) ON CONFLICT (endpoint) DO UPDATE SET user_id = EXCLUDED.user_id, p256dh = EXCLUDED.p256dh, auth = EXCLUDED.auth, user_agent = EXCLUDED.user_agent, last_used_at = now()`, userID, endpoint, p256dh, auth, userAgent, ) if err != nil { return fmt.Errorf("upsert push subscription: %w", err) } return nil } // ListByUser returns the user's active subscriptions. func (r *PushRepo) ListByUser(ctx context.Context, userID string) ([]model.PushSubscription, error) { rows, err := r.pg.Pool.Query(ctx, ` SELECT id, user_id, endpoint, p256dh, auth FROM push_subscriptions WHERE user_id = $1`, userID) if err != nil { return nil, fmt.Errorf("list push subscriptions: %w", err) } defer rows.Close() var out []model.PushSubscription for rows.Next() { var s model.PushSubscription if err := rows.Scan(&s.ID, &s.UserID, &s.Endpoint, &s.P256dh, &s.Auth); err != nil { return nil, fmt.Errorf("scan push subscription: %w", err) } out = append(out, s) } return out, rows.Err() } // DeleteByEndpoint removes a subscription (on unsubscribe or when the push // service reports it gone). func (r *PushRepo) DeleteByEndpoint(ctx context.Context, endpoint string) error { _, err := r.pg.Pool.Exec(ctx, `DELETE FROM push_subscriptions WHERE endpoint = $1`, endpoint) if err != nil { return fmt.Errorf("delete push subscription: %w", err) } return nil }