diff --git a/backend/src/TeleWave.Application/Media/ManualInbox/ImportManualInboxCommand.cs b/backend/src/TeleWave.Application/Media/ManualInbox/ImportManualInboxCommand.cs index 308ea3c..a7df188 100644 --- a/backend/src/TeleWave.Application/Media/ManualInbox/ImportManualInboxCommand.cs +++ b/backend/src/TeleWave.Application/Media/ManualInbox/ImportManualInboxCommand.cs @@ -37,11 +37,12 @@ public sealed class ImportManualInboxCommandValidator RuleFor(x => x.Items.Count).LessThanOrEqualTo(500); RuleFor(x => x.ShowId).NotEmpty(); + // Ноль — законный номер: пилот часто идёт как E00, а спецвыпуски живут в нулевом сезоне. RuleForEach(x => x.Items) - .Must(i => i.Season is null or (> 0 and <= 99)) + .Must(i => i.Season is null or (>= 0 and <= 99)) .WithMessage("Сезон вне допустимого диапазона."); RuleForEach(x => x.Items) - .Must(i => i.Episode is null or (> 0 and <= 999)) + .Must(i => i.Episode is null or (>= 0 and <= 999)) .WithMessage("Номер серии вне допустимого диапазона."); } } diff --git a/backend/tests/TeleWave.Application.Tests/Media/ImportManualInboxValidatorTests.cs b/backend/tests/TeleWave.Application.Tests/Media/ImportManualInboxValidatorTests.cs new file mode 100644 index 0000000..7c13b3b --- /dev/null +++ b/backend/tests/TeleWave.Application.Tests/Media/ImportManualInboxValidatorTests.cs @@ -0,0 +1,49 @@ +using TeleWave.Application.Media.ManualInbox; +using Xunit; + +namespace TeleWave.Application.Tests.Media; + +public class ImportManualInboxValidatorTests +{ + private static ImportManualInboxCommand Command(int? season, int? episode) => + new([new ManualImportItem("Шоу/файл.mkv", season, episode)], Guid.NewGuid()); + + [Theory] + [InlineData(1, 0)] // пилот идёт как E00 — это норма, а не ошибка ввода + [InlineData(0, 1)] // спецвыпуски живут в нулевом сезоне + [InlineData(1, 1)] + [InlineData(99, 999)] + [InlineData(null, null)] // номера не заданы — сервер разберёт имя сам + public void AllowsRealWorldNumbers(int? season, int? episode) + { + Assert.True(new ImportManualInboxCommandValidator().Validate(Command(season, episode)).IsValid); + } + + [Theory] + [InlineData(-1, 1)] + [InlineData(100, 1)] + [InlineData(1, -1)] + [InlineData(1, 1000)] + public void RejectsOutOfRange(int? season, int? episode) + { + Assert.False(new ImportManualInboxCommandValidator().Validate(Command(season, episode)).IsValid); + } + + [Fact] + public void RejectsEmptyBatchAndMissingShow() + { + var validator = new ImportManualInboxCommandValidator(); + + Assert.False(validator.Validate(new ImportManualInboxCommand([], Guid.NewGuid())).IsValid); + Assert.False( + validator + .Validate( + new ImportManualInboxCommand( + [new ManualImportItem("файл.mkv", 1, 1)], + Guid.Empty + ) + ) + .IsValid + ); + } +} diff --git a/frontend/src/features/admin/media/ManualInboxDialog.tsx b/frontend/src/features/admin/media/ManualInboxDialog.tsx index fc71e30..4eebf35 100644 --- a/frontend/src/features/admin/media/ManualInboxDialog.tsx +++ b/frontend/src/features/admin/media/ManualInboxDialog.tsx @@ -184,9 +184,10 @@ export function ManualInboxDialog({ onClose }: { onClose: () => void }) {
+ {/* Ноль — законный сезон: в нём живут спецвыпуски и пилоты. */} setSeasonStr(e.target.value)}