feat(template-engine): TemplateService.MoveTemplateAsync
This commit is contained in:
@@ -155,6 +155,31 @@ public class TemplateService
|
|||||||
return Result<bool>.Success(true);
|
return Result<bool>.Success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Result<Template>> MoveTemplateAsync(
|
||||||
|
int templateId,
|
||||||
|
int? newFolderId,
|
||||||
|
string user,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var template = await _repository.GetTemplateByIdAsync(templateId, cancellationToken);
|
||||||
|
if (template == null)
|
||||||
|
return Result<Template>.Failure($"Template with ID {templateId} not found.");
|
||||||
|
|
||||||
|
if (newFolderId.HasValue)
|
||||||
|
{
|
||||||
|
var folder = await _repository.GetFolderByIdAsync(newFolderId.Value, cancellationToken);
|
||||||
|
if (folder == null)
|
||||||
|
return Result<Template>.Failure($"Target folder with ID {newFolderId.Value} not found.");
|
||||||
|
}
|
||||||
|
|
||||||
|
template.FolderId = newFolderId;
|
||||||
|
await _repository.UpdateTemplateAsync(template, cancellationToken);
|
||||||
|
await _repository.SaveChangesAsync(cancellationToken);
|
||||||
|
await _auditService.LogAsync(user, "Move", "Template", template.Id.ToString(), template.Name, template, cancellationToken);
|
||||||
|
|
||||||
|
return Result<Template>.Success(template);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Template?> GetTemplateByIdAsync(int templateId, CancellationToken cancellationToken = default)
|
public async Task<Template?> GetTemplateByIdAsync(int templateId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await _repository.GetTemplateByIdAsync(templateId, cancellationToken);
|
return await _repository.GetTemplateByIdAsync(templateId, cancellationToken);
|
||||||
|
|||||||
@@ -507,4 +507,47 @@ public class TemplateServiceTests
|
|||||||
Assert.True(result.IsFailure);
|
Assert.True(result.IsFailure);
|
||||||
Assert.Contains("cycle", result.Error, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains("cycle", result.Error, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========================================================================
|
||||||
|
// Move template between folders
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MoveTemplate_ToFolder_ReturnsSuccess()
|
||||||
|
{
|
||||||
|
var t = new Template("X") { Id = 1, FolderId = null };
|
||||||
|
var folder = new TemplateFolder("Dev") { Id = 7 };
|
||||||
|
_repoMock.Setup(r => r.GetTemplateByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(t);
|
||||||
|
_repoMock.Setup(r => r.GetFolderByIdAsync(7, It.IsAny<CancellationToken>())).ReturnsAsync(folder);
|
||||||
|
|
||||||
|
var result = await _service.MoveTemplateAsync(1, 7, "admin");
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.Equal(7, result.Value.FolderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MoveTemplate_ToRoot_ReturnsSuccess()
|
||||||
|
{
|
||||||
|
var t = new Template("X") { Id = 1, FolderId = 7 };
|
||||||
|
_repoMock.Setup(r => r.GetTemplateByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(t);
|
||||||
|
|
||||||
|
var result = await _service.MoveTemplateAsync(1, null, "admin");
|
||||||
|
|
||||||
|
Assert.True(result.IsSuccess);
|
||||||
|
Assert.Null(result.Value.FolderId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MoveTemplate_TargetFolderMissing_ReturnsFailure()
|
||||||
|
{
|
||||||
|
var t = new Template("X") { Id = 1 };
|
||||||
|
_repoMock.Setup(r => r.GetTemplateByIdAsync(1, It.IsAny<CancellationToken>())).ReturnsAsync(t);
|
||||||
|
_repoMock.Setup(r => r.GetFolderByIdAsync(99, It.IsAny<CancellationToken>())).ReturnsAsync((TemplateFolder?)null);
|
||||||
|
|
||||||
|
var result = await _service.MoveTemplateAsync(1, 99, "admin");
|
||||||
|
|
||||||
|
Assert.True(result.IsFailure);
|
||||||
|
Assert.Contains("not found", result.Error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user