| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // Package repository
- package repository
- import (
- "context"
- "errors"
- "fmt"
- "time"
- "github.com/jackc/pgx/v5"
- "github.com/jackc/pgx/v5/pgconn"
- "github.com/jackc/pgx/v5/pgxpool"
- "gogs.fxtmmsk.ru/foxtime/photoplaces/backend/internal/models"
- )
- var ErrEmailExists = errors.New("email already exists")
- type UserRepo struct {
- pool *pgxpool.Pool
- }
- func NewUserRepo(pool *pgxpool.Pool) *UserRepo {
- return &UserRepo{pool: pool}
- }
- func (r *UserRepo) Create(ctx context.Context, u *models.User) error {
- err := r.pool.QueryRow(ctx,
- `INSERT INTO users (email, password_hash, role, name, status)
- VALUES ($1, $2, $3, $4, 'active')
- RETURNING id, created_at, updated_at`,
- u.Email, u.PasswordHash, u.Role, u.Name,
- ).Scan(&u.ID, &u.CreatedAt, &u.UpdatedAt)
- if err != nil {
- var pgErr *pgconn.PgError
- if errors.As(err, &pgErr) && pgErr.Code == "23505" {
- return ErrEmailExists
- }
- return fmt.Errorf("create user: %w", err)
- }
- return nil
- }
- func (r *UserRepo) GetByID(ctx context.Context, id string) (*models.User, error) {
- row := r.pool.QueryRow(ctx,
- `SELECT id, email, password_hash, role, status, name, avatar_url, phone, bio, country,
- created_at, updated_at, deleted_at
- FROM users WHERE id = $1 AND deleted_at IS NULL`, id)
- return scanUser(row)
- }
- func (r *UserRepo) GetByEmail(ctx context.Context, email string) (*models.User, error) {
- row := r.pool.QueryRow(ctx,
- `SELECT id, email, password_hash, role, status, name, avatar_url, phone, bio, country,
- created_at, updated_at, deleted_at
- FROM users WHERE email = $1 AND deleted_at IS NULL`, email)
- return scanUser(row)
- }
- func (r *UserRepo) Update(ctx context.Context, u *models.User) error {
- u.UpdatedAt = time.Now()
- _, err := r.pool.Exec(ctx,
- `UPDATE users SET name=$1, phone=$2, bio=$3, avatar_url=$4, country=$5, updated_at=$6
- WHERE id=$7 AND deleted_at IS NULL`,
- u.Name, u.Phone, u.Bio, u.AvatarURL, u.Country, u.UpdatedAt, u.ID)
- return err
- }
- func (r *UserRepo) UpdateRole(ctx context.Context, id, role string) error {
- _, err := r.pool.Exec(ctx,
- `UPDATE users SET role=$1, updated_at=now() WHERE id=$2 AND deleted_at IS NULL`, role, id)
- return err
- }
- func (r *UserRepo) UpdateStatus(ctx context.Context, id, status string) error {
- _, err := r.pool.Exec(ctx,
- `UPDATE users SET status=$1, updated_at=now() WHERE id=$2 AND deleted_at IS NULL`, status, id)
- return err
- }
- func (r *UserRepo) HasSuperadmin(ctx context.Context) (bool, error) {
- count, err := r.CountByRole(ctx, "superadmin")
- if err != nil {
- return false, err
- }
- return count > 0, nil
- }
- func (r *UserRepo) CountByRole(ctx context.Context, role string) (int, error) {
- var count int
- err := r.pool.QueryRow(ctx,
- `SELECT COUNT(*) FROM users WHERE role = $1 AND deleted_at IS NULL`, role,
- ).Scan(&count)
- if err != nil {
- return 0, fmt.Errorf("count by role: %w", err)
- }
- return count, nil
- }
- func (r *UserRepo) List(ctx context.Context, filter models.UserFilter) ([]*models.User, error) {
- query := `SELECT id, email, password_hash, role, status, name, avatar_url, phone, bio, country,
- created_at, updated_at, deleted_at
- FROM users WHERE deleted_at IS NULL`
- args := pgx.NamedArgs{}
- if filter.Role != "" {
- query += ` AND role = @role`
- args["role"] = filter.Role
- }
- if filter.Status != "" {
- query += ` AND status = @status`
- args["status"] = filter.Status
- }
- query += ` ORDER BY created_at DESC LIMIT @lim`
- args["lim"] = filter.Limit()
- rows, err := r.pool.Query(ctx, query, args)
- if err != nil {
- return nil, fmt.Errorf("list users: %w", err)
- }
- defer rows.Close()
- var users []*models.User
- for rows.Next() {
- u, err := scanUser(rows)
- if err != nil {
- return nil, err
- }
- users = append(users, u)
- }
- return users, nil
- }
- func scanUser(row interface{ Scan(dest ...any) error }) (*models.User, error) {
- var u models.User
- err := row.Scan(
- &u.ID, &u.Email, &u.PasswordHash, &u.Role, &u.Status,
- &u.Name, &u.AvatarURL, &u.Phone, &u.Bio, &u.Country,
- &u.CreatedAt, &u.UpdatedAt, &u.DeletedAt,
- )
- if err != nil {
- if err == pgx.ErrNoRows {
- return nil, nil
- }
- return nil, err
- }
- return &u, nil
- }
|