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