generated from VLADIMIR/template
add team service
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package game_service
|
||||
|
||||
import "evening_detective_server/internal/modules/storytelling"
|
||||
import (
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
)
|
||||
|
||||
// Answer — ответ команды на вопрос дела (для публичного API команды).
|
||||
type Answer struct {
|
||||
@@ -18,7 +21,7 @@ type AnswerScore struct {
|
||||
|
||||
// TeamAnswers — ответы одной команды игры.
|
||||
type TeamAnswers struct {
|
||||
Team *Team
|
||||
Team *game_model.Team
|
||||
Answers []AnswerScore
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package game_service
|
||||
|
||||
import (
|
||||
"evening_detective_server/internal/services/scenarios_service"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
Format string
|
||||
ID int
|
||||
Name string
|
||||
Description string
|
||||
StartAt time.Time
|
||||
Status string
|
||||
Scenario *scenarios_service.Scenario
|
||||
Teams []*Team
|
||||
StartedAt *time.Time
|
||||
EndedAt *time.Time
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package game_service
|
||||
|
||||
import (
|
||||
"evening_detective_server/internal/repos"
|
||||
"evening_detective_server/internal/services/scenarios_service"
|
||||
)
|
||||
|
||||
func mapGame(
|
||||
o *repos.Game,
|
||||
domain string,
|
||||
) *Game {
|
||||
return &Game{
|
||||
ID: o.ID,
|
||||
Name: o.Name,
|
||||
Description: o.Description,
|
||||
StartAt: o.StartAt,
|
||||
Status: o.Status,
|
||||
Format: o.Format,
|
||||
Scenario: scenarios_service.MapScenarioLight(o.Scenario, domain),
|
||||
Teams: mapTeams(o.Teams),
|
||||
StartedAt: o.StartedAt,
|
||||
EndedAt: o.EndedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func mapGames(
|
||||
o []*repos.Game,
|
||||
domain string,
|
||||
) []*Game {
|
||||
res := make([]*Game, 0, len(o))
|
||||
for _, item := range o {
|
||||
res = append(res, mapGame(item, domain))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package game_service
|
||||
|
||||
import (
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"sort"
|
||||
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
@@ -9,7 +10,7 @@ import (
|
||||
// TeamResult — строка итоговой таблицы: команда, баллы по вопросам (в порядке
|
||||
// сценария), сумма баллов и место.
|
||||
type TeamResult struct {
|
||||
Team *Team
|
||||
Team *game_model.Team
|
||||
Answers []AnswerScore
|
||||
// TotalScore — сумма баллов по всем вопросам сценария; неоценённые
|
||||
// вопросы считаются как 0.
|
||||
@@ -34,7 +35,7 @@ type GameResults struct {
|
||||
// rankTeams.
|
||||
func buildTeamResults(
|
||||
questions []*storytelling.Question,
|
||||
teams []*Team,
|
||||
teams []*game_model.Team,
|
||||
answerByTeamAndCode map[int]map[string]AnswerScore,
|
||||
) []TeamResult {
|
||||
res := make([]TeamResult, 0, len(teams))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package game_service
|
||||
|
||||
import (
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"testing"
|
||||
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
@@ -10,7 +11,7 @@ func intPtr(v int) *int { return &v }
|
||||
|
||||
func teamResult(id, actions, total int) TeamResult {
|
||||
return TeamResult{
|
||||
Team: &Team{ID: id, ActionsCount: actions},
|
||||
Team: &game_model.Team{ID: id, ActionsCount: actions},
|
||||
TotalScore: total,
|
||||
}
|
||||
}
|
||||
@@ -105,7 +106,7 @@ func TestBuildTeamResultsScenarioOrderAndNilScores(t *testing.T) {
|
||||
{Code: "q2", Text: "Вопрос 2"},
|
||||
{Code: "q3", Text: "Вопрос 3"},
|
||||
}
|
||||
teams := []*Team{
|
||||
teams := []*game_model.Team{
|
||||
{ID: 1, Name: "А", ActionsCount: 4},
|
||||
{ID: 2, Name: "Б", ActionsCount: 2},
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"evening_detective_server/internal/modules/cleaner"
|
||||
"evening_detective_server/internal/modules/password_generator"
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
"evening_detective_server/internal/modules/team_qr_pdf"
|
||||
"evening_detective_server/internal/repos"
|
||||
"evening_detective_server/internal/repos/actions_repo"
|
||||
"evening_detective_server/internal/repos/applications_repo"
|
||||
@@ -15,24 +14,20 @@ import (
|
||||
"evening_detective_server/internal/repos/team_answers_repo"
|
||||
"evening_detective_server/internal/repos/teams_repo"
|
||||
"evening_detective_server/internal/services/scenarios_service"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GameService struct {
|
||||
gamesRepo *games_repo.GamesRepo
|
||||
teamsRepo *teams_repo.TeamsRepo
|
||||
scenariosRepo *scenarios_repo.ScenariosRepo
|
||||
scenarioService *scenarios_service.ScenarioService
|
||||
domain string
|
||||
passwordGenerator password_generator.IPasswordGenerator
|
||||
storyteller storytelling.IStory
|
||||
actionsRepo *actions_repo.ActionsRepo
|
||||
applicationsRepo *applications_repo.ApplicationsRepo
|
||||
answersRepo *team_answers_repo.TeamAnswersRepo
|
||||
cleaner cleaner.ICleaner
|
||||
teamQRGenerator team_qr_pdf.IGenerator
|
||||
appBaseURL string
|
||||
gamesRepo *games_repo.GamesRepo
|
||||
teamsRepo *teams_repo.TeamsRepo
|
||||
scenariosRepo *scenarios_repo.ScenariosRepo
|
||||
scenarioService *scenarios_service.ScenarioService
|
||||
domain string
|
||||
storyteller storytelling.IStory
|
||||
actionsRepo *actions_repo.ActionsRepo
|
||||
applicationsRepo *applications_repo.ApplicationsRepo
|
||||
answersRepo *team_answers_repo.TeamAnswersRepo
|
||||
cleaner cleaner.ICleaner
|
||||
}
|
||||
|
||||
func NewGameService(
|
||||
@@ -41,29 +36,23 @@ func NewGameService(
|
||||
scenariosRepo *scenarios_repo.ScenariosRepo,
|
||||
scenarioService *scenarios_service.ScenarioService,
|
||||
domain string,
|
||||
passwordGenerator password_generator.IPasswordGenerator,
|
||||
storyteller storytelling.IStory,
|
||||
actionsRepo *actions_repo.ActionsRepo,
|
||||
applicationsRepo *applications_repo.ApplicationsRepo,
|
||||
answersRepo *team_answers_repo.TeamAnswersRepo,
|
||||
cleaner cleaner.ICleaner,
|
||||
teamQRGenerator team_qr_pdf.IGenerator,
|
||||
appBaseURL string,
|
||||
) *GameService {
|
||||
return &GameService{
|
||||
gamesRepo: gamesRepo,
|
||||
teamsRepo: teamsRepo,
|
||||
scenariosRepo: scenariosRepo,
|
||||
scenarioService: scenarioService,
|
||||
domain: domain,
|
||||
passwordGenerator: passwordGenerator,
|
||||
storyteller: storyteller,
|
||||
actionsRepo: actionsRepo,
|
||||
applicationsRepo: applicationsRepo,
|
||||
answersRepo: answersRepo,
|
||||
cleaner: cleaner,
|
||||
teamQRGenerator: teamQRGenerator,
|
||||
appBaseURL: appBaseURL,
|
||||
gamesRepo: gamesRepo,
|
||||
teamsRepo: teamsRepo,
|
||||
scenariosRepo: scenariosRepo,
|
||||
scenarioService: scenarioService,
|
||||
domain: domain,
|
||||
storyteller: storyteller,
|
||||
actionsRepo: actionsRepo,
|
||||
applicationsRepo: applicationsRepo,
|
||||
answersRepo: answersRepo,
|
||||
cleaner: cleaner,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,21 +77,21 @@ func (s *GameService) AddGame(
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (s *GameService) GetGame(ctx context.Context, id int) (*Game, error) {
|
||||
func (s *GameService) GetGame(ctx context.Context, id int) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := mapGame(game, s.domain)
|
||||
res := game_model.MapGame(game, s.domain)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *GameService) GetGameMedia(ctx context.Context, id int) (*Game, error) {
|
||||
func (s *GameService) GetGameMedia(ctx context.Context, id int) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gameResult := mapGame(game, s.domain)
|
||||
gameResult := game_model.MapGame(game, s.domain)
|
||||
gameResult.Scenario, err = s.scenarioService.GetFullScenarioByID(ctx, game.ScenarioId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -113,7 +102,7 @@ func (s *GameService) GetGameMedia(ctx context.Context, id int) (*Game, error) {
|
||||
func (s *GameService) GetFullGame(
|
||||
ctx context.Context,
|
||||
id int,
|
||||
) (*Game, error) {
|
||||
) (*game_model.Game, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -129,7 +118,7 @@ func (s *GameService) GetFullGame(
|
||||
}
|
||||
game.Teams = teams
|
||||
|
||||
res := mapGame(game, s.domain)
|
||||
res := game_model.MapGame(game, s.domain)
|
||||
|
||||
teamIds := make([]int, 0, len(game.Teams))
|
||||
for _, team := range game.Teams {
|
||||
@@ -163,12 +152,12 @@ func (s *GameService) DeleteGame(
|
||||
|
||||
func (s *GameService) GetGames(
|
||||
ctx context.Context,
|
||||
) ([]*Game, error) {
|
||||
) ([]*game_model.Game, error) {
|
||||
games, err := s.gamesRepo.GetGames(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mapGames(games, s.domain), nil
|
||||
return game_model.MapGames(games, s.domain), nil
|
||||
}
|
||||
|
||||
func (s *GameService) UpdateGame(
|
||||
@@ -213,48 +202,11 @@ func (s *GameService) ResetGame(ctx context.Context, id int) error {
|
||||
return s.gamesRepo.ResetGame(ctx, id)
|
||||
}
|
||||
|
||||
func (s *GameService) AddTeam(
|
||||
ctx context.Context,
|
||||
creatorId int,
|
||||
gameId int,
|
||||
name string,
|
||||
captainEmail string,
|
||||
) (*Team, error) {
|
||||
captainEmail = strings.TrimSpace(captainEmail)
|
||||
if captainEmail != "" && !validCaptainEmail(captainEmail) {
|
||||
return nil, errors.New("Укажите корректную почту капитана")
|
||||
}
|
||||
password, err := s.passwordGenerator.Generate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := s.teamsRepo.AddTeamWithParticipation(ctx, creatorId, gameId, name, password, captainEmail, !time.Now().Before(game.StartAt.Add(-24*time.Hour)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Team{
|
||||
ID: id,
|
||||
Password: password,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *GameService) UpdateTeam(ctx context.Context, teamId int, name string) error {
|
||||
return s.teamsRepo.UpdateTeam(ctx, teamId, name)
|
||||
}
|
||||
|
||||
func (s *GameService) DeleteTeam(ctx context.Context, teamId int) error {
|
||||
return s.teamsRepo.DeleteTeam(ctx, teamId)
|
||||
}
|
||||
|
||||
func (s *GameService) GiveTeamApplications(ctx context.Context, teamId int, name string) error {
|
||||
return s.applicationsRepo.UpdateApplicationStatus(ctx, teamId, name, "done")
|
||||
}
|
||||
|
||||
func (s *GameService) GetTeamActions(ctx context.Context, teamId int, password string) (*storytelling.Story, *Game, []actions_repo.Action, error) {
|
||||
func (s *GameService) GetTeamActions(ctx context.Context, teamId int, password string) (*storytelling.Story, *game_model.Game, []actions_repo.Action, error) {
|
||||
team, err := s.teamsRepo.GetTeamByID(ctx, teamId)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
@@ -269,7 +221,7 @@ func (s *GameService) GetTeamActions(ctx context.Context, teamId int, password s
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if game.Status == "finish" {
|
||||
return &storytelling.Story{}, mapGame(game, s.domain), nil, nil
|
||||
return &storytelling.Story{}, game_model.MapGame(game, s.domain), nil, nil
|
||||
}
|
||||
|
||||
actions, err := s.actionsRepo.GetActionsByTeamID(ctx, teamId)
|
||||
@@ -288,7 +240,7 @@ func (s *GameService) GetTeamActions(ctx context.Context, teamId int, password s
|
||||
}
|
||||
story := s.storyteller.GetStory(scenario.Story, codes)
|
||||
filterTeamStory(story, game.Format)
|
||||
return story, mapGame(game, s.domain), actions, nil
|
||||
return story, game_model.MapGame(game, s.domain), actions, nil
|
||||
}
|
||||
|
||||
func (s *GameService) AddTeamAction(ctx context.Context, teamId int, password string, actionCode string, viaMCP bool) error {
|
||||
@@ -546,7 +498,7 @@ func (s *GameService) GetGameAnswers(ctx context.Context, gameId int) (*GameAnsw
|
||||
answers = append(answers, AnswerScore{QuestionCode: question.Code})
|
||||
}
|
||||
teamAnswers = append(teamAnswers, TeamAnswers{
|
||||
Team: mapTeam(team),
|
||||
Team: game_model.MapTeam(team),
|
||||
Answers: answers,
|
||||
})
|
||||
}
|
||||
@@ -626,9 +578,9 @@ func (s *GameService) GetGameResults(ctx context.Context, gameId int) (*GameResu
|
||||
Score: row.Score,
|
||||
}
|
||||
}
|
||||
mappedTeams := make([]*Team, 0, len(teams))
|
||||
mappedTeams := make([]*game_model.Team, 0, len(teams))
|
||||
for _, team := range teams {
|
||||
mapped := mapTeam(team)
|
||||
mapped := game_model.MapTeam(team)
|
||||
mapped.ActionsCount = actionsCountByTeamIDs[team.ID]
|
||||
mappedTeams = append(mappedTeams, mapped)
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package game_service
|
||||
|
||||
import "evening_detective_server/internal/modules/storytelling"
|
||||
|
||||
type Team struct {
|
||||
ParticipationStatus string
|
||||
ParticipationSource string
|
||||
ParticipationEmailError string
|
||||
ParticipationEmailSent bool
|
||||
CaptainEmail string
|
||||
ParticipantsCount int32
|
||||
ID int
|
||||
Name string
|
||||
Status string
|
||||
Password string
|
||||
ActionsCount int
|
||||
Applications []*storytelling.Application
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package game_service
|
||||
|
||||
import "evening_detective_server/internal/repos"
|
||||
|
||||
func mapTeam(
|
||||
o *repos.Team,
|
||||
) *Team {
|
||||
return &Team{
|
||||
ParticipationStatus: o.ParticipationStatus,
|
||||
ParticipationSource: o.ParticipationSource,
|
||||
ParticipationEmailError: o.ParticipationEmailError,
|
||||
ParticipationEmailSent: o.ParticipationEmailSent,
|
||||
ID: o.ID,
|
||||
CaptainEmail: o.CaptainEmail,
|
||||
ParticipantsCount: o.ParticipantsCount,
|
||||
Name: o.Name,
|
||||
Status: o.Status,
|
||||
Password: o.Password,
|
||||
}
|
||||
}
|
||||
|
||||
func mapTeams(
|
||||
o []*repos.Team,
|
||||
) []*Team {
|
||||
res := make([]*Team, 0, len(o))
|
||||
for _, item := range o {
|
||||
res = append(res, mapTeam(item))
|
||||
}
|
||||
return res
|
||||
}
|
||||
@@ -2,13 +2,13 @@ package mcp_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"evening_detective_server/internal/modules/storytelling"
|
||||
"evening_detective_server/internal/services/game_service"
|
||||
|
||||
"github.com/mark3labs/mcp-go/client"
|
||||
"github.com/mark3labs/mcp-go/mcp"
|
||||
@@ -82,6 +82,6 @@ func TestStreamableHTTPEndToEnd(t *testing.T) {
|
||||
func TestMockTypesUsable(t *testing.T) {
|
||||
_ = defaultStory()
|
||||
_ = defaultGame()
|
||||
_ = (*game_service.Game)(nil)
|
||||
_ = (*game_model.Game)(nil)
|
||||
_ = (*storytelling.Story)(nil)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package mcp_service
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -30,7 +31,7 @@ const defaultCallTimeout = 10 * time.Second
|
||||
// *game_service.GameService; интерфейс позволяет тестировать сервис
|
||||
// без БД.
|
||||
type GamePlayer interface {
|
||||
GetTeamActions(ctx context.Context, teamId int, password string) (*storytelling.Story, *game_service.Game, []actions_repo.Action, error)
|
||||
GetTeamActions(ctx context.Context, teamId int, password string) (*storytelling.Story, *game_model.Game, []actions_repo.Action, error)
|
||||
AddTeamAction(ctx context.Context, teamId int, password, actionCode string, viaMCP bool) error
|
||||
SubmitTeamAnswers(ctx context.Context, teamId int, password string, answers []game_service.Answer) error
|
||||
}
|
||||
@@ -163,7 +164,7 @@ func parseConnectURL(rawURL string) (connectArgs, error) {
|
||||
}
|
||||
|
||||
// gameResponse — компактное описание игры для ответа инструментов
|
||||
// (game_service.Game JSON-тегов не имеет).
|
||||
// (game_model.Game JSON-тегов не имеет).
|
||||
type gameResponse struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -177,7 +178,7 @@ type storyResponse struct {
|
||||
}
|
||||
|
||||
// storyJSON сериализует историю команды и игру в JSON.
|
||||
func storyJSON(story *storytelling.Story, game *game_service.Game) (string, error) {
|
||||
func storyJSON(story *storytelling.Story, game *game_model.Game) (string, error) {
|
||||
resp := storyResponse{
|
||||
Story: story,
|
||||
Game: &gameResponse{
|
||||
|
||||
@@ -3,6 +3,7 @@ package mcp_service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -19,12 +20,12 @@ import (
|
||||
// ошибками (реализует интерфейс GamePlayer, БД не нужна).
|
||||
type fakeGamePlayer struct {
|
||||
story *storytelling.Story
|
||||
game *game_service.Game
|
||||
game *game_model.Game
|
||||
err error
|
||||
viaMCP bool
|
||||
}
|
||||
|
||||
func (f *fakeGamePlayer) GetTeamActions(_ context.Context, teamID int, password string) (*storytelling.Story, *game_service.Game, []actions_repo.Action, error) {
|
||||
func (f *fakeGamePlayer) GetTeamActions(_ context.Context, teamID int, password string) (*storytelling.Story, *game_model.Game, []actions_repo.Action, error) {
|
||||
if f.err != nil {
|
||||
return nil, nil, nil, f.err
|
||||
}
|
||||
@@ -65,8 +66,8 @@ func defaultStory() *storytelling.Story {
|
||||
}
|
||||
}
|
||||
|
||||
func defaultGame() *game_service.Game {
|
||||
return &game_service.Game{
|
||||
func defaultGame() *game_model.Game {
|
||||
return &game_model.Game{
|
||||
ID: 1,
|
||||
Name: "Игра 1",
|
||||
Status: "started",
|
||||
|
||||
@@ -222,7 +222,7 @@ func TestParticipationPostgres(t *testing.T) {
|
||||
t.Fatal("cancelled team in active list")
|
||||
}
|
||||
}
|
||||
gameService := game_service.NewGameService(nil, repo, nil, nil, "", nil, nil, nil, nil, nil, nil, nil, "")
|
||||
gameService := game_service.NewGameService(nil, repo, nil, nil, "", nil, nil, nil, nil, nil)
|
||||
if _, _, _, err := gameService.GetTeamActions(ctx, 3, "secret"); !errors.Is(err, teams_repo.ErrTeamNotFound) {
|
||||
t.Fatalf("cancelled team got story: %v", err)
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package game_service
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -13,7 +13,7 @@ func TestManualTeamEmail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
for _, email := range []string{"invalid", "Captain <captain@example.org>", "a@example.org\r\nBcc: other@example.org", strings.Repeat("a", 250) + "@example.org"} {
|
||||
service := &GameService{}
|
||||
service := &TeamService{}
|
||||
if _, err := service.AddTeam(context.Background(), 1, 1, "Team", email); err == nil {
|
||||
t.Errorf("accepted invalid email %q", email)
|
||||
}
|
||||
+1
-22
@@ -1,14 +1,12 @@
|
||||
package game_service
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/mail"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
@@ -65,22 +63,3 @@ func (r *Registration) Validate() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *GameService) RegisterTeam(ctx context.Context, gameID int, deliveryID string, registration Registration) (int, error) {
|
||||
if err := registration.Validate(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if gameID <= 0 || deliveryID == "" || len(deliveryID) > 255 || strings.ContainsRune(deliveryID, 0) {
|
||||
return 0, ErrInvalidRegistration
|
||||
}
|
||||
password, err := s.passwordGenerator.Generate()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
autoConfirm := time.Now().Before(game.StartAt.Add(-24*time.Hour)) == false
|
||||
return s.teamsRepo.RegisterTeamWithParticipation(ctx, gameID, deliveryID, registration.Name, registration.Email, registration.ParticipantsCount, password, autoConfirm)
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package game_service
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@@ -0,0 +1,113 @@
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"evening_detective_server/internal/modules/game_model"
|
||||
"evening_detective_server/internal/modules/password_generator"
|
||||
"evening_detective_server/internal/modules/team_qr_pdf"
|
||||
"evening_detective_server/internal/repos/games_repo"
|
||||
"evening_detective_server/internal/repos/teams_repo"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TeamService struct {
|
||||
gamesRepo *games_repo.GamesRepo
|
||||
teamsRepo *teams_repo.TeamsRepo
|
||||
passwordGenerator password_generator.IPasswordGenerator
|
||||
teamQRGenerator team_qr_pdf.IGenerator
|
||||
appBaseURL string
|
||||
}
|
||||
|
||||
func NewTeamService(
|
||||
gamesRepo *games_repo.GamesRepo,
|
||||
teamsRepo *teams_repo.TeamsRepo,
|
||||
passwordGenerator password_generator.IPasswordGenerator,
|
||||
teamQRGenerator team_qr_pdf.IGenerator,
|
||||
appBaseURL string,
|
||||
) *TeamService {
|
||||
return &TeamService{
|
||||
gamesRepo: gamesRepo,
|
||||
teamsRepo: teamsRepo,
|
||||
passwordGenerator: passwordGenerator,
|
||||
teamQRGenerator: teamQRGenerator,
|
||||
appBaseURL: appBaseURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TeamService) AddTeam(
|
||||
ctx context.Context,
|
||||
creatorId int,
|
||||
gameId int,
|
||||
name string,
|
||||
captainEmail string,
|
||||
) (*game_model.Team, error) {
|
||||
captainEmail = strings.TrimSpace(captainEmail)
|
||||
if captainEmail != "" && !validCaptainEmail(captainEmail) {
|
||||
return nil, errors.New("Укажите корректную почту капитана")
|
||||
}
|
||||
password, err := s.passwordGenerator.Generate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := s.teamsRepo.AddTeamWithParticipation(ctx, creatorId, gameId, name, password, captainEmail, !time.Now().Before(game.StartAt.Add(-24*time.Hour)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &game_model.Team{
|
||||
ID: id,
|
||||
Password: password,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *TeamService) UpdateTeam(ctx context.Context, teamId int, name string) error {
|
||||
return s.teamsRepo.UpdateTeam(ctx, teamId, name)
|
||||
}
|
||||
|
||||
func (s *TeamService) DeleteTeam(ctx context.Context, teamId int) error {
|
||||
return s.teamsRepo.DeleteTeam(ctx, teamId)
|
||||
}
|
||||
|
||||
func (s *TeamService) RegisterTeam(ctx context.Context, gameID int, deliveryID string, registration Registration) (int, error) {
|
||||
if err := registration.Validate(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if gameID <= 0 || deliveryID == "" || len(deliveryID) > 255 || strings.ContainsRune(deliveryID, 0) {
|
||||
return 0, ErrInvalidRegistration
|
||||
}
|
||||
password, err := s.passwordGenerator.Generate()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, gameID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
autoConfirm := time.Now().Before(game.StartAt.Add(-24*time.Hour)) == false
|
||||
return s.teamsRepo.RegisterTeamWithParticipation(ctx, gameID, deliveryID, registration.Name, registration.Email, registration.ParticipantsCount, password, autoConfirm)
|
||||
}
|
||||
|
||||
func (s *TeamService) DownloadTeamQR(ctx context.Context, id int) ([]byte, string, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
teams, err := s.teamsRepo.GetActiveTeamsByGameID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if len(teams) == 0 {
|
||||
return nil, "", team_qr_pdf.ErrNoTeams
|
||||
}
|
||||
cards, filename, err := teamQRData(s.appBaseURL, game, teams)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
data, err := s.teamQRGenerator.Generate(cards)
|
||||
return data, filename, err
|
||||
}
|
||||
+1
-22
@@ -1,7 +1,6 @@
|
||||
package game_service
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
@@ -12,26 +11,6 @@ import (
|
||||
"evening_detective_server/internal/repos"
|
||||
)
|
||||
|
||||
func (s *GameService) DownloadTeamQR(ctx context.Context, id int) ([]byte, string, error) {
|
||||
game, err := s.gamesRepo.GetGameByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
teams, err := s.teamsRepo.GetActiveTeamsByGameID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if len(teams) == 0 {
|
||||
return nil, "", team_qr_pdf.ErrNoTeams
|
||||
}
|
||||
cards, filename, err := teamQRData(s.appBaseURL, game, teams)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
data, err := s.teamQRGenerator.Generate(cards)
|
||||
return data, filename, err
|
||||
}
|
||||
|
||||
func teamQRData(baseURL string, game *repos.Game, teams []*repos.Team) ([]team_qr_pdf.Card, string, error) {
|
||||
base, err := url.Parse(strings.TrimSpace(baseURL))
|
||||
if err != nil || (base.Scheme != "http" && base.Scheme != "https") || base.Host == "" || base.User != nil || base.RawQuery != "" || base.Fragment != "" {
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package game_service
|
||||
package team_service
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
Reference in New Issue
Block a user