mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
10 changed files with 289 additions and 5 deletions
@ -0,0 +1,109 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Domain.Apps.Entities.Assets.Commands; |
||||
|
using Squidex.Domain.Apps.Entities.Assets.Repositories; |
||||
|
using Squidex.Domain.Apps.Events.Assets; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Assets |
||||
|
{ |
||||
|
public sealed class RecursiveDeleter : IEventConsumer |
||||
|
{ |
||||
|
private readonly ICommandBus commandBus; |
||||
|
private readonly IAssetRepository assetRepository; |
||||
|
private readonly IAssetFolderRepository assetFolderRepository; |
||||
|
private readonly ISemanticLog log; |
||||
|
private readonly string folderDeletedType; |
||||
|
|
||||
|
public string Name |
||||
|
{ |
||||
|
get { return GetType().Name; } |
||||
|
} |
||||
|
|
||||
|
public string EventsFilter |
||||
|
{ |
||||
|
get { return "^assetFolder\\-"; } |
||||
|
} |
||||
|
|
||||
|
public RecursiveDeleter( |
||||
|
ICommandBus commandBus, |
||||
|
IAssetRepository assetRepository, |
||||
|
IAssetFolderRepository assetFolderRepository, |
||||
|
TypeNameRegistry typeNameRegistry, |
||||
|
ISemanticLog log) |
||||
|
{ |
||||
|
Guard.NotNull(commandBus); |
||||
|
Guard.NotNull(assetRepository); |
||||
|
Guard.NotNull(assetFolderRepository); |
||||
|
Guard.NotNull(typeNameRegistry); |
||||
|
Guard.NotNull(log); |
||||
|
|
||||
|
this.commandBus = commandBus; |
||||
|
this.assetRepository = assetRepository; |
||||
|
this.assetFolderRepository = assetFolderRepository; |
||||
|
this.log = log; |
||||
|
|
||||
|
folderDeletedType = typeNameRegistry.GetName<AssetFolderDeleted>(); |
||||
|
} |
||||
|
|
||||
|
public Task ClearAsync() |
||||
|
{ |
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
|
||||
|
public bool Handles(StoredEvent @event) |
||||
|
{ |
||||
|
return @event.Data.Type == folderDeletedType; |
||||
|
} |
||||
|
|
||||
|
public async Task On(Envelope<IEvent> @event) |
||||
|
{ |
||||
|
if (@event.Payload is AssetFolderDeleted folderDeleted) |
||||
|
{ |
||||
|
async Task PublishAsync(SquidexCommand command) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
command.Actor = folderDeleted.Actor; |
||||
|
|
||||
|
await commandBus.PublishAsync(command); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
log.LogError(ex, w => w |
||||
|
.WriteProperty("action", "DeleteAssetsRecursive") |
||||
|
.WriteProperty("status", "Failed")); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var appId = folderDeleted.AppId; |
||||
|
|
||||
|
var childAssetFolders = await assetFolderRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId); |
||||
|
|
||||
|
foreach (var assetFolderId in childAssetFolders) |
||||
|
{ |
||||
|
await PublishAsync(new DeleteAssetFolder { AssetFolderId = assetFolderId }); |
||||
|
} |
||||
|
|
||||
|
var childAssets = await assetRepository.QueryChildIdsAsync(appId.Id, folderDeleted.AssetFolderId); |
||||
|
|
||||
|
foreach (var assetId in childAssets) |
||||
|
{ |
||||
|
await PublishAsync(new DeleteAsset { AssetId = assetId }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,110 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Entities.Assets.Commands; |
||||
|
using Squidex.Domain.Apps.Entities.Assets.Repositories; |
||||
|
using Squidex.Domain.Apps.Events.Assets; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
using Squidex.Infrastructure.Reflection; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Assets |
||||
|
{ |
||||
|
public class RecursiveDeleterTests |
||||
|
{ |
||||
|
private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry(); |
||||
|
private readonly ISemanticLog log = A.Fake<ISemanticLog>(); |
||||
|
private readonly IAssetRepository assetRepository = A.Fake<IAssetRepository>(); |
||||
|
private readonly IAssetFolderRepository assetFolderRepository = A.Fake<IAssetFolderRepository>(); |
||||
|
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); |
||||
|
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); |
||||
|
private readonly RecursiveDeleter sut; |
||||
|
|
||||
|
public RecursiveDeleterTests() |
||||
|
{ |
||||
|
typeNameRegistry.Map(typeof(AssetFolderDeleted)); |
||||
|
|
||||
|
sut = new RecursiveDeleter(commandBus, assetRepository, assetFolderRepository, typeNameRegistry, log); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_do_nothing_on_clear() |
||||
|
{ |
||||
|
await sut.ClearAsync(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_invoke_delete_commands_for_all_subfolders() |
||||
|
{ |
||||
|
var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; |
||||
|
|
||||
|
var childFolderId1 = Guid.NewGuid(); |
||||
|
var childFolderId2 = Guid.NewGuid(); |
||||
|
|
||||
|
A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) |
||||
|
.Returns(new List<Guid> { childFolderId1, childFolderId2 }); |
||||
|
|
||||
|
await sut.On(Envelope.Create(@event)); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAssetFolder>.That.Matches(x => x.AssetFolderId == childFolderId1))) |
||||
|
.MustHaveHappened(); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAssetFolder>.That.Matches(x => x.AssetFolderId == childFolderId2))) |
||||
|
.MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_invoke_delete_commands_for_all_assets() |
||||
|
{ |
||||
|
var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; |
||||
|
|
||||
|
var childId1 = Guid.NewGuid(); |
||||
|
var childId2 = Guid.NewGuid(); |
||||
|
|
||||
|
A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) |
||||
|
.Returns(new List<Guid> { childId1, childId2 }); |
||||
|
|
||||
|
await sut.On(Envelope.Create(@event)); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId1))) |
||||
|
.MustHaveHappened(); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId2))) |
||||
|
.MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_ignore_exceptions() |
||||
|
{ |
||||
|
var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = Guid.NewGuid() }; |
||||
|
|
||||
|
var childId1 = Guid.NewGuid(); |
||||
|
var childId2 = Guid.NewGuid(); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId1))) |
||||
|
.Throws(new InvalidOperationException()); |
||||
|
|
||||
|
A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId)) |
||||
|
.Returns(new List<Guid> { childId1, childId2 }); |
||||
|
|
||||
|
await sut.On(Envelope.Create(@event)); |
||||
|
|
||||
|
A.CallTo(() => commandBus.PublishAsync(A<DeleteAsset>.That.Matches(x => x.AssetId == childId2))) |
||||
|
.MustHaveHappened(); |
||||
|
|
||||
|
A.CallTo(() => log.Log(SemanticLogLevel.Error, None.Value, A<Action<None, IObjectWriter>>.Ignored)) |
||||
|
.MustHaveHappened(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue