diff --git a/NzbDrone.Api/Indexers/IndexerModule.cs b/NzbDrone.Api/Indexers/IndexerModule.cs index fd19ea4a1..3c3601c25 100644 --- a/NzbDrone.Api/Indexers/IndexerModule.cs +++ b/NzbDrone.Api/Indexers/IndexerModule.cs @@ -1,11 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using FluentValidation.Internal; using NzbDrone.Api.ClientSchema; using NzbDrone.Api.Mapping; using NzbDrone.Api.REST; -using NzbDrone.Api.Validation; using NzbDrone.Core.Indexers; using Omu.ValueInjecter; using FluentValidation; @@ -28,8 +26,6 @@ namespace NzbDrone.Api.Indexers SharedValidator.RuleFor(c => c.Name).NotEmpty(); SharedValidator.RuleFor(c => c.Implementation).NotEmpty(); - SharedValidator.RuleForField(c=>c.Fields,"Url").NotEmpty(); - PostValidator.RuleFor(c => c.Fields).NotEmpty(); } @@ -67,6 +63,9 @@ namespace NzbDrone.Api.Indexers var indexer = _indexerService.Get(indexerResource.Id); indexer.InjectFrom(indexerResource); indexer.Settings = SchemaDeserializer.DeserializeSchema(indexer.Settings, indexerResource.Fields); + + ValidateSetting(indexer.Settings); + indexer = _indexerService.Update(indexer); var response = indexer.InjectTo(); @@ -75,6 +74,17 @@ namespace NzbDrone.Api.Indexers return response; } + + private static void ValidateSetting(IIndexerSetting setting) + { + var validationResult = setting.Validate(); + + if (!validationResult.IsValid) + { + throw new ValidationException(validationResult.Errors); + } + } + private Indexer GetIndexer(IndexerResource indexerResource) { var indexer = _indexerService.Schema() @@ -90,6 +100,8 @@ namespace NzbDrone.Api.Indexers indexer.InjectFrom(indexerResource); indexer.Settings = SchemaDeserializer.DeserializeSchema(indexer.Settings, indexerResource.Fields); + ValidateSetting(indexer.Settings); + return indexer; } diff --git a/NzbDrone.Api/Validation/RuleBuilderExtensions.cs b/NzbDrone.Api/Validation/RuleBuilderExtensions.cs index f14c833bd..23dc34c77 100644 --- a/NzbDrone.Api/Validation/RuleBuilderExtensions.cs +++ b/NzbDrone.Api/Validation/RuleBuilderExtensions.cs @@ -1,4 +1,5 @@ -using FluentValidation; +using System.Text.RegularExpressions; +using FluentValidation; using FluentValidation.Validators; namespace NzbDrone.Api.Validation @@ -14,5 +15,10 @@ namespace NzbDrone.Api.Validation { return ruleBuilder.SetValidator(new EqualValidator(0)); } + + public static IRuleBuilderOptions HaveHttpProtocol(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new RegularExpressionValidator("^http(s)?://", RegexOptions.IgnoreCase)).WithMessage("must start with http:// or https://"); + } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index a65e1eb59..963f7702d 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -55,6 +55,9 @@ False ..\packages\FluentMigrator.1.1.1.0\tools\FluentMigrator.Runner.dll + + ..\packages\FluentValidation.4.0.0.1\lib\Net40\FluentValidation.dll + False diff --git a/NzbDrone.Core.Test/packages.config b/NzbDrone.Core.Test/packages.config index d5925e31a..0881c7fe5 100644 --- a/NzbDrone.Core.Test/packages.config +++ b/NzbDrone.Core.Test/packages.config @@ -4,6 +4,7 @@ + diff --git a/NzbDrone.Core/Indexers/IIndexerSetting.cs b/NzbDrone.Core/Indexers/IIndexerSetting.cs index a979b3531..078b18ff5 100644 --- a/NzbDrone.Core/Indexers/IIndexerSetting.cs +++ b/NzbDrone.Core/Indexers/IIndexerSetting.cs @@ -1,26 +1,20 @@ -namespace NzbDrone.Core.Indexers +using FluentValidation.Results; + +namespace NzbDrone.Core.Indexers { public interface IIndexerSetting { - bool IsValid { get; } + ValidationResult Validate(); } public class NullSetting : IIndexerSetting { - public static NullSetting Instance = new NullSetting(); - - private NullSetting() - { - - } + public static readonly NullSetting Instance = new NullSetting(); - public bool IsValid + public ValidationResult Validate() { - get - { - return true; - } + return new ValidationResult(); } } } diff --git a/NzbDrone.Core/Indexers/IndexerService.cs b/NzbDrone.Core/Indexers/IndexerService.cs index 3a4860cbb..168835ffa 100644 --- a/NzbDrone.Core/Indexers/IndexerService.cs +++ b/NzbDrone.Core/Indexers/IndexerService.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Core.Indexers public List GetAvailableIndexers() { - return All().Where(c => c.Enable && c.Settings.IsValid).Select(c => c.Instance).ToList(); + return All().Where(c => c.Enable && c.Settings.Validate().IsValid).Select(c => c.Instance).ToList(); } public Indexer Get(int id) diff --git a/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs b/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs index 30e142e23..7cac534ec 100644 --- a/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs +++ b/NzbDrone.Core/Indexers/Newznab/NewznabSettings.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using FluentValidation; +using FluentValidation.Results; using NzbDrone.Core.Annotations; +using NzbDrone.Core.Validation; namespace NzbDrone.Core.Indexers.Newznab { @@ -8,7 +11,8 @@ namespace NzbDrone.Core.Indexers.Newznab { public NewznabSettings() { - Categories = new [] { 5030, 5040 }; + Categories = new[] { 5030, 5040 }; + //RuleFor(c => c.Url).ValidRootUrl(); } [FieldDefinition(0, Label = "URL")] @@ -26,5 +30,11 @@ namespace NzbDrone.Core.Indexers.Newznab return !string.IsNullOrWhiteSpace(Url); } } + + public ValidationResult Validate() + { + return new ValidationResult(); + //return Validate(this); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsSettings.cs b/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsSettings.cs index a0e8fe815..b8ef34518 100644 --- a/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsSettings.cs +++ b/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsSettings.cs @@ -1,22 +1,28 @@ using System; +using FluentValidation; +using FluentValidation.Results; using NzbDrone.Core.Annotations; namespace NzbDrone.Core.Indexers.Omgwtfnzbs { - public class OmgwtfnzbsSetting : IIndexerSetting + public class OmgwtfnzbsSetting : AbstractValidator, IIndexerSetting { + public OmgwtfnzbsSetting() + { + RuleFor(c => c.Username).NotEmpty(); + RuleFor(c => c.ApiKey).NotEmpty(); + } + [FieldDefinition(0, Label = "Username")] public String Username { get; set; } [FieldDefinition(1, Label = "API Key")] public String ApiKey { get; set; } - public bool IsValid + + public ValidationResult Validate() { - get - { - return !string.IsNullOrWhiteSpace(Username) && !string.IsNullOrWhiteSpace(ApiKey); - } + return Validate(this); } } } diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index bc4e017d5..77753145a 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -67,6 +67,10 @@ False ..\packages\FluentMigrator.1.1.1.0\tools\FluentMigrator.Runner.dll + + False + ..\packages\FluentValidation.4.0.0.1\lib\Net40\FluentValidation.dll + ..\packages\Growl.0.6\lib\Growl.Connector.dll @@ -490,6 +494,7 @@ + diff --git a/NzbDrone.Core/Validation/RuleBuilderExtensions.cs b/NzbDrone.Core/Validation/RuleBuilderExtensions.cs new file mode 100644 index 000000000..6401fb475 --- /dev/null +++ b/NzbDrone.Core/Validation/RuleBuilderExtensions.cs @@ -0,0 +1,29 @@ +using System.Text.RegularExpressions; +using FluentValidation; +using FluentValidation.Validators; + +namespace NzbDrone.Core.Validation +{ + public static class RuleBuilderExtensions + { + public static IRuleBuilderOptions ValidId(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new GreaterThanValidator(0)); + } + + public static IRuleBuilderOptions IsZero(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new EqualValidator(0)); + } + + public static IRuleBuilderOptions HaveHttpProtocol(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new RegularExpressionValidator("^http(s)?://", RegexOptions.IgnoreCase)).WithMessage("must start with http:// or https://"); + } + + public static IRuleBuilderOptions ValidRootUrl(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.SetValidator(new RegularExpressionValidator("^http(?:s)?://[a-z0-9-.]+", RegexOptions.IgnoreCase)).WithMessage("must be valid URL that"); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/packages.config b/NzbDrone.Core/packages.config index 760898188..6674b3182 100644 --- a/NzbDrone.Core/packages.config +++ b/NzbDrone.Core/packages.config @@ -1,6 +1,7 @@  +