From 1676ccdffbea99dee20011f0f6d263cd12225e8a Mon Sep 17 00:00:00 2001 From: Fedorov Vladimir Date: Wed, 28 Oct 2026 23:52:03 +0700 Subject: [PATCH] fix --- .../game_package_service/service_test.go | 46 ++++++++++++++++++- .../game_package_service/validation.go | 5 +- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/internal/services/game_package_service/service_test.go b/internal/services/game_package_service/service_test.go index bdbcc5e..1ee38f4 100644 --- a/internal/services/game_package_service/service_test.go +++ b/internal/services/game_package_service/service_test.go @@ -90,6 +90,12 @@ func TestPackagePreservesPregameData(t *testing.T) { t.Run(tc.name, func(t *testing.T) { snapshot, files := fixture() snapshot.Data.Game.Format = tc.format + snapshot.Data.ScreenPlan.Steps = append(snapshot.Data.ScreenPlan.Steps, + game_screen_plans_repo.Step{Mode: 6}, + game_screen_plans_repo.Step{Mode: 9, QRURL: "https://example.org", Text: "QR"}, + game_screen_plans_repo.Step{Mode: 10}, + game_screen_plans_repo.Step{Mode: 7, TimerType: 1, TimerDurationSeconds: 60, TimerLabel: "До начала игры"}, + ) if tc.format == "offline" { snapshot.Data.Game.WiFiName = "Детектив" snapshot.Data.Game.WiFiPassword = " secret " @@ -194,7 +200,7 @@ func TestPackRejectsInvalidSnapshot(t *testing.T) { {"duplicate map item", func(s *Snapshot) { s.Data.Map = append(s.Data.Map, s.Data.Map[0]) }}, {"invalid organizer desk", func(s *Snapshot) { s.Data.Map[1].ItemID = "" }}, {"invalid plan index", func(s *Snapshot) { s.Data.ScreenPlan.CurrentStep = 10 }}, - {"invalid plan mode", func(s *Snapshot) { s.Data.ScreenPlan.Steps[0].Mode = 9 }}, + {"invalid plan mode", func(s *Snapshot) { s.Data.ScreenPlan.Steps[0].Mode = 11 }}, } { t.Run(tc.name, func(t *testing.T) { snapshot, files := fixture() @@ -838,3 +844,41 @@ func TestRewriteMediaChecksAllNamesBeforeMutation(t *testing.T) { }) } } + +func TestPackageValidatesScreenSteps(t *testing.T) { + for _, tc := range []struct { + name string + step game_screen_plans_repo.Step + valid bool + }{ + {"cover", game_screen_plans_repo.Step{Mode: 1}, true}, + {"intro", game_screen_plans_repo.Step{Mode: 2}, true}, + {"conclusion", game_screen_plans_repo.Step{Mode: 4}, true}, + {"results before game", game_screen_plans_repo.Step{Mode: 6}, true}, + {"timer", game_screen_plans_repo.Step{Mode: 7, TimerDurationSeconds: 60}, true}, + {"text", game_screen_plans_repo.Step{Mode: 8, Text: "Hello"}, true}, + {"QR", game_screen_plans_repo.Step{Mode: 9, QRURL: "https://example.org"}, true}, + {"teams", game_screen_plans_repo.Step{Mode: 10}, true}, + {"unspecified", game_screen_plans_repo.Step{Mode: 0}, false}, + {"removed intro", game_screen_plans_repo.Step{Mode: 3}, false}, + {"removed conclusion", game_screen_plans_repo.Step{Mode: 5}, false}, + {"unknown", game_screen_plans_repo.Step{Mode: 11}, false}, + {"missing QR", game_screen_plans_repo.Step{Mode: 9}, false}, + {"unsafe QR", game_screen_plans_repo.Step{Mode: 9, QRURL: "javascript:alert(1)"}, false}, + {"invalid timer type", game_screen_plans_repo.Step{Mode: 7, TimerDurationSeconds: 60, TimerType: 3}, false}, + {"negative timer type", game_screen_plans_repo.Step{Mode: 1, TimerType: -1}, false}, + } { + t.Run(tc.name, func(t *testing.T) { + snapshot, _ := fixture() + snapshot.Data.ScreenPlan.Steps = []game_screen_plans_repo.Step{tc.step} + snapshot.Data.ScreenPlan.CurrentStep = 0 + err := validateData(&snapshot.Data) + if tc.valid && err != nil { + t.Fatal(err) + } + if !tc.valid && !errors.Is(err, ErrInvalidPackage) { + t.Fatalf("expected invalid package, got %v", err) + } + }) + } +} diff --git a/internal/services/game_package_service/validation.go b/internal/services/game_package_service/validation.go index 13cfac2..b7b73a9 100644 --- a/internal/services/game_package_service/validation.go +++ b/internal/services/game_package_service/validation.go @@ -10,6 +10,7 @@ import ( "unicode" "evening_detective_server/internal/modules/team_qr_pdf" + "evening_detective_server/internal/services/screen_service" "github.com/google/uuid" ) @@ -156,7 +157,9 @@ func validateData(data *Data) error { return invalid("некорректный план экранов") } for _, step := range plan.Steps { - if step.Mode < 1 || step.Mode > 8 || + if !screen_service.ValidMode(step.Mode) || + !screen_service.ValidTimerType(step.TimerType) || + (step.Mode == 9 && !screen_service.ValidQR(step.QRURL, step.Text)) || (step.Mode == 7 && (step.TimerDurationSeconds <= 0 || step.TimerDurationSeconds > 86400 || len(step.TimerLabel) > 200)) || (step.Mode == 8 && (strings.TrimSpace(step.Text) == "" || len(step.Text) > 10000)) { return invalid("некорректный шаг плана экранов")