This commit is contained in:
2026-10-03 13:22:11 +07:00
parent 05090722a0
commit 2caa2c1a88
74 changed files with 44 additions and 676 deletions
@@ -5,7 +5,6 @@ import (
"time"
)
// Participation — данные участия, доступные транспортному и email-сценариям.
type Participation struct {
TeamID int
TeamName string
@@ -99,7 +99,7 @@ func TestParticipationPostgres(t *testing.T) {
}
}
state(1, "pending")
state(2, "pending") // Существующие команды миграция не изменяет.
state(2, "pending")
// Model registration output explicitly: direct SQL inserts do not auto-confirm teams.
exec(`UPDATE teams SET captain_email='captain@example.org',participants_count=5 WHERE id=1;
INSERT INTO teams(game_id,created_at,captain_email) SELECT 1,start_at-INTERVAL '24 hours','boundary@example.org' FROM games WHERE id=1;
@@ -113,7 +113,6 @@ func TestParticipationPostgres(t *testing.T) {
t.Fatal(err)
}
state(5, "confirmed")
// Независимые рабочие процессы должны захватывать каждую подходящую команду только один раз.
var wg sync.WaitGroup
ids := make(chan int, 8)
errs := make(chan error, 8)
@@ -158,7 +157,6 @@ func TestParticipationPostgres(t *testing.T) {
t.Fatalf("failed send not recorded: %+v %v", team, err)
}
sender.err = nil
// Истёкшая аренда восстанавливается после перезапуска рабочего процесса.
exec(`UPDATE teams SET participation_next_attempt_at=NOW()-INTERVAL '1 minute' WHERE id IN (1,3)`)
if err := service.sendParticipationEmails(ctx, sender, "secret", time.UTC); err != nil {
t.Fatal(err)
@@ -209,7 +207,6 @@ func TestParticipationPostgres(t *testing.T) {
if _, err := service.AnswerParticipation(ctx, token, p.Status); err != nil {
t.Fatalf("same answer not idempotent: %v", err)
}
// Отмена исключает команды из общих активных списков и игры по паролю.
token3 := participationToken("secret", 3)
if _, err := service.AnswerParticipation(ctx, token3, "cancelled"); err != nil {
t.Fatal(err)
@@ -58,10 +58,6 @@ func mapParticipationError(err error) error {
}
}
// Стабильные токены для разных целей сохраняют работоспособность ссылок при
// повторе после неоднозначной ошибки SMTP.
// В базе хранится только хеш; секрет подписи должен быть постоянным между
// рабочими процессами и перезапусками.
func participationToken(secret string, id int) string {
mac := hmac.New(sha256.New, []byte(secret))
_, _ = fmt.Fprintf(mac, "team-participation:v1:%d", id)
@@ -129,7 +125,6 @@ func (s *ParticipationService) sendParticipationEmails(ctx context.Context, send
err = sender.Send(jobCtx, participationEmail(p, s.appBaseURL, token, location))
}
cancel()
// Сохраняем результат даже если отправка исчерпала время задачи.
saveCtx, saveCancel := context.WithTimeout(ctx, 10*time.Second)
saveErr := s.teamsRepo.FinishParticipationEmail(saveCtx, p.TeamID, p.Attempts, err)
saveCancel()