generated from VLADIMIR/template
add get ticket
This commit is contained in:
@@ -5,11 +5,41 @@ import (
|
||||
|
||||
"evening_detective_server/internal/modules/processor_jwt"
|
||||
"evening_detective_server/internal/modules/roles"
|
||||
"evening_detective_server/internal/services/ticket_service"
|
||||
"evening_detective_server/proto"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func (s *server) GetTicket(ctx context.Context, req *proto.GetTicketReq) (*proto.GetTicketRsp, error) {
|
||||
_ = grpc.SetHeader(ctx, metadata.Pairs("Cache-Control", "no-store"))
|
||||
if req == nil {
|
||||
return &proto.GetTicketRsp{Error: ticket_service.ErrTicketNotFound.Error()}, nil
|
||||
}
|
||||
page, err := s.ticketService.Get(ctx, req.Token)
|
||||
if err != nil {
|
||||
return &proto.GetTicketRsp{Error: ticket_service.ErrTicketNotFound.Error()}, nil
|
||||
}
|
||||
|
||||
result := &proto.TicketPage{
|
||||
Id: int32(page.ID),
|
||||
GameName: page.GameName,
|
||||
StartAt: timestamppb.New(page.StartAt),
|
||||
Status: page.Status,
|
||||
GameStatus: page.GameStatus,
|
||||
}
|
||||
if page.Location != nil {
|
||||
result.Location = *page.Location
|
||||
}
|
||||
if page.UsedAt != nil {
|
||||
result.UsedAt = timestamppb.New(*page.UsedAt)
|
||||
}
|
||||
return &proto.GetTicketRsp{Ticket: result}, nil
|
||||
}
|
||||
|
||||
func (s *server) IssueGameTickets(ctx context.Context, req *proto.IssueGameTicketsReq) (*proto.IssueGameTicketsRsp, error) {
|
||||
claims, ok := ctx.Value("claims").(*processor_jwt.JWTClaims)
|
||||
if !ok || claims == nil {
|
||||
|
||||
@@ -2,10 +2,25 @@ package tickets_repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
var ErrTicketNotFound = errors.New("Билет не найден")
|
||||
|
||||
type Info struct {
|
||||
ID int
|
||||
Status string
|
||||
GameName string
|
||||
StartAt time.Time
|
||||
Location *string
|
||||
GameStatus string
|
||||
UsedAt *time.Time
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
@@ -37,3 +52,16 @@ func (r *Repo) CreateBatch(ctx context.Context, gameID int, tokenHashes [][]byte
|
||||
}
|
||||
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, g.name, g.start_at, g.location, g.status, t.used_at
|
||||
FROM tickets t JOIN games g ON g.id = t.game_id
|
||||
WHERE t.token_hash = $1`, tokenHash).Scan(
|
||||
&info.ID, &info.Status, &info.GameName, &info.StartAt, &info.Location, &info.GameStatus, &info.UsedAt)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, ErrTicketNotFound
|
||||
}
|
||||
return info, err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"evening_detective_server/internal/repos/tickets_repo"
|
||||
)
|
||||
@@ -18,6 +19,7 @@ const maxTicketsPerRequest = 100
|
||||
var (
|
||||
ErrInvalidTicketCount = errors.New("количество билетов должно быть от 1 до 100")
|
||||
ErrInvalidBaseURL = errors.New("необходимо настроить APP_BASE_URL — публичный адрес приложения")
|
||||
ErrTicketNotFound = tickets_repo.ErrTicketNotFound
|
||||
)
|
||||
|
||||
type Ticket struct {
|
||||
@@ -25,6 +27,16 @@ type Ticket struct {
|
||||
URL string
|
||||
}
|
||||
|
||||
type Page struct {
|
||||
ID int
|
||||
Status string
|
||||
GameName string
|
||||
StartAt time.Time
|
||||
Location *string
|
||||
GameStatus string
|
||||
UsedAt *time.Time
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
repo *tickets_repo.Repo
|
||||
appBaseURL string
|
||||
@@ -71,6 +83,26 @@ func (s *Service) Issue(ctx context.Context, gameID, count int) ([]*Ticket, erro
|
||||
return tickets, nil
|
||||
}
|
||||
|
||||
func (s *Service) Get(ctx context.Context, token string) (*Page, error) {
|
||||
hash, err := tokenHash(token)
|
||||
if err != nil {
|
||||
return nil, ErrTicketNotFound
|
||||
}
|
||||
info, err := s.repo.GetByHash(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Page{
|
||||
ID: info.ID,
|
||||
Status: info.Status,
|
||||
GameName: info.GameName,
|
||||
StartAt: info.StartAt,
|
||||
Location: info.Location,
|
||||
GameStatus: info.GameStatus,
|
||||
UsedAt: info.UsedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newToken() (string, error) {
|
||||
data := make([]byte, 32)
|
||||
if _, err := rand.Read(data); err != nil {
|
||||
@@ -79,6 +111,15 @@ func newToken() (string, error) {
|
||||
return base64.RawURLEncoding.EncodeToString(data), nil
|
||||
}
|
||||
|
||||
func tokenHash(token string) ([]byte, error) {
|
||||
data, err := base64.RawURLEncoding.DecodeString(token)
|
||||
if err != nil || len(data) != 32 {
|
||||
return nil, ErrTicketNotFound
|
||||
}
|
||||
hash := sha256.Sum256([]byte(token))
|
||||
return hash[:], nil
|
||||
}
|
||||
|
||||
func parseBaseURL(value string) (*url.URL, error) {
|
||||
base, err := url.Parse(strings.TrimSpace(value))
|
||||
if err != nil || base.Host == "" || (base.Scheme != "http" && base.Scheme != "https") || base.User != nil || base.RawQuery != "" || base.Fragment != "" {
|
||||
|
||||
Reference in New Issue
Block a user