feat(template-folder): delete folder blocked if non-empty
This commit is contained in:
@@ -122,4 +122,37 @@ public class TemplateFolderService
|
||||
|
||||
return Result<TemplateFolder>.Success(folder);
|
||||
}
|
||||
|
||||
public async Task<Result<bool>> DeleteFolderAsync(
|
||||
int folderId, string user,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var folder = await _repository.GetFolderByIdAsync(folderId, cancellationToken);
|
||||
if (folder == null)
|
||||
return Result<bool>.Failure($"Folder with ID {folderId} not found.");
|
||||
|
||||
var allFolders = await _repository.GetAllFoldersAsync(cancellationToken);
|
||||
var allTemplates = await _repository.GetAllTemplatesAsync(cancellationToken);
|
||||
|
||||
var childFolderCount = allFolders.Count(f => f.ParentFolderId == folderId);
|
||||
var childTemplateCount = allTemplates.Count(t => t.FolderId == folderId);
|
||||
|
||||
if (childFolderCount > 0 || childTemplateCount > 0)
|
||||
{
|
||||
var parts = new List<string>();
|
||||
if (childTemplateCount > 0)
|
||||
parts.Add($"{childTemplateCount} template{(childTemplateCount == 1 ? "" : "s")}");
|
||||
if (childFolderCount > 0)
|
||||
parts.Add($"{childFolderCount} subfolder{(childFolderCount == 1 ? "" : "s")}");
|
||||
return Result<bool>.Failure(
|
||||
$"Cannot delete folder '{folder.Name}': it contains {string.Join(" and ", parts)}. " +
|
||||
"Move or delete contents first.");
|
||||
}
|
||||
|
||||
await _repository.DeleteFolderAsync(folderId, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
await _auditService.LogAsync(user, "Delete", "TemplateFolder", folderId.ToString(), folder.Name, null, cancellationToken);
|
||||
|
||||
return Result<bool>.Success(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,4 +186,54 @@ public class TemplateFolderServiceTests
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Contains("cycle", result.Error, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteFolder_Empty_ReturnsSuccess()
|
||||
{
|
||||
var f = new TemplateFolder("Empty") { Id = 1 };
|
||||
_repoMock.Setup(r => r.GetFolderByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(f);
|
||||
_repoMock.Setup(r => r.GetAllFoldersAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateFolder> { f });
|
||||
_repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<Template>());
|
||||
|
||||
var result = await _sut.DeleteFolderAsync(1, "admin");
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
_repoMock.Verify(r => r.DeleteFolderAsync(1, It.IsAny<CancellationToken>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteFolder_HasChildFolders_ReturnsFailure_WithCounts()
|
||||
{
|
||||
var parent = new TemplateFolder("P") { Id = 1 };
|
||||
var child = new TemplateFolder("C") { Id = 2, ParentFolderId = 1 };
|
||||
_repoMock.Setup(r => r.GetFolderByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(parent);
|
||||
_repoMock.Setup(r => r.GetAllFoldersAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateFolder> { parent, child });
|
||||
_repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<Template>());
|
||||
|
||||
var result = await _sut.DeleteFolderAsync(1, "admin");
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Contains("1 subfolder", result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DeleteFolder_HasTemplates_ReturnsFailure_WithCounts()
|
||||
{
|
||||
var f = new TemplateFolder("P") { Id = 1 };
|
||||
var t = new Template("X") { Id = 5, FolderId = 1 };
|
||||
_repoMock.Setup(r => r.GetFolderByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(f);
|
||||
_repoMock.Setup(r => r.GetAllFoldersAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<TemplateFolder> { f });
|
||||
_repoMock.Setup(r => r.GetAllTemplatesAsync(It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(new List<Template> { t });
|
||||
|
||||
var result = await _sut.DeleteFolderAsync(1, "admin");
|
||||
|
||||
Assert.True(result.IsFailure);
|
||||
Assert.Contains("1 template", result.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user