This commit is contained in:
2026-10-11 16:00:18 +07:00
parent 504b49f7cc
commit 030ca56900
77 changed files with 793 additions and 638 deletions
@@ -35,7 +35,7 @@ func TestRegistrationValidation(t *testing.T) {
func TestRegistrationEmail(t *testing.T) {
message := registrationEmail(&repos.Team{
ID: 7,
ID: "019a1234-5678-7abc-8def-000000000007",
Name: "Команда",
CaptainEmail: "captain@example.org",
ParticipantsCount: 5,
@@ -49,8 +49,8 @@ func TestRegistrationEmail(t *testing.T) {
t.Errorf("registration email has incorrect team data: %q", value)
}
}
if !strings.Contains(message.Body, "https://app.test/team-story/7?password=abcdefgh") ||
!strings.Contains(message.HTML, "team-story/7?password=abcdefgh") {
if !strings.Contains(message.Body, "https://app.test/team-story/019a1234-5678-7abc-8def-000000000007?password=abcdefgh") ||
!strings.Contains(message.HTML, "team-story/019a1234-5678-7abc-8def-000000000007?password=abcdefgh") {
t.Error("registration email misses the password link")
}
}
+13 -13
View File
@@ -81,7 +81,7 @@ func (s *TeamService) AddTeam(
}
// UpdateTeam changes a team's name.
func (s *TeamService) UpdateTeam(ctx context.Context, teamID int, name string) error {
func (s *TeamService) UpdateTeam(ctx context.Context, teamID string, name string) error {
err := s.teamsRepo.UpdateTeam(ctx, teamID, name)
if errors.Is(err, teams_repo.ErrTeamNotFound) {
return ErrTeamNotFound
@@ -90,7 +90,7 @@ func (s *TeamService) UpdateTeam(ctx context.Context, teamID int, name string) e
}
// DeleteTeam removes a team.
func (s *TeamService) DeleteTeam(ctx context.Context, teamID int) error {
func (s *TeamService) DeleteTeam(ctx context.Context, teamID string) error {
err := s.teamsRepo.DeleteTeam(ctx, teamID)
if errors.Is(err, teams_repo.ErrTeamNotFound) {
return ErrTeamNotFound
@@ -99,44 +99,44 @@ func (s *TeamService) DeleteTeam(ctx context.Context, teamID int) error {
}
// RegisterTeam registers a team for a game.
func (s *TeamService) RegisterTeam(ctx context.Context, gameID int, deliveryID string, registration Registration) (int, error) {
func (s *TeamService) RegisterTeam(ctx context.Context, gameID int, deliveryID string, registration Registration) (string, error) {
if err := registration.Validate(); err != nil {
return 0, err
return "", err
}
if gameID <= 0 || deliveryID == "" || len(deliveryID) > 255 || strings.ContainsRune(deliveryID, 0) {
return 0, ErrInvalidRegistration
return "", ErrInvalidRegistration
}
password, err := s.passwordGenerator.Generate()
if err != nil {
return 0, err
return "", err
}
game, err := s.gamesRepo.GetGameByID(ctx, gameID)
if err != nil {
return 0, err
return "", err
}
autoConfirm := !time.Now().Before(game.StartAt.Add(-24 * time.Hour))
id, err := s.teamsRepo.RegisterTeamWithParticipation(ctx, gameID, deliveryID, registration.Name, registration.Email, registration.ParticipantsCount, password, autoConfirm)
if err != nil {
if errors.Is(err, teams_repo.ErrRegistrationClosed) {
return 0, ErrRegistrationClosed
return "", ErrRegistrationClosed
}
return 0, err
return "", err
}
if s.emailSender == nil {
return id, nil
}
team, err := s.teamsRepo.GetTeamByID(ctx, id)
if err != nil {
return 0, err
return "", err
}
if err := s.emailSender.Send(ctx, registrationEmail(team, game.Name, s.appBaseURL)); err != nil {
return 0, fmt.Errorf("email send: %w", err)
return "", fmt.Errorf("email send: %w", err)
}
return id, nil
}
func registrationEmail(team *repos.Team, gameName, baseURL string) email_sender.Message {
link := strings.TrimRight(baseURL, "/") + "/team-story/" + fmt.Sprint(team.ID) + "?password=" + team.Password
link := strings.TrimRight(baseURL, "/") + "/team-story/" + team.ID + "?password=" + team.Password
body := fmt.Sprintf("Регистрация команды «%s» в игре «%s» прошла успешно.\n\nУчастников: %d\n\nСсылка для входа в игру: %s", team.Name, gameName, team.ParticipantsCount, link)
content := fmt.Sprintf("<p class=\"email-text\">Регистрация команды <strong>%s</strong> в игре <strong>%s</strong> прошла успешно.</p><p class=\"email-text\">Участников: %d</p>%s", html.EscapeString(team.Name), html.EscapeString(gameName), team.ParticipantsCount, email_sender.ButtonHTML(link, "Войти в игру"))
markup := email_sender.WrapHTML(content, strings.TrimRight(baseURL, "/"))
@@ -168,7 +168,7 @@ func (s *TeamService) DownloadTeamQR(ctx context.Context, id int) ([]byte, strin
}
// CheckPresence validates team credentials without loading game progress or a scenario.
func (s *TeamService) CheckPresence(ctx context.Context, teamID int, password string) (int, error) {
func (s *TeamService) CheckPresence(ctx context.Context, teamID string, password string) (int, error) {
team, err := s.teamsRepo.GetTeamByID(ctx, teamID)
if errors.Is(err, teams_repo.ErrTeamNotFound) {
return 0, ErrTeamNotFound
+2 -3
View File
@@ -2,7 +2,6 @@ package team_service
import (
"errors"
"fmt"
"net/url"
"strings"
"unicode"
@@ -23,11 +22,11 @@ func teamQRData(baseURL string, game *repos.Game, teams []*repos.Team) ([]team_q
}
cards := make([]team_qr_pdf.Card, 0, len(teams))
for _, team := range teams {
if team.ID <= 0 || team.Password == "" {
if team.ID == "" || team.Password == "" {
return nil, "", errors.New("у команды отсутствуют данные для входа")
}
link := *base
link.Path = strings.TrimRight(base.Path, "/") + fmt.Sprintf("/team-story/%d", team.ID)
link.Path = strings.TrimRight(base.Path, "/") + "/team-story/" + team.ID
link.RawPath = ""
link.RawQuery = url.Values{"password": {team.Password}}.Encode()
cards = append(cards, team_qr_pdf.Card{Name: team.Name, URL: link.String()})
@@ -10,7 +10,7 @@ import (
func TestTeamQRData(t *testing.T) {
game := &repos.Game{Name: "Дело / №1\r\n", StartAt: time.Date(2026, 9, 8, 14, 0, 0, 0, time.UTC)}
teams := []*repos.Team{{ID: 7, Name: "Знатоки", Password: "a+b&c?"}}
teams := []*repos.Team{{ID: "019a1234-5678-7abc-8def-000000000007", Name: "Знатоки", Password: "a+b&c?"}}
cards, filename, err := teamQRData("https://example.org/app/", game, teams)
if err != nil {
t.Fatal(err)
@@ -19,7 +19,7 @@ func TestTeamQRData(t *testing.T) {
t.Fatalf("cards: %+v", cards)
}
u, err := url.Parse(cards[0].URL)
if err != nil || u.Path != "/app/team-story/7" || u.Query().Get("password") != teams[0].Password {
if err != nil || u.Path != "/app/team-story/019a1234-5678-7abc-8def-000000000007" || u.Query().Get("password") != teams[0].Password {
t.Fatalf("wrong team link: %s", cards[0].URL)
}
if filename != "2026-09-08_Дело _ №1__.pdf" {