New: Validate before deleting artist folders

pull/170/head
Qstick 7 years ago
parent 66d3fd17e9
commit 91afcc36c0

@ -45,6 +45,7 @@ namespace Lidarr.Api.V1.Artist
ArtistPathValidator artistPathValidator,
ArtistExistsValidator artistExistsValidator,
ArtistAncestorValidator artistAncestorValidator,
SystemFolderValidator systemFolderValidator,
ProfileExistsValidator profileExistsValidator,
LanguageProfileExistsValidator languageProfileExistsValidator,
MetadataProfileExistsValidator metadataProfileExistsValidator
@ -71,6 +72,7 @@ namespace Lidarr.Api.V1.Artist
.SetValidator(rootFolderValidator)
.SetValidator(artistPathValidator)
.SetValidator(artistAncestorValidator)
.SetValidator(systemFolderValidator)
.When(s => !s.Path.IsNullOrWhiteSpace());
SharedValidator.RuleFor(s => s.QualityProfileId).SetValidator(profileExistsValidator);

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using FluentValidation;
using NzbDrone.Core.RootFolders;
using NzbDrone.Core.Validation.Paths;
@ -15,7 +15,11 @@ namespace Lidarr.Api.V1.RootFolders
IBroadcastSignalRMessage signalRBroadcaster,
RootFolderValidator rootFolderValidator,
PathExistsValidator pathExistsValidator,
MappedNetworkDriveValidator mappedNetworkDriveValidator)
MappedNetworkDriveValidator mappedNetworkDriveValidator,
StartupFolderValidator startupFolderValidator,
SystemFolderValidator systemFolderValidator,
FolderWritableValidator folderWritableValidator
)
: base(signalRBroadcaster)
{
_rootFolderService = rootFolderService;
@ -30,7 +34,10 @@ namespace Lidarr.Api.V1.RootFolders
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(mappedNetworkDriveValidator)
.SetValidator(pathExistsValidator);
.SetValidator(startupFolderValidator)
.SetValidator(pathExistsValidator)
.SetValidator(systemFolderValidator)
.SetValidator(folderWritableValidator);
}
private RootFolderResource GetRootFolder(int id)
@ -55,4 +62,4 @@ namespace Lidarr.Api.V1.RootFolders
_rootFolderService.Remove(id);
}
}
}
}

@ -347,6 +347,7 @@
<Compile Include="ThingiProviderTests\ProviderStatusServiceFixture.cs" />
<Compile Include="UpdateTests\UpdatePackageProviderFixture.cs" />
<Compile Include="UpdateTests\UpdateServiceFixture.cs" />
<Compile Include="ValidationTests\SystemFolderValidatorFixture.cs" />
<Compile Include="XbmcVersionTests.cs" />
<None Include="Files\Nzbs\NoFiles.nzb">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

@ -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.Music;
using NzbDrone.Core.Validation.Paths;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ValidationTests
{
public class SystemFolderValidatorFixture : CoreTest<SystemFolderValidator>
{
private TestValidator<Artist> _validator;
[SetUp]
public void Setup()
{
_validator = new TestValidator<Artist>
{
v => v.RuleFor(s => s.Path).SetValidator(Subject)
};
}
[Test]
public void should_not_be_valid_if_set_to_windows_folder()
{
WindowsOnly();
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = Environment.GetFolderPath(Environment.SpecialFolder.Windows))
.Build();
_validator.Validate(artist).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_child_of_windows_folder()
{
WindowsOnly();
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "Test"))
.Build();
_validator.Validate(artist).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_set_to_bin_folder()
{
MonoOnly();
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = "/bin")
.Build();
_validator.Validate(artist).IsValid.Should().BeFalse();
}
[Test]
public void should_not_be_valid_if_child_of_bin_folder()
{
MonoOnly();
var artist = Builder<Artist>.CreateNew()
.With(s => s.Path = "/bin/test")
.Build();
_validator.Validate(artist).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 IArtistService _artistService;
private readonly Logger _logger;
public MediaFileDeletionService(IDiskProvider diskProvider,
IRecycleBinProvider recycleBinProvider,
IMediaFileService mediaFileService,
IArtistService artistService,
Logger logger)
{
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_mediaFileService = mediaFileService;
_artistService = artistService;
_logger = logger;
}
@ -76,6 +79,25 @@ namespace NzbDrone.Core.MediaFiles
{
if (message.DeleteFiles)
{
var artist = message.Artist;
var allArtists = _artistService.GetAllArtists();
foreach (var s in allArtists)
{
if (s.Id == artist.Id) continue;
if (artist.Path.IsParentPath(s.Path))
{
_logger.Error("Artist path: '{0}' is a parent of another artist, not deleting files.", artist.Path);
return;
}
if (artist.Path.PathEquals(s.Path))
{
_logger.Error("Artist path: '{0}' is the same as another artist, not deleting files.", artist.Path);
return;
}
}
if (_diskProvider.FolderExists(message.Artist.Path))
{
_recycleBinProvider.DeleteFolder(message.Artist.Path);

@ -1092,6 +1092,7 @@
<Compile Include="Validation\Paths\StartupFolderValidator.cs" />
<Compile Include="Validation\Paths\RootFolderValidator.cs" />
<Compile Include="Validation\Paths\ArtistAncestorValidator.cs" />
<Compile Include="Validation\Paths\SystemFolderValidator.cs" />
<Compile Include="Validation\ProfileExistsValidator.cs" />
<Compile Include="Validation\RuleBuilderExtensions.cs" />
<Compile Include="Validation\UrlValidator.cs" />

@ -10,7 +10,7 @@ namespace NzbDrone.Core.Validation.Paths
private readonly IArtistService _artistService;
public ArtistAncestorValidator(IArtistService artistService)
: base("Path is an ancestor of an existing path")
: base("Path is an ancestor of an existing artist")
{
_artistService = artistService;
}

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