You've already forked Sonarr
							
							
				mirror of
				https://github.com/Sonarr/Sonarr.git
				synced 2025-10-31 00:07:55 +02:00 
			
		
		
		
	Add 'qualitydefinition/limits' endpoint to get size limitations
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -162,3 +162,6 @@ src/.idea/ | ||||
|  | ||||
| # API doc generation | ||||
| .config/ | ||||
|  | ||||
| # Ignore Jetbrains IntelliJ Workspace Directories | ||||
| .idea/ | ||||
|   | ||||
| @@ -0,0 +1,198 @@ | ||||
| using FluentValidation.TestHelper; | ||||
| using NUnit.Framework; | ||||
| using NzbDrone.Core.Qualities; | ||||
| using Sonarr.Api.V3.Qualities; | ||||
| 
 | ||||
| namespace NzbDrone.Api.Test.v3.Qualities; | ||||
| 
 | ||||
| [Parallelizable(ParallelScope.All)] | ||||
| public class QualityDefinitionResourceValidatorTests | ||||
| { | ||||
|     private readonly QualityDefinitionResourceValidator _validator = new (); | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_min_size_is_below_min_limit() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = QualityDefinitionLimits.Min - 1, | ||||
|             PreferredSize = null, | ||||
|             MaxSize = null | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MinSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_min_size_is_above_preferred_size_and_below_limit() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 10, | ||||
|             PreferredSize = 5, | ||||
|             MaxSize = null | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MinSize) | ||||
|             .WithErrorCode("LessThanOrEqualTo"); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.PreferredSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_passes_when_min_size_is_within_limits() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = QualityDefinitionLimits.Min, | ||||
|             PreferredSize = null, | ||||
|             MaxSize = null | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldNotHaveAnyValidationErrors(); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_max_size_is_below_preferred_size_and_above_limit() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = null, | ||||
|             PreferredSize = 10, | ||||
|             MaxSize = 5 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MaxSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.PreferredSize) | ||||
|             .WithErrorCode("LessThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_max_size_exceeds_max_limit() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = null, | ||||
|             PreferredSize = null, | ||||
|             MaxSize = QualityDefinitionLimits.Max + 1 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MaxSize) | ||||
|             .WithErrorCode("LessThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_passes_when_max_size_is_within_limits() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = null, | ||||
|             PreferredSize = null, | ||||
|             MaxSize = QualityDefinitionLimits.Max | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldNotHaveAnyValidationErrors(); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_preferred_size_is_below_min_size_and_above_max_size() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 10, | ||||
|             PreferredSize = 7, | ||||
|             MaxSize = 5 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.PreferredSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MaxSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_passes_when_preferred_size_is_null_and_other_sizes_are_valid() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 5, | ||||
|             PreferredSize = null, | ||||
|             MaxSize = 10 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldNotHaveAnyValidationErrors(); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_passes_when_preferred_size_equals_limits() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 5, | ||||
|             PreferredSize = 5, | ||||
|             MaxSize = 10 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldNotHaveAnyValidationErrors(); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_fails_when_all_sizes_are_provided_and_invalid() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 15, | ||||
|             PreferredSize = 10, | ||||
|             MaxSize = 5 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MinSize) | ||||
|             .WithErrorCode("LessThanOrEqualTo"); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.MaxSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
| 
 | ||||
|         result.ShouldHaveValidationErrorFor(r => r.PreferredSize) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo"); | ||||
|     } | ||||
| 
 | ||||
|     [Test] | ||||
|     public void Validate_passes_when_preferred_size_is_valid_within_limits() | ||||
|     { | ||||
|         var resource = new QualityDefinitionResource | ||||
|         { | ||||
|             MinSize = 5, | ||||
|             PreferredSize = 7, | ||||
|             MaxSize = 10 | ||||
|         }; | ||||
| 
 | ||||
|         var result = _validator.TestValidate(resource); | ||||
| 
 | ||||
|         result.ShouldNotHaveAnyValidationErrors(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										7
									
								
								src/NzbDrone.Core/Qualities/QualityDefinitionLimits.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/NzbDrone.Core/Qualities/QualityDefinitionLimits.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| namespace NzbDrone.Core.Qualities; | ||||
| 
 | ||||
| public static class QualityDefinitionLimits | ||||
| { | ||||
|     public const int Min = 0; | ||||
|     public const int Max = 1000; | ||||
| } | ||||
| @@ -12,14 +12,21 @@ using Sonarr.Http.REST.Attributes; | ||||
| namespace Sonarr.Api.V3.Qualities | ||||
| { | ||||
|     [V3ApiController] | ||||
|     public class QualityDefinitionController : RestControllerWithSignalR<QualityDefinitionResource, QualityDefinition>, IHandle<CommandExecutedEvent> | ||||
|     public class QualityDefinitionController : | ||||
|         RestControllerWithSignalR<QualityDefinitionResource, QualityDefinition>, | ||||
|         IHandle<CommandExecutedEvent> | ||||
|     { | ||||
|         private readonly IQualityDefinitionService _qualityDefinitionService; | ||||
| 
 | ||||
|         public QualityDefinitionController(IQualityDefinitionService qualityDefinitionService, IBroadcastSignalRMessage signalRBroadcaster) | ||||
|         public QualityDefinitionController( | ||||
|             IQualityDefinitionService qualityDefinitionService, | ||||
|             IBroadcastSignalRMessage signalRBroadcaster) | ||||
|             : base(signalRBroadcaster) | ||||
|         { | ||||
|             _qualityDefinitionService = qualityDefinitionService; | ||||
| 
 | ||||
|             SharedValidator.RuleFor(c => c) | ||||
|                 .SetValidator(new QualityDefinitionResourceValidator()); | ||||
|         } | ||||
| 
 | ||||
|         [RestPutById] | ||||
| @@ -45,9 +52,7 @@ namespace Sonarr.Api.V3.Qualities | ||||
|         public object UpdateMany([FromBody] List<QualityDefinitionResource> resource) | ||||
|         { | ||||
|             // Read from request | ||||
|             var qualityDefinitions = resource | ||||
|                                                  .ToModel() | ||||
|                                                  .ToList(); | ||||
|             var qualityDefinitions = resource.ToModel().ToList(); | ||||
| 
 | ||||
|             _qualityDefinitionService.UpdateMany(qualityDefinitions); | ||||
| 
 | ||||
| @@ -55,6 +60,14 @@ namespace Sonarr.Api.V3.Qualities | ||||
|                 .ToResource()); | ||||
|         } | ||||
| 
 | ||||
|         [HttpGet("limits")] | ||||
|         public ActionResult<QualityDefinitionLimitsResource> GetLimits() | ||||
|         { | ||||
|             return Ok(new QualityDefinitionLimitsResource( | ||||
|                 QualityDefinitionLimits.Min, | ||||
|                 QualityDefinitionLimits.Max)); | ||||
|         } | ||||
| 
 | ||||
|         [NonAction] | ||||
|         public void Handle(CommandExecutedEvent message) | ||||
|         { | ||||
|   | ||||
| @@ -0,0 +1,6 @@ | ||||
| namespace Sonarr.Api.V3.Qualities; | ||||
| 
 | ||||
| // SA1313 still applies to records until https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3181 is available in a release build. | ||||
| #pragma warning disable SA1313 | ||||
| public record QualityDefinitionLimitsResource(int Min, int Max); | ||||
| #pragma warning restore SA1313 | ||||
| @@ -0,0 +1,31 @@ | ||||
| using FluentValidation; | ||||
| using NzbDrone.Core.Qualities; | ||||
| 
 | ||||
| namespace Sonarr.Api.V3.Qualities; | ||||
| 
 | ||||
| public class QualityDefinitionResourceValidator : AbstractValidator<QualityDefinitionResource> | ||||
| { | ||||
|     public QualityDefinitionResourceValidator() | ||||
|     { | ||||
|         RuleFor(c => c.MinSize) | ||||
|             .GreaterThanOrEqualTo(QualityDefinitionLimits.Min) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo") | ||||
|             .LessThanOrEqualTo(c => c.PreferredSize ?? QualityDefinitionLimits.Max) | ||||
|             .WithErrorCode("LessThanOrEqualTo") | ||||
|             .When(c => c.MinSize is not null); | ||||
| 
 | ||||
|         RuleFor(c => c.PreferredSize) | ||||
|             .GreaterThanOrEqualTo(c => c.MinSize ?? QualityDefinitionLimits.Min) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo") | ||||
|             .LessThanOrEqualTo(c => c.MaxSize ?? QualityDefinitionLimits.Max) | ||||
|             .WithErrorCode("LessThanOrEqualTo") | ||||
|             .When(c => c.PreferredSize is not null); | ||||
| 
 | ||||
|         RuleFor(c => c.MaxSize) | ||||
|             .GreaterThanOrEqualTo(c => c.PreferredSize ?? QualityDefinitionLimits.Min) | ||||
|             .WithErrorCode("GreaterThanOrEqualTo") | ||||
|             .LessThanOrEqualTo(QualityDefinitionLimits.Max) | ||||
|             .WithErrorCode("LessThanOrEqualTo") | ||||
|             .When(c => c.MaxSize is not null); | ||||
|     } | ||||
| } | ||||
| @@ -70,11 +70,15 @@ namespace Sonarr.Http.REST | ||||
|             var skipValidate = skipAttribute?.Skip ?? false; | ||||
|             var skipShared = skipAttribute?.SkipShared ?? false; | ||||
| 
 | ||||
|             if (Request.Method == "POST" || Request.Method == "PUT") | ||||
|             if (Request.Method is "POST" or "PUT") | ||||
|             { | ||||
|                 var resourceArgs = context.ActionArguments.Values.Where(x => x.GetType() == typeof(TResource)) | ||||
|                     .Select(x => x as TResource) | ||||
|                     .ToList(); | ||||
|                 var resourceArgs = context.ActionArguments.Values | ||||
|                     .SelectMany(x => x switch | ||||
|                     { | ||||
|                         TResource single => new[] { single }, | ||||
|                         IEnumerable<TResource> multiple => multiple, | ||||
|                         _ => Enumerable.Empty<TResource>() | ||||
|                     }); | ||||
| 
 | ||||
|                 foreach (var resource in resourceArgs) | ||||
|                 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user