1
0
Fork 0
mirror of https://github.com/Sonarr/Sonarr synced 2024-12-30 11:46:09 +00:00

Add 'qualitydefinition/limits' endpoint to get size limitations

This commit is contained in:
Robert Dailey 2024-09-15 12:19:08 -05:00 committed by GitHub
parent 5513d7bc5d
commit 24f03fc1e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 271 additions and 9 deletions

3
.gitignore vendored
View file

@ -162,3 +162,6 @@ src/.idea/
# API doc generation
.config/
# Ignore Jetbrains IntelliJ Workspace Directories
.idea/

View file

@ -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();
}
}

View file

@ -0,0 +1,7 @@
namespace NzbDrone.Core.Qualities;
public static class QualityDefinitionLimits
{
public const int Min = 0;
public const int Max = 1000;
}

View file

@ -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)
{

View file

@ -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

View file

@ -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);
}
}

View file

@ -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)
{