mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
c822e95e7f
# Conflicts: # cmd/backend/main.go # internal/api/handler/handler.go # internal/api/routes.go # internal/models/audit.go # internal/models/organization.go # internal/models/user.go # internal/repository/pg_organization.go # internal/repository/pg_user.go
159 lines
4.1 KiB
Go
159 lines
4.1 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/mail"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/db"
|
|
"github.com/warmbly/warmbly/internal/infrastructure/kms"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
type UserRepository interface {
|
|
CreateUser(ctx context.Context, email *mail.Address, password string) (*models.User, error)
|
|
GetUser(ctx context.Context, id uuid.UUID) (*models.User, error)
|
|
GetUserByEmail(ctx context.Context, email string) (*models.User, error)
|
|
SetFreeTrialUsed(ctx context.Context, userID uuid.UUID) error
|
|
UpdateOnboarding(ctx context.Context, userID uuid.UUID, firstName, lastName, referralSource string) error
|
|
UpdateAvatar(ctx context.Context, userID uuid.UUID, avatarURL *string) error
|
|
}
|
|
|
|
type userRepository struct {
|
|
DB *db.DB
|
|
kms *kms.KMS
|
|
}
|
|
|
|
func NewUserRepostory(db *db.DB, kms *kms.KMS) UserRepository {
|
|
return &userRepository{
|
|
DB: db,
|
|
kms: kms,
|
|
}
|
|
}
|
|
|
|
func (r *userRepository) CreateUser(ctx context.Context, email *mail.Address, passwordHash string) (*models.User, error) {
|
|
id := uuid.New()
|
|
|
|
var firstName string
|
|
|
|
nameSplit := strings.SplitN(email.Address, "@", 2)
|
|
if len(nameSplit) < 2 {
|
|
firstName = "Unknown"
|
|
} else {
|
|
firstName = nameSplit[0]
|
|
}
|
|
|
|
var lastName string
|
|
now := time.Now()
|
|
|
|
const q = `
|
|
INSERT INTO users (
|
|
id, email, password_hash,
|
|
first_name, last_name,
|
|
created_at, updated_at
|
|
)
|
|
VALUES (
|
|
$1, $2, $3,
|
|
$4, $5,
|
|
$6, $6
|
|
)
|
|
`
|
|
|
|
var params = []any{
|
|
id, email.Address, passwordHash,
|
|
firstName, lastName,
|
|
now,
|
|
}
|
|
|
|
_, err := r.DB.Exec(
|
|
ctx,
|
|
q,
|
|
params...)
|
|
if err != nil {
|
|
db.CaptureError(err, q, nil, "exec")
|
|
return nil, err
|
|
}
|
|
|
|
return &models.User{
|
|
ID: id,
|
|
|
|
FirstName: firstName,
|
|
LastName: lastName,
|
|
Email: email.Address,
|
|
Roles: make([]uuid.UUID, 0),
|
|
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}, nil
|
|
}
|
|
|
|
func (r *userRepository) getUser(ctx context.Context, key string, value any) (*models.User, error) {
|
|
var u models.User
|
|
|
|
q := fmt.Sprintf(
|
|
`SELECT u.id, u.email, u.first_name, u.last_name, u.avatar_url, u.referral_source, u.onboarding_completed_at,
|
|
u.max_organizations, u.free_trial_used,
|
|
u.deletion_scheduled_at, u.deletion_scheduled_for,
|
|
u.updated_at, u.created_at,
|
|
COALESCE(array_agg(ur.role_id) FILTER (WHERE ur.role_id IS NOT NULL), '{}') AS role_ids
|
|
FROM users u
|
|
LEFT JOIN user_roles ur ON ur.user_id = u.id
|
|
WHERE u.%s = $1
|
|
GROUP BY u.id`,
|
|
key,
|
|
)
|
|
|
|
var params = []any{
|
|
value,
|
|
}
|
|
|
|
err := r.DB.QueryRow(
|
|
ctx,
|
|
q,
|
|
params...,
|
|
).Scan(&u.ID, &u.Email, &u.FirstName, &u.LastName, &u.AvatarURL, &u.ReferralSource, &u.OnboardingCompletedAt,
|
|
&u.MaxOrganizations, &u.FreeTrialUsed,
|
|
&u.DeletionScheduledAt, &u.DeletionScheduledFor,
|
|
&u.UpdatedAt, &u.CreatedAt, &u.Roles)
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, errx.ErrUser
|
|
}
|
|
db.CaptureError(err, q, params, "queryrow")
|
|
return nil, err
|
|
}
|
|
return &u, nil
|
|
}
|
|
|
|
func (r *userRepository) GetUser(ctx context.Context, userID uuid.UUID) (*models.User, error) {
|
|
return r.getUser(ctx, "id", userID)
|
|
}
|
|
|
|
func (r *userRepository) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
|
|
return r.getUser(ctx, "email", email)
|
|
}
|
|
|
|
func (r *userRepository) SetFreeTrialUsed(ctx context.Context, userID uuid.UUID) error {
|
|
const q = `UPDATE users SET free_trial_used = TRUE, updated_at = NOW() WHERE id = $1`
|
|
_, err := r.DB.Exec(ctx, q, userID)
|
|
return err
|
|
}
|
|
|
|
func (r *userRepository) UpdateOnboarding(ctx context.Context, userID uuid.UUID, firstName, lastName, referralSource string) error {
|
|
const q = `UPDATE users SET first_name=$2, last_name=$3, referral_source=$4, onboarding_completed_at=NOW(), updated_at=NOW() WHERE id=$1`
|
|
_, err := r.DB.Exec(ctx, q, userID, firstName, lastName, referralSource)
|
|
return err
|
|
}
|
|
|
|
func (r *userRepository) UpdateAvatar(ctx context.Context, userID uuid.UUID, avatarURL *string) error {
|
|
const q = `UPDATE users SET avatar_url=$2, updated_at=NOW() WHERE id=$1`
|
|
_, err := r.DB.Exec(ctx, q, userID, avatarURL)
|
|
return err
|
|
}
|