Files
backend/internal/database/user_repository.go

97 lines
3.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// File: backend/internal/database/user_repository.go
package database
import (
"context"
"database/sql"
"errors"
"gitea.mrixs.me/minecraft-platform/backend/internal/models"
"github.com/google/uuid"
)
var (
ErrUserExists = errors.New("user with this username or email already exists")
)
type UserRepository struct {
DB *sql.DB
}
// CreateUserTx создает нового пользователя и его профиль в рамках одной транзакции
func (r *UserRepository) CreateUserTx(ctx context.Context, user *models.User) error {
tx, err := r.DB.BeginTx(ctx, nil)
if err != nil {
return err
}
// Гарантируем откат транзакции в случае любой ошибки
defer tx.Rollback()
// Шаг 4 из ТЗ: Проверка уникальности
var exists bool
err = tx.QueryRowContext(ctx,
"SELECT EXISTS(SELECT 1 FROM users WHERE username = $1 OR email = $2)",
user.Username, user.Email).Scan(&exists)
if err != nil {
return err
}
if exists {
return ErrUserExists
}
// Шаг 7 из ТЗ: INSERT в таблицу users. Получаем ID нового пользователя.
var newUserID int
err = tx.QueryRowContext(ctx,
"INSERT INTO users (uuid, username, email, password_hash, role) VALUES ($1, $2, $3, $4, $5) RETURNING id",
user.UUID, user.Username, user.Email, user.PasswordHash, user.Role,
).Scan(&newUserID)
if err != nil {
return err
}
// Шаг 9 из ТЗ: INSERT в таблицу profiles
_, err = tx.ExecContext(ctx, "INSERT INTO profiles (user_id) VALUES ($1)", newUserID)
if err != nil {
return err
}
// Шаг 10 из ТЗ: Коммитим транзакцию
return tx.Commit()
}
var (
ErrUserExists = errors.New("user with this username or email already exists")
ErrUserNotFound = errors.New("user not found") // Новая ошибка
)
// ...
// GetUserByUsername находит пользователя по его имени.
// Возвращает полную структуру User, включая хеш пароля для проверки.
func (r *UserRepository) GetUserByUsername(ctx context.Context, username string) (*models.User, error) {
user := &models.User{}
var userUUID string
query := "SELECT id, uuid, username, email, password_hash, role FROM users WHERE username = $1"
err := r.DB.QueryRowContext(ctx, query, username).Scan(
&user.ID, &userUUID, &user.Username, &user.Email, &user.PasswordHash, &user.Role,
)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, ErrUserNotFound
}
return nil, err
}
user.UUID, _ = uuid.Parse(userUUID)
return user, nil
}
// CreateAccessToken сохраняет новый токен доступа в базу данных.
func (r *UserRepository) CreateAccessToken(ctx context.Context, userID int, accessToken, clientToken string) error {
query := "INSERT INTO access_tokens (user_id, access_token, client_token) VALUES ($1, $2, $3)"
_, err := r.DB.ExecContext(ctx, query, userID, accessToken, clientToken)
return err
}