diff --git a/src/NzbDrone.Api/Series/SeriesModule.cs b/src/NzbDrone.Api/Series/SeriesModule.cs index 97255f50c..dc251fae2 100644 --- a/src/NzbDrone.Api/Series/SeriesModule.cs +++ b/src/NzbDrone.Api/Series/SeriesModule.cs @@ -32,7 +32,13 @@ namespace NzbDrone.Api.Series public SeriesModule(ICommandExecutor commandExecutor, ISeriesService seriesService, ISeriesStatisticsService seriesStatisticsService, - IMapCoversToLocal coverMapper) + IMapCoversToLocal coverMapper, + RootFolderValidator rootFolderValidator, + PathExistsValidator pathExistsValidator, + SeriesPathValidator seriesPathValidator, + SeriesExistsValidator seriesExistsValidator, + DroneFactoryValidator droneFactoryValidator + ) : base(commandExecutor) { _commandExecutor = commandExecutor; @@ -48,11 +54,18 @@ namespace NzbDrone.Api.Series SharedValidator.RuleFor(s => s.QualityProfileId).ValidId(); - PutValidator.RuleFor(s => s.Path).IsValidPath(); + PutValidator.RuleFor(s => s.Path) + .Cascade(CascadeMode.StopOnFirstFailure) + .IsValidPath() + .SetValidator(rootFolderValidator) + .SetValidator(pathExistsValidator) + .SetValidator(seriesPathValidator) + .SetValidator(droneFactoryValidator); PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => String.IsNullOrEmpty(s.RootFolderPath)); PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => String.IsNullOrEmpty(s.Path)); PostValidator.RuleFor(s => s.Title).NotEmpty(); + PostValidator.RuleFor(s => s.TvdbId).GreaterThan(0).SetValidator(seriesExistsValidator); } private SeriesResource GetSeries(int id) diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index df565832a..f42a89f96 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -682,9 +682,11 @@ + + - + diff --git a/src/NzbDrone.Core/Validation/Paths/SeriesExistsValidator.cs b/src/NzbDrone.Core/Validation/Paths/SeriesExistsValidator.cs new file mode 100644 index 000000000..21e4ea629 --- /dev/null +++ b/src/NzbDrone.Core/Validation/Paths/SeriesExistsValidator.cs @@ -0,0 +1,26 @@ +using System; +using FluentValidation.Validators; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Validation.Paths +{ + public class SeriesExistsValidator : PropertyValidator + { + private readonly ISeriesService _seriesService; + + public SeriesExistsValidator(ISeriesService seriesService) + : base("This series has already been added") + { + _seriesService = seriesService; + } + + protected override bool IsValid(PropertyValidatorContext context) + { + if (context.PropertyValue == null) return true; + + var tvdbId = Convert.ToInt32(context.PropertyValue.ToString()); + + return (!_seriesService.GetAllSeries().Exists(s => s.TvdbId == tvdbId)); + } + } +} \ No newline at end of file diff --git a/src/NzbDrone.Core/Validation/Paths/SeriesPathValidator.cs b/src/NzbDrone.Core/Validation/Paths/SeriesPathValidator.cs new file mode 100644 index 000000000..fd7c0b5d1 --- /dev/null +++ b/src/NzbDrone.Core/Validation/Paths/SeriesPathValidator.cs @@ -0,0 +1,30 @@ +using FluentValidation.Validators; +using NzbDrone.Common; +using NzbDrone.Core.Tv; +using Omu.ValueInjecter; + +namespace NzbDrone.Core.Validation.Paths +{ + public class SeriesPathValidator : PropertyValidator + { + private readonly ISeriesService _seriesService; + + public SeriesPathValidator(ISeriesService seriesService) + : base("Path is already configured for another series") + { + _seriesService = seriesService; + } + + protected override bool IsValid(PropertyValidatorContext context) + { + if (context.PropertyValue == null) return true; + + var series = new Series(); + series.InjectFrom(context.ParentContext.InstanceToValidate); + + if (series.Id == 0) return true; + + return (!_seriesService.GetAllSeries().Exists(s => s.Path.PathEquals(context.PropertyValue.ToString()) && s.Id != series.Id)); + } + } +} \ No newline at end of file diff --git a/src/UI/AddSeries/SearchResultViewTemplate.html b/src/UI/AddSeries/SearchResultViewTemplate.html index 5a266ecf0..afe628724 100644 --- a/src/UI/AddSeries/SearchResultViewTemplate.html +++ b/src/UI/AddSeries/SearchResultViewTemplate.html @@ -21,6 +21,7 @@ {{overview}} + {{#unless existing}}
{{#unless path}}
Path
@@ -29,6 +30,7 @@
Starting Season
Quality Profile
+ {{/unless}}
{{#if existing}}