diff --git a/code/backend/Cleanuparr.Api/Features/QueueCleaner/Contracts/Requests/QueueRuleDto.cs b/code/backend/Cleanuparr.Api/Features/QueueCleaner/Contracts/Requests/QueueRuleDto.cs index 15a39ab6..ec432953 100644 --- a/code/backend/Cleanuparr.Api/Features/QueueCleaner/Contracts/Requests/QueueRuleDto.cs +++ b/code/backend/Cleanuparr.Api/Features/QueueCleaner/Contracts/Requests/QueueRuleDto.cs @@ -20,7 +20,7 @@ public abstract record QueueRuleDto [Range(0, 100, ErrorMessage = "Minimum completion percentage must be between 0 and 100")] public ushort MinCompletionPercentage { get; set; } - [Range(0, 100, ErrorMessage = "Maximum completion percentage must be between 0 and 100")] + [Range(1, 100, ErrorMessage = "Maximum completion percentage must be between 1 and 100")] public ushort MaxCompletionPercentage { get; set; } public bool DeletePrivateTorrentsFromClient { get; set; } = false; diff --git a/code/backend/Cleanuparr.Persistence.Tests/Models/Configuration/QueueCleaner/QueueRuleTests.cs b/code/backend/Cleanuparr.Persistence.Tests/Models/Configuration/QueueCleaner/QueueRuleTests.cs index fb521777..bbbe95d6 100644 --- a/code/backend/Cleanuparr.Persistence.Tests/Models/Configuration/QueueCleaner/QueueRuleTests.cs +++ b/code/backend/Cleanuparr.Persistence.Tests/Models/Configuration/QueueCleaner/QueueRuleTests.cs @@ -188,11 +188,26 @@ public sealed class QueueRuleTests }; var exception = Should.Throw(() => rule.Validate()); - exception.Message.ShouldBe("Maximum completion percentage must be between 0 and 100"); + exception.Message.ShouldBe("Maximum completion percentage must be between 1 and 100"); + } + + [Fact] + public void Validate_WithZeroMaxCompletionPercentage_ThrowsValidationException() + { + var rule = new StallRule + { + Name = "test-rule", + MaxStrikes = 3, + MinCompletionPercentage = 0, + MaxCompletionPercentage = 0 + }; + + var exception = Should.Throw(() => rule.Validate()); + exception.Message.ShouldBe("Maximum completion percentage must be greater than 0"); } [Theory] - [InlineData((ushort)0)] + [InlineData((ushort)1)] [InlineData((ushort)50)] [InlineData((ushort)100)] public void Validate_WithValidMaxCompletionPercentage_DoesNotThrow(ushort maxCompletionPercentage) diff --git a/code/backend/Cleanuparr.Persistence/Models/Configuration/QueueCleaner/QueueRule.cs b/code/backend/Cleanuparr.Persistence/Models/Configuration/QueueCleaner/QueueRule.cs index 0b184e9f..3725626c 100644 --- a/code/backend/Cleanuparr.Persistence/Models/Configuration/QueueCleaner/QueueRule.cs +++ b/code/backend/Cleanuparr.Persistence/Models/Configuration/QueueCleaner/QueueRule.cs @@ -24,8 +24,8 @@ public abstract record QueueRule : IConfig, IQueueRule public TorrentPrivacyType PrivacyType { get; init; } = TorrentPrivacyType.Public; public ushort MinCompletionPercentage { get; init; } = 0; - - public ushort MaxCompletionPercentage { get; init; } + + public ushort MaxCompletionPercentage { get; init; } = 100; public bool DeletePrivateTorrentsFromClient { get; init; } = false; @@ -48,9 +48,14 @@ public abstract record QueueRule : IConfig, IQueueRule throw new Cleanuparr.Domain.Exceptions.ValidationException("Minimum completion percentage must be between 0 and 100"); } + if (MaxCompletionPercentage == 0) + { + throw new Cleanuparr.Domain.Exceptions.ValidationException("Maximum completion percentage must be greater than 0"); + } + if (MaxCompletionPercentage > 100) { - throw new Cleanuparr.Domain.Exceptions.ValidationException("Maximum completion percentage must be between 0 and 100"); + throw new Cleanuparr.Domain.Exceptions.ValidationException("Maximum completion percentage must be between 1 and 100"); } if (MaxCompletionPercentage < MinCompletionPercentage) diff --git a/code/frontend/src/app/features/settings/queue-cleaner/queue-cleaner.component.html b/code/frontend/src/app/features/settings/queue-cleaner/queue-cleaner.component.html index 05c58704..a4f22045 100644 --- a/code/frontend/src/app/features/settings/queue-cleaner/queue-cleaner.component.html +++ b/code/frontend/src/app/features/settings/queue-cleaner/queue-cleaner.component.html @@ -261,10 +261,10 @@ helpKey="queue-cleaner:stallRule.privacyType" /> - - { const min = this.stallMinCompletion() ?? 0; const max = this.stallMaxCompletion() ?? 100; + if (max <= 0) return 'Max percentage must be greater than 0'; if (max < min) return 'Max percentage must be greater than or equal to Min percentage'; return undefined; }); @@ -256,6 +257,7 @@ export class QueueCleanerComponent implements OnInit, HasPendingChanges { readonly slowCompletionError = computed(() => { const min = this.slowMinCompletion() ?? 0; const max = this.slowMaxCompletion() ?? 100; + if (max <= 0) return 'Max percentage must be greater than 0'; if (max < min) return 'Max percentage must be greater than or equal to Min percentage'; return undefined; });