Validate before deleting series folders

Closes #264
pull/2342/merge
Mark McDowall 7 years ago
parent 0553a39a02
commit b371296e78

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Validation.Paths;
@ -17,7 +17,9 @@ namespace NzbDrone.Api.RootFolders
DroneFactoryValidator droneFactoryValidator,
MappedNetworkDriveValidator mappedNetworkDriveValidator,
StartupFolderValidator startupFolderValidator,
FolderWritableValidator folderWritableValidator)
SystemFolderValidator systemFolderValidator,
FolderWritableValidator folderWritableValidator
)
: base(signalRBroadcaster)
{
_rootFolderService = rootFolderService;
@ -35,6 +37,7 @@ namespace NzbDrone.Api.RootFolders
.SetValidator(mappedNetworkDriveValidator)
.SetValidator(startupFolderValidator)
.SetValidator(pathExistsValidator)
.SetValidator(systemFolderValidator)
.SetValidator(folderWritableValidator);
}
@ -60,4 +63,4 @@ namespace NzbDrone.Api.RootFolders
_rootFolderService.Remove(id);
}
}
}
}

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using FluentValidation;
@ -45,6 +45,7 @@ namespace NzbDrone.Api.Series
SeriesExistsValidator seriesExistsValidator,
DroneFactoryValidator droneFactoryValidator,
SeriesAncestorValidator seriesAncestorValidator,
SystemFolderValidator systemFolderValidator,
ProfileExistsValidator profileExistsValidator
)
: base(signalRBroadcaster)
@ -71,6 +72,7 @@ namespace NzbDrone.Api.Series
.SetValidator(seriesPathValidator)
.SetValidator(droneFactoryValidator)
.SetValidator(seriesAncestorValidator)
.SetValidator(systemFolderValidator)
.When(s => !s.Path.IsNullOrWhiteSpace());
SharedValidator.RuleFor(s => s.ProfileId).SetValidator(profileExistsValidator);

@ -402,6 +402,7 @@
<Compile Include="TvTests\ShouldRefreshSeriesFixture.cs" />
<Compile Include="UpdateTests\UpdatePackageProviderFixture.cs" />
<Compile Include="UpdateTests\UpdateServiceFixture.cs" />
<Compile Include="ValidationTests\SystemFolderValidatorFixture.cs" />
<Compile Include="XbmcVersionTests.cs" />
</ItemGroup>
<ItemGroup>

@ -0,0 +1,74 @@
using System;
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ValidationTests
{
public class SystemFolderValidatorFixture : CoreTest<SystemFolderValidator>
{
private TestValidator<Series> _validator;
[SetUp]
public void Setup()
{
_validator = new TestValidator<Series>
{
v => v.RuleFor(s => s.Path).SetValidator(Subject)
};
}
[Test]
public void should_not_be_valid_if_set_to_windows_folder()
{
WindowsOnly();
var series = Builder<Series>.CreateNew()
.With(s => s.Path = Environment.GetFolderPath(Environment.SpecialFolder.Windows))
.Build();
_validator.Validate(series).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_child_of_windows_folder()
{
WindowsOnly();
var series = Builder<Series>.CreateNew()
.With(s => s.Path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Test"))
.Build();
_validator.Validate(series).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_set_to_bin_folder()
{
MonoOnly();
var series = Builder<Series>.CreateNew()
.With(s => s.Path = "/bin")
.Build();
_validator.Validate(series).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_child_of_bin_folder()
{
MonoOnly();
var series = Builder<Series>.CreateNew()
.With(s => s.Path = "/bin/test")
.Build();
_validator.Validate(series).IsValid.Should().BeFalse();
}
}
}

@ -21,16 +21,19 @@ namespace NzbDrone.Core.MediaFiles
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IMediaFileService _mediaFileService;
private readonly ISeriesService _seriesService;
private readonly Logger _logger;
public MediaFileDeletionService(IDiskProvider diskProvider,
IRecycleBinProvider recycleBinProvider,
IMediaFileService mediaFileService,
ISeriesService seriesService,
Logger logger)
{
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_mediaFileService = mediaFileService;
_seriesService = seriesService;
_logger = logger;
}
@ -76,6 +79,26 @@ namespace NzbDrone.Core.MediaFiles
{
if (message.DeleteFiles)
{
var series = message.Series;
var allSeries = _seriesService.GetAllSeries();
foreach (var s in allSeries)
{
if (s.Id == series.Id) continue;
if (series.Path.IsParentPath(s.Path))
{
_logger.Error("Series path: '{0}' is a parent of another series, not deleting files.", series.Path);
return;
}
if (series.Path.PathEquals(s.Path))
{
_logger.Error("Series path: '{0}' is the same as another series, not deleting files.", series.Path);
return;
}
}
if (_diskProvider.FolderExists(message.Series.Path))
{
_recycleBinProvider.DeleteFolder(message.Series.Path);

@ -1182,6 +1182,7 @@
<Compile Include="Validation\NzbDroneValidationFailure.cs" />
<Compile Include="Validation\NzbDroneValidationResult.cs" />
<Compile Include="Validation\NzbDroneValidationState.cs" />
<Compile Include="Validation\Paths\SystemFolderValidator.cs" />
<Compile Include="Validation\Paths\MappedNetworkDriveValidator.cs" />
<Compile Include="Validation\Paths\DroneFactoryValidator.cs" />
<Compile Include="Validation\Paths\FolderWritableValidator.cs" />

@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using FluentValidation.Validators;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv;
@ -10,7 +10,7 @@ namespace NzbDrone.Core.Validation.Paths
private readonly ISeriesService _seriesService;
public SeriesAncestorValidator(ISeriesService seriesService)
: base("Path is an ancestor of an existing path")
: base("Path is an ancestor of an existing series")
{
_seriesService = seriesService;
}
@ -22,4 +22,4 @@ namespace NzbDrone.Core.Validation.Paths
return !_seriesService.GetAllSeries().Any(s => context.PropertyValue.ToString().IsParentPath(s.Path));
}
}
}
}

@ -0,0 +1,92 @@
using System;
using FluentValidation.Validators;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Core.Validation.Paths
{
public class SystemFolderValidator : PropertyValidator
{
public SystemFolderValidator()
: base("Is {relationship} system folder {systemFolder}")
{
}
protected override bool IsValid(PropertyValidatorContext context)
{
var folder = context.PropertyValue.ToString();
if (OsInfo.IsWindows)
{
var windowsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
context.MessageFormatter.AppendArgument("systemFolder", windowsFolder);
if (windowsFolder.PathEquals(folder))
{
context.MessageFormatter.AppendArgument("relationship", "set to");
return false;
}
if (windowsFolder.IsParentPath(folder))
{
context.MessageFormatter.AppendArgument("relationship", "child of");
return false;
}
}
else if (OsInfo.IsOsx)
{
var systemFolder = "/System";
context.MessageFormatter.AppendArgument("systemFolder", systemFolder);
if (systemFolder.PathEquals(folder))
{
context.MessageFormatter.AppendArgument("relationship", "child of");
return false;
}
if (systemFolder.IsParentPath(folder))
{
context.MessageFormatter.AppendArgument("relationship", "child of");
return false;
}
}
else
{
var folders = new[]
{
"/bin",
"/boot",
"/lib",
"/sbin",
"/srv",
"/proc"
};
foreach (var f in folders)
{
context.MessageFormatter.AppendArgument("systemFolder", f);
if (f.PathEquals(folder))
{
context.MessageFormatter.AppendArgument("relationship", "child of");
return false;
}
if (f.IsParentPath(folder))
{
context.MessageFormatter.AppendArgument("relationship", "child of");
return false;
}
}
}
return true;
}
}
}
Loading…
Cancel
Save