buhapp-backend/internal/preferences/repo.go
ga 1eb7af6bac Sprint 5: reviews and ratings
- POST /api/v1/reviews (one per chat_id, UNIQUE)
- GET  /api/v1/users/:id/reviews (public list)
- GET  /api/v1/users/:id/stats (rating_avg, count)
- migration 0004: reviews (rating 1-5, anonymous flag), user_stats aggregate
- only chat participants can review; reviewed_id is other party
2026-08-20 16:20:15 +00:00

101 lines
2.5 KiB
Go

package preferences
import (
"context"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
// допустимые значения (для валидации)
var AllowedDrinks = map[string]bool{
"beer": true, "wine": true, "whiskey": true, "vodka": true,
"cocktail": true, "rum": true, "gin": true, "tequila": true,
"cider": true, "champagne": true, "non_alcoholic": true,
}
var AllowedActivities = map[string]bool{
"walk": true, "dinner": true, "bar": true, "cafe": true,
"travel": true, "movie": true, "concert": true, "sport": true,
"cooking": true, "gaming": true, "reading": true, "other": true,
}
var AllowedPurposes = map[string]bool{
"chat": true, "drink": true, "walk": true, "dinner": true,
"travel": true, "relationship": true, "friendship": true, "other": true,
}
type Prefs struct {
UserID uuid.UUID
Drinks []string
Activities []string
Purposes []string
Language string
UpdatedAt time.Time
}
type Repo struct {
pool *pgxpool.Pool
}
func NewRepo(pool *pgxpool.Pool) *Repo {
return &Repo{pool: pool}
}
func (r *Repo) Get(ctx context.Context, userID uuid.UUID) (*Prefs, error) {
p := &Prefs{UserID: userID, Drinks: []string{}, Activities: []string{}, Purposes: []string{}, Language: "ru"}
err := r.pool.QueryRow(ctx, `
SELECT drinks, activities, purposes, COALESCE(language, 'ru'), updated_at
FROM user_preferences WHERE user_id=$1`, userID,
).Scan(&p.Drinks, &p.Activities, &p.Purposes, &p.Language, &p.UpdatedAt)
if err != nil {
// no row = defaults
p.UpdatedAt = time.Now()
return p, nil
}
return p, nil
}
func (r *Repo) Upsert(ctx context.Context, p *Prefs) error {
_, err := r.pool.Exec(ctx, `
INSERT INTO user_preferences (user_id, drinks, activities, purposes, language, updated_at)
VALUES ($1, $2, $3, $4, $5, NOW())
ON CONFLICT (user_id) DO UPDATE
SET drinks = EXCLUDED.drinks,
activities = EXCLUDED.activities,
purposes = EXCLUDED.purposes,
language = EXCLUDED.language,
updated_at = NOW()`,
p.UserID, p.Drinks, p.Activities, p.Purposes, p.Language,
)
return err
}
func (r *Repo) Validate(values []string, allowed map[string]bool) []string {
out := make([]string, 0, len(values))
seen := make(map[string]bool)
for _, v := range values {
v = trimLower(v)
if v == "" || seen[v] {
continue
}
if allowed[v] {
out = append(out, v)
seen[v] = true
}
}
return out
}
func trimLower(s string) string {
out := []rune{}
for _, r := range s {
if r >= 'A' && r <= 'Z' {
r = r + 32
}
out = append(out, r)
}
return string(out)
}