Your ROOT_URL in app.ini is https://git.cloudchain.link/ but you are visiting https://dash.bss.nz/open-source-mirrors/Radarr/commit/16ed68d5de5add1ee017bc3181f08e7c835d4b9f You should set ROOT_URL correctly, otherwise the web may not work correctly.

New: Custom Format Spec Validation

Fixes 
pull/7411/head
Qstick 3 years ago
parent 098a893083
commit 16ed68d5de

@ -1,4 +1,5 @@
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
@ -18,6 +19,8 @@ namespace NzbDrone.Core.CustomFormats
return (ICustomFormatSpecification)MemberwiseClone();
}
public abstract NzbDroneValidationResult Validate();
public bool IsSatisfiedBy(ParsedMovieInfo movieInfo)
{
var match = IsSatisfiedByWithoutNegate(movieInfo);

@ -1,4 +1,5 @@
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
@ -11,6 +12,8 @@ namespace NzbDrone.Core.CustomFormats
bool Negate { get; set; }
bool Required { get; set; }
NzbDroneValidationResult Validate();
ICustomFormatSpecification Clone();
bool IsSatisfiedBy(ParsedMovieInfo movieInfo);
}

@ -1,11 +1,31 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class IndexerFlagSpecificationValidator : AbstractValidator<IndexerFlagSpecification>
{
public IndexerFlagSpecificationValidator()
{
RuleFor(c => c.Value).NotEmpty();
RuleFor(c => c.Value).Custom((qualityValue, context) =>
{
if (!Enum.IsDefined(typeof(IndexerFlags), qualityValue))
{
context.AddFailure(string.Format("Invalid indexer flag condition value: {0}", qualityValue));
}
});
}
}
public class IndexerFlagSpecification : CustomFormatSpecificationBase
{
private static readonly IndexerFlagSpecificationValidator Validator = new IndexerFlagSpecificationValidator();
public override int Order => 4;
public override string ImplementationName => "Indexer Flag";
@ -17,5 +37,10 @@ namespace NzbDrone.Core.CustomFormats
var flags = movieInfo?.ExtraInfo?.GetValueOrDefault("IndexerFlags") as IndexerFlags?;
return flags?.HasFlag((IndexerFlags)Value) == true;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,11 +1,31 @@
using System.Linq;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class LanguageSpecificationValidator : AbstractValidator<LanguageSpecification>
{
public LanguageSpecificationValidator()
{
RuleFor(c => c.Value).NotEmpty();
RuleFor(c => c.Value).Custom((value, context) =>
{
if (!Language.All.Any(o => o.Id == value))
{
context.AddFailure(string.Format("Invalid Language condition value: {0}", value));
}
});
}
}
public class LanguageSpecification : CustomFormatSpecificationBase
{
private static readonly LanguageSpecificationValidator Validator = new LanguageSpecificationValidator();
public override int Order => 3;
public override string ImplementationName => "Language";
@ -19,5 +39,10 @@ namespace NzbDrone.Core.CustomFormats
: (Language)Value;
return movieInfo?.Languages?.Contains(comparedLanguage) ?? false;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,11 +1,31 @@
using System;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class QualityModifierSpecificationValidator : AbstractValidator<QualityModifierSpecification>
{
public QualityModifierSpecificationValidator()
{
RuleFor(c => c.Value).NotEmpty();
RuleFor(c => c.Value).Custom((qualityValue, context) =>
{
if (!Enum.IsDefined(typeof(Modifier), qualityValue))
{
context.AddFailure(string.Format("Invalid quality modifier condition value: {0}", qualityValue));
}
});
}
}
public class QualityModifierSpecification : CustomFormatSpecificationBase
{
private static readonly QualityModifierSpecificationValidator Validator = new QualityModifierSpecificationValidator();
public override int Order => 7;
public override string ImplementationName => "Quality Modifier";
@ -16,5 +36,10 @@ namespace NzbDrone.Core.CustomFormats
{
return (movieInfo?.Quality?.Quality?.Modifier ?? (int)Modifier.NONE) == (Modifier)Value;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,10 +1,23 @@
using System.Text.RegularExpressions;
using FluentValidation;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class RegexSpecificationBaseValidator : AbstractValidator<RegexSpecificationBase>
{
public RegexSpecificationBaseValidator()
{
RuleFor(c => c.Value).NotEmpty().WithMessage("Regex Pattern must not be empty");
}
}
public abstract class RegexSpecificationBase : CustomFormatSpecificationBase
{
private static readonly RegexSpecificationBaseValidator Validator = new RegexSpecificationBaseValidator();
protected Regex _regex;
protected string _raw;
@ -15,7 +28,11 @@ namespace NzbDrone.Core.CustomFormats
set
{
_raw = value;
_regex = new Regex(value, RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (value.IsNotNullOrWhiteSpace())
{
_regex = new Regex(value, RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
}
}
@ -28,5 +45,10 @@ namespace NzbDrone.Core.CustomFormats
return _regex.IsMatch(compared);
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,11 +1,23 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class ResolutionSpecificationValidator : AbstractValidator<ResolutionSpecification>
{
public ResolutionSpecificationValidator()
{
RuleFor(c => c.Value).NotEmpty();
}
}
public class ResolutionSpecification : CustomFormatSpecificationBase
{
private static readonly ResolutionSpecificationValidator Validator = new ResolutionSpecificationValidator();
public override int Order => 6;
public override string ImplementationName => "Resolution";
@ -16,5 +28,10 @@ namespace NzbDrone.Core.CustomFormats
{
return (movieInfo?.Quality?.Quality?.Resolution ?? (int)Resolution.Unknown) == Value;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,11 +1,24 @@
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class SizeSpecificationValidator : AbstractValidator<SizeSpecification>
{
public SizeSpecificationValidator()
{
RuleFor(c => c.Min).GreaterThan(0);
RuleFor(c => c.Max).GreaterThan(c => c.Min);
}
}
public class SizeSpecification : CustomFormatSpecificationBase
{
private static readonly SizeSpecificationValidator Validator = new SizeSpecificationValidator();
public override int Order => 8;
public override string ImplementationName => "Size";
@ -21,5 +34,10 @@ namespace NzbDrone.Core.CustomFormats
return size > Min.Gigabytes() && size <= Max.Gigabytes();
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -1,11 +1,23 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.CustomFormats
{
public class SourceSpecificationValidator : AbstractValidator<SourceSpecification>
{
public SourceSpecificationValidator()
{
RuleFor(c => c.Value).NotEmpty();
}
}
public class SourceSpecification : CustomFormatSpecificationBase
{
private static readonly SourceSpecificationValidator Validator = new SourceSpecificationValidator();
public override int Order => 5;
public override string ImplementationName => "Source";
@ -16,5 +28,10 @@ namespace NzbDrone.Core.CustomFormats
{
return (movieInfo?.Quality?.Quality?.Source ?? (int)Source.UNKNOWN) == (Source)Value;
}
public override NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -2,10 +2,12 @@ using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Validation;
using Radarr.Http;
using Radarr.Http.REST;
using Radarr.Http.REST.Attributes;
@ -50,6 +52,9 @@ namespace Radarr.Api.V3.CustomFormats
public ActionResult<CustomFormatResource> Create(CustomFormatResource customFormatResource)
{
var model = customFormatResource.ToModel(_specifications);
Validate(model);
return Created(_formatService.Insert(model).Id);
}
@ -57,6 +62,9 @@ namespace Radarr.Api.V3.CustomFormats
public ActionResult<CustomFormatResource> Update(CustomFormatResource resource)
{
var model = resource.ToModel(_specifications);
Validate(model);
_formatService.Update(model);
return Accepted(model.Id);
@ -89,6 +97,25 @@ namespace Radarr.Api.V3.CustomFormats
return schema;
}
private void Validate(CustomFormat definition)
{
foreach (var spec in definition.Specifications)
{
var validationResult = spec.Validate();
VerifyValidationResult(validationResult);
}
}
protected void VerifyValidationResult(ValidationResult validationResult)
{
var result = new NzbDroneValidationResult(validationResult.Errors);
if (!result.IsValid)
{
throw new ValidationException(result.Errors);
}
}
private IEnumerable<ICustomFormatSpecification> GetPresets()
{
yield return new ReleaseTitleSpecification

Loading…
Cancel
Save