generated from VLADIMIR/template
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package tickets_repo
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
var (
|
|
ErrTicketNotFound = errors.New("Билет не найден")
|
|
ErrTicketUsed = errors.New("Билет уже использован")
|
|
ErrGameFinished = errors.New("Игра уже завершена")
|
|
)
|
|
|
|
type Info struct {
|
|
ID int
|
|
Status string
|
|
GameName string
|
|
StartAt time.Time
|
|
Location *string
|
|
GameStatus string
|
|
UsedAt *time.Time
|
|
UsedBy *string
|
|
}
|
|
|
|
type Repo struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func New(pool *pgxpool.Pool) *Repo {
|
|
return &Repo{pool: pool}
|
|
}
|
|
|
|
func (r *Repo) CreateBatch(ctx context.Context, gameID int, tokenHashes [][]byte) ([]int, error) {
|
|
tx, err := r.pool.Begin(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() { _ = tx.Rollback(ctx) }()
|
|
|
|
ids := make([]int, 0, len(tokenHashes))
|
|
for _, tokenHash := range tokenHashes {
|
|
var id int
|
|
if err := tx.QueryRow(ctx,
|
|
`INSERT INTO tickets (game_id, token_hash) VALUES ($1, $2) RETURNING id`,
|
|
gameID, tokenHash,
|
|
).Scan(&id); err != nil {
|
|
return nil, err
|
|
}
|
|
ids = append(ids, id)
|
|
}
|
|
if err := tx.Commit(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
func (r *Repo) GetByHash(ctx context.Context, tokenHash []byte) (*Info, error) {
|
|
info := &Info{}
|
|
err := r.pool.QueryRow(ctx, `
|
|
SELECT t.id, t.status, s.name, g.start_at, g.location, g.status, t.used_at, u.username
|
|
FROM tickets t
|
|
JOIN games g ON g.id = t.game_id
|
|
JOIN scenarios s ON s.id = g.scenario_id
|
|
LEFT JOIN users u ON u.id = t.used_by
|
|
WHERE t.token_hash = $1`, tokenHash).Scan(
|
|
&info.ID, &info.Status, &info.GameName, &info.StartAt, &info.Location, &info.GameStatus, &info.UsedAt, &info.UsedBy)
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, ErrTicketNotFound
|
|
}
|
|
return info, err
|
|
}
|
|
|
|
func (r *Repo) Accept(ctx context.Context, tokenHash []byte, userID int) (*Info, error) {
|
|
var status, gameStatus string
|
|
if err := r.pool.QueryRow(ctx, `
|
|
SELECT t.status, g.status
|
|
FROM tickets t JOIN games g ON g.id = t.game_id
|
|
WHERE t.token_hash = $1`, tokenHash).Scan(&status, &gameStatus); errors.Is(err, pgx.ErrNoRows) {
|
|
return nil, ErrTicketNotFound
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
if status == "used" {
|
|
return nil, ErrTicketUsed
|
|
}
|
|
if gameStatus == "finish" {
|
|
return nil, ErrGameFinished
|
|
}
|
|
|
|
tag, err := r.pool.Exec(ctx, `
|
|
UPDATE tickets t SET status = 'used', used_at = NOW(), used_by = $2
|
|
FROM games g
|
|
WHERE t.game_id = g.id AND t.token_hash = $1 AND t.status = 'active' AND g.status <> 'finish'`, tokenHash, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tag.RowsAffected() == 0 {
|
|
if status == "used" {
|
|
return nil, ErrTicketUsed
|
|
}
|
|
return nil, ErrGameFinished
|
|
}
|
|
return r.GetByHash(ctx, tokenHash)
|
|
}
|