diff --git a/Backbone.sln b/Backbone.sln index 3805154b47..c3e580c55c 100644 --- a/Backbone.sln +++ b/Backbone.sln @@ -297,6 +297,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EventHandlerService.Tests", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DatabaseMigrator", "DatabaseMigrator\DatabaseMigrator.csproj", "{143EAC38-A2D0-4F74-88F1-3EF27413A8C6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tokens.Domain.Tests", "Modules\Tokens\test\Tokens.Domain.Tests\Tokens.Domain.Tests.csproj", "{EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -715,6 +717,10 @@ Global {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {143EAC38-A2D0-4F74-88F1-3EF27413A8C6}.Release|Any CPU.Build.0 = Release|Any CPU + {EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDCB84BE-54C3-4CAD-977E-45EEBEFA1402}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -849,6 +855,7 @@ Global {2429FCAB-2058-4403-94DA-DA26B1655A7D} = {11FE034C-FA73-4766-99DB-D2C606018934} {B4664E79-77A5-41AE-8480-C449ED5B2576} = {D54A9259-7708-45C1-B8D9-448B97F43B80} {D47E0FE1-23A0-4A96-AF57-E3CE71A132AD} = {2429FCAB-2058-4403-94DA-DA26B1655A7D} + {EDCB84BE-54C3-4CAD-977E-45EEBEFA1402} = {1E437DEA-7657-48AD-ADA0-7B86608E0768} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1F3BD2C6-7CB3-450F-A21A-23EA520D5B7A} diff --git a/BuildingBlocks/src/Tooling/Extensions/DateTimeExtensions.cs b/BuildingBlocks/src/Tooling/Extensions/DateTimeExtensions.cs index 2f89586eba..9cb77373a9 100644 --- a/BuildingBlocks/src/Tooling/Extensions/DateTimeExtensions.cs +++ b/BuildingBlocks/src/Tooling/Extensions/DateTimeExtensions.cs @@ -22,7 +22,9 @@ public static DateTime StartOfDay(this DateTime pivot) public static DateTime StartOfWeek(this DateTime pivot) { var result = new DateTime(pivot.Year, pivot.Month, pivot.Day, 0, 0, 0, 0, DateTimeKind.Utc); - do result = result.AddDays(-1); while (result.DayOfWeek != FIRST_DAY_OF_WEEK); + + while (result.DayOfWeek != FIRST_DAY_OF_WEEK) result = result.AddDays(-1); + return result; } diff --git a/BuildingBlocks/test/Tooling.Tests/Tests/DateTimeExtensionsTests.cs b/BuildingBlocks/test/Tooling.Tests/Tests/DateTimeExtensionsTests.cs index 403ab601d4..8d87594463 100644 --- a/BuildingBlocks/test/Tooling.Tests/Tests/DateTimeExtensionsTests.cs +++ b/BuildingBlocks/test/Tooling.Tests/Tests/DateTimeExtensionsTests.cs @@ -6,6 +6,7 @@ using Xunit; namespace Backbone.Tooling.Tests.Tests; + public class DateTimeExtensionsTests : AbstractTestsBase { [Theory] @@ -69,6 +70,7 @@ public IEnumerator GetEnumerator() yield return ["2023-02-23T23:58:30.000", DateTimeExtensions.StartOfDay, "2023-02-23T00:00:00.000"]; yield return ["2023-06-20T00:00:30.000", DateTimeExtensions.StartOfWeek, "2023-06-19T00:00:00.000"]; yield return ["2023-01-01T23:58:30.000", DateTimeExtensions.StartOfWeek, "2022-12-26T00:00:00.000"]; + yield return ["2024-06-10T23:58:30.000", DateTimeExtensions.StartOfWeek, "2024-06-10T00:00:00.000"]; yield return ["2023-01-01T00:00:30.000", DateTimeExtensions.StartOfMonth, "2023-01-01T00:00:00.000"]; yield return ["2023-02-23T00:00:30.000", DateTimeExtensions.StartOfMonth, "2023-02-01T00:00:00.000"]; yield return ["2023-02-23T00:00:30.000", DateTimeExtensions.StartOfYear, "2023-01-01T00:00:00.000"]; @@ -85,6 +87,4 @@ public IEnumerator GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } #pragma warning restore CS8974 // Converting method group to non-delegate type - - } diff --git a/Modules/Challenges/src/Challenges.Domain/Entities/Challenge.cs b/Modules/Challenges/src/Challenges.Domain/Entities/Challenge.cs index 00605f6589..7072b68c3a 100644 --- a/Modules/Challenges/src/Challenges.Domain/Entities/Challenge.cs +++ b/Modules/Challenges/src/Challenges.Domain/Entities/Challenge.cs @@ -1,15 +1,18 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Challenges.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Challenges.Domain.Entities; -public class Challenge +public class Challenge : Entity { private const int EXPIRY_TIME_IN_MINUTES = 10; - public Challenge() : this(null, null) { } + public Challenge() : this(null, null) + { + } public Challenge(IdentityAddress? createdBy, DeviceId? createdByDevice) { diff --git a/Modules/Challenges/src/Challenges.Infrastructure/Persistence/Database/Configurations/ChallengeEntityTypeConfiguration.cs b/Modules/Challenges/src/Challenges.Infrastructure/Persistence/Database/Configurations/ChallengeEntityTypeConfiguration.cs index 22e10e56e5..1834ea65ae 100644 --- a/Modules/Challenges/src/Challenges.Infrastructure/Persistence/Database/Configurations/ChallengeEntityTypeConfiguration.cs +++ b/Modules/Challenges/src/Challenges.Infrastructure/Persistence/Database/Configurations/ChallengeEntityTypeConfiguration.cs @@ -1,12 +1,8 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Challenges.Domain.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Challenges.Infrastructure.Persistence.Database.Configurations; -public class ChallengeEventEntityTypeConfiguration : IEntityTypeConfiguration +public class ChallengeEventEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) - { - } } diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/ApproveDeletionProcess/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/ApproveDeletionProcess/Handler.cs index 020ac2e484..5caa89c1d4 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/ApproveDeletionProcess/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/ApproveDeletionProcess/Handler.cs @@ -46,7 +46,8 @@ public async Task Handle(ApproveDeletionProcessC _eventBus.Publish(new TierOfIdentityChangedDomainEvent(identity, oldTierId, newTierId)); - var daysUntilDeletion = deletionProcess.GracePeriodEndsAt?.DaysUntilDate() ?? throw new Exception($"Expected '{nameof(deletionProcess.GracePeriodEndsAt)}' to be set but found 'null' instead."); + var daysUntilDeletion = deletionProcess.GracePeriodEndsAt?.DaysUntilDate() ?? + throw new Exception($"Expected '{nameof(deletionProcess.GracePeriodEndsAt)}' to be set but found 'null' instead."); await _notificationSender.SendNotification(identity.Address, new DeletionProcessApprovedNotification(daysUntilDeletion), cancellationToken); return new ApproveDeletionProcessResponse(deletionProcess); diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsOwner/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsOwner/Handler.cs index a967a021bc..ddb3f13748 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsOwner/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsOwner/Handler.cs @@ -15,14 +15,12 @@ public class Handler : IRequestHandler Handle(CancelDeletionPro await _identitiesRepository.Update(identity, cancellationToken); var newTierId = identity.TierId; - _eventBus.Publish(new TierOfIdentityChangedDomainEvent(identity, oldTierId, newTierId)); - _eventBus.Publish(new IdentityDeletionProcessStatusChangedDomainEvent(identity.Address, deletionProcess.Id, _userContext.GetAddress())); - await _notificationSender.SendNotification(identity.Address, new DeletionProcessCancelledByOwnerNotification(), cancellationToken); return new CancelDeletionProcessAsOwnerResponse(deletionProcess); diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsSupport/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsSupport/Handler.cs index e9f995c93a..8d4665b7c5 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsSupport/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelDeletionProcessAsSupport/Handler.cs @@ -1,10 +1,8 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.PushNotifications; using Backbone.BuildingBlocks.Domain; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using MediatR; @@ -13,20 +11,17 @@ namespace Backbone.Modules.Devices.Application.Identities.Commands.CancelDeletio public class Handler : IRequestHandler { private readonly IIdentitiesRepository _identitiesRepository; - private readonly IEventBus _eventBus; private readonly IPushNotificationSender _notificationSender; - public Handler(IIdentitiesRepository identitiesRepository, IEventBus eventBus, IPushNotificationSender notificationSender) + public Handler(IIdentitiesRepository identitiesRepository, IPushNotificationSender notificationSender) { _identitiesRepository = identitiesRepository; - _eventBus = eventBus; _notificationSender = notificationSender; } public async Task Handle(CancelDeletionAsSupportCommand request, CancellationToken cancellationToken) { var identity = await _identitiesRepository.FindByAddress(request.Address, cancellationToken, track: true) ?? throw new NotFoundException(nameof(Identity)); - var oldTierId = identity.TierId; var deletionProcessIdResult = IdentityDeletionProcessId.Create(request.DeletionProcessId); @@ -38,10 +33,6 @@ public async Task Handle(CancelDeletionAsSuppor var deletionProcess = identity.CancelDeletionProcessAsSupport(deletionProcessId); await _identitiesRepository.Update(identity, cancellationToken); - var newTierId = identity.TierId; - - _eventBus.Publish(new TierOfIdentityChangedDomainEvent(identity, oldTierId, newTierId)); - _eventBus.Publish(new IdentityDeletionProcessStatusChangedDomainEvent(identity.Address, deletionProcess.Id, null)); await _notificationSender.SendNotification(identity.Address, new DeletionProcessCancelledBySupportNotification(), cancellationToken); diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelStaleIdentityDeletionProcesses/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelStaleIdentityDeletionProcesses/Handler.cs index 37970841a4..bb7fabba32 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/CancelStaleIdentityDeletionProcesses/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/CancelStaleIdentityDeletionProcesses/Handler.cs @@ -1,6 +1,4 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; +using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Devices.Domain.Entities.Identities; using MediatR; @@ -8,13 +6,11 @@ namespace Backbone.Modules.Devices.Application.Identities.Commands.CancelStaleId public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IIdentitiesRepository _identityRepository; - public Handler(IIdentitiesRepository identityRepository, IEventBus eventBus) + public Handler(IIdentitiesRepository identityRepository) { _identityRepository = identityRepository; - _eventBus = eventBus; } public async Task Handle(CancelStaleIdentityDeletionProcessesCommand request, CancellationToken cancellationToken) @@ -33,8 +29,6 @@ public async Task Handle(CancelSta idsOfCancelledDeletionProcesses.Add(deletionProcess.Value.Id); await _identityRepository.Update(identity, cancellationToken); - - _eventBus.Publish(new IdentityDeletionProcessStatusChangedDomainEvent(identity.Address, deletionProcess.Value.Id, null)); } return new CancelStaleIdentityDeletionProcessesResponse(idsOfCancelledDeletionProcesses); diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/CreateIdentity/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/CreateIdentity/Handler.cs index b0c8692898..42125e5fe8 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/CreateIdentity/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/CreateIdentity/Handler.cs @@ -1,10 +1,8 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Devices.Application.Devices.DTOs; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities; using Backbone.Modules.Devices.Domain.Entities.Identities; using MediatR; @@ -20,14 +18,12 @@ public class Handler : IRequestHandler _logger; - private readonly IEventBus _eventBus; - public Handler(ChallengeValidator challengeValidator, ILogger logger, IEventBus eventBus, IOptions applicationOptions, IIdentitiesRepository identitiesRepository, + public Handler(ChallengeValidator challengeValidator, ILogger logger, IOptions applicationOptions, IIdentitiesRepository identitiesRepository, IOAuthClientsRepository oAuthClientsRepository) { _challengeValidator = challengeValidator; _logger = logger; - _eventBus = eventBus; _applicationOptions = applicationOptions.Value; _identitiesRepository = identitiesRepository; _oAuthClientsRepository = oAuthClientsRepository; @@ -69,8 +65,6 @@ public async Task Handle(CreateIdentityCommand command, _logger.CreatedIdentity(newIdentity.Address, user.DeviceId, user.UserName!); - _eventBus.Publish(new IdentityCreatedDomainEvent(newIdentity)); - return new CreateIdentityResponse { Address = address, diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/StartDeletionProcessAsSupport/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/StartDeletionProcessAsSupport/Handler.cs index 9406345c5d..235834470e 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/StartDeletionProcessAsSupport/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/StartDeletionProcessAsSupport/Handler.cs @@ -1,7 +1,5 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using MediatR; @@ -10,12 +8,10 @@ namespace Backbone.Modules.Devices.Application.Identities.Commands.StartDeletion public class Handler : IRequestHandler { private readonly IIdentitiesRepository _identitiesRepository; - private readonly IEventBus _eventBus; - public Handler(IIdentitiesRepository identitiesRepository, IEventBus eventBus) + public Handler(IIdentitiesRepository identitiesRepository) { _identitiesRepository = identitiesRepository; - _eventBus = eventBus; } public async Task Handle(StartDeletionProcessAsSupportCommand request, CancellationToken cancellationToken) @@ -25,8 +21,6 @@ public async Task Handle(StartDeletionPro await _identitiesRepository.Update(identity, cancellationToken); - _eventBus.Publish(new IdentityDeletionProcessStartedDomainEvent(identity.Address, deletionProcess.Id, null)); - return new StartDeletionProcessAsSupportResponse(deletionProcess); } } diff --git a/Modules/Devices/src/Devices.Application/Identities/Commands/UpdateIdentity/Handler.cs b/Modules/Devices/src/Devices.Application/Identities/Commands/UpdateIdentity/Handler.cs index ba8e2883fe..73a565f0a2 100644 --- a/Modules/Devices/src/Devices.Application/Identities/Commands/UpdateIdentity/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Identities/Commands/UpdateIdentity/Handler.cs @@ -13,13 +13,11 @@ public class Handler : IRequestHandler { private readonly IIdentitiesRepository _identitiesRepository; private readonly ITiersRepository _tiersRepository; - private readonly IEventBus _eventBus; - public Handler(IIdentitiesRepository identitiesRepository, ITiersRepository tiersRepository, IEventBus eventBus) + public Handler(IIdentitiesRepository identitiesRepository, ITiersRepository tiersRepository) { _identitiesRepository = identitiesRepository; _tiersRepository = tiersRepository; - _eventBus = eventBus; } public async Task Handle(UpdateIdentityCommand request, CancellationToken cancellationToken) @@ -39,6 +37,5 @@ public async Task Handle(UpdateIdentityCommand request, CancellationToken cancel identity.ChangeTier(newTier.Id); await _identitiesRepository.Update(identity, cancellationToken); - _eventBus.Publish(new TierOfIdentityChangedDomainEvent(identity, oldTier.Id, newTier.Id)); } } diff --git a/Modules/Devices/src/Devices.Application/Tiers/Commands/CreateTier/Handler.cs b/Modules/Devices/src/Devices.Application/Tiers/Commands/CreateTier/Handler.cs index 4cea3c46f1..b5fac276d9 100644 --- a/Modules/Devices/src/Devices.Application/Tiers/Commands/CreateTier/Handler.cs +++ b/Modules/Devices/src/Devices.Application/Tiers/Commands/CreateTier/Handler.cs @@ -1,7 +1,5 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Devices.Domain.Aggregates.Tier; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using MediatR; using Microsoft.Extensions.Logging; using ApplicationException = Backbone.BuildingBlocks.Application.Abstractions.Exceptions.ApplicationException; @@ -12,13 +10,11 @@ public class Handler : IRequestHandler { private readonly ITiersRepository _tierRepository; private readonly ILogger _logger; - private readonly IEventBus _eventBus; - public Handler(ITiersRepository tierRepository, ILogger logger, IEventBus eventBus) + public Handler(ITiersRepository tierRepository, ILogger logger) { _tierRepository = tierRepository; _logger = logger; - _eventBus = eventBus; } public async Task Handle(CreateTierCommand request, CancellationToken cancellationToken) @@ -35,8 +31,6 @@ public async Task Handle(CreateTierCommand request, Cancella _logger.CreatedTier(tier.Id.Value, tier.Name.Value); - _eventBus.Publish(new TierCreatedDomainEvent(tier)); - return new CreateTierResponse(tier.Id, tier.Name); } } diff --git a/Modules/Devices/src/Devices.Domain/Aggregates/PushNotifications/PnsRegistration.cs b/Modules/Devices/src/Devices.Domain/Aggregates/PushNotifications/PnsRegistration.cs index 7e0c729dbf..53a627d82e 100644 --- a/Modules/Devices/src/Devices.Domain/Aggregates/PushNotifications/PnsRegistration.cs +++ b/Modules/Devices/src/Devices.Domain/Aggregates/PushNotifications/PnsRegistration.cs @@ -1,4 +1,5 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Devices.Domain.Aggregates.PushNotifications.Handles; using Backbone.Tooling; @@ -6,7 +7,7 @@ namespace Backbone.Modules.Devices.Domain.Aggregates.PushNotifications; -public class PnsRegistration +public class PnsRegistration : Entity { // ReSharper disable once UnusedMember.Local private PnsRegistration() diff --git a/Modules/Devices/src/Devices.Domain/Aggregates/Tier/Tier.cs b/Modules/Devices/src/Devices.Domain/Aggregates/Tier/Tier.cs index a27452135e..0c5deca67c 100644 --- a/Modules/Devices/src/Devices.Domain/Aggregates/Tier/Tier.cs +++ b/Modules/Devices/src/Devices.Domain/Aggregates/Tier/Tier.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Domain.Errors; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; namespace Backbone.Modules.Devices.Domain.Aggregates.Tier; -public class Tier +public class Tier : Entity { public static readonly Tier QUEUED_FOR_DELETION = new(TierId.Create("TIR00000000000000001").Value, TierName.Create("Queued for Deletion").Value, false, false); public Tier(TierName name) : this(TierId.Generate(), name, true, true) { + RaiseDomainEvent(new TierCreatedDomainEvent(this)); } private Tier(TierId id, TierName name, bool canBeUsedAsDefaultForClient, bool canBeManuallyAssigned) @@ -26,7 +29,8 @@ private Tier(TierId id, TierName name, bool canBeUsedAsDefaultForClient, bool ca public DomainError? CanBeDeleted(int clientsCount, int identitiesCount) { if (clientsCount > 0) - return DomainErrors.CannotDeleteUsedTier($"The Tier is used as the default Tier by one or more clients. A Tier cannot be deleted if it is the default Tier of a Client ({clientsCount} found)."); + return DomainErrors.CannotDeleteUsedTier( + $"The Tier is used as the default Tier by one or more clients. A Tier cannot be deleted if it is the default Tier of a Client ({clientsCount} found)."); if (identitiesCount > 0) return DomainErrors.CannotDeleteUsedTier($"The Tier is assigned to one or more Identities. A Tier cannot be deleted if it is assigned to an Identity ({identitiesCount} found)."); diff --git a/Modules/Devices/src/Devices.Domain/Entities/Challenge.cs b/Modules/Devices/src/Devices.Domain/Entities/Challenge.cs index 02a7cadb3c..6e2ae2f9db 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Challenge.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Challenge.cs @@ -1,8 +1,9 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.Tooling; namespace Backbone.Modules.Devices.Domain.Entities; -public class Challenge +public class Challenge : Entity { // ReSharper disable once UnusedMember.Local private Challenge() diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/Device.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/Device.cs index ff84329542..c7ba9a39d3 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/Device.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/Device.cs @@ -6,7 +6,7 @@ namespace Backbone.Modules.Devices.Domain.Entities.Identities; -public class Device +public class Device : Entity { // ReSharper disable once UnusedMember.Local private Device() diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs index 9555894770..3e0e5a83a5 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/Identity.cs @@ -3,16 +3,19 @@ using Backbone.BuildingBlocks.Domain.Errors; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Devices.Domain.Aggregates.Tier; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Tooling; using CSharpFunctionalExtensions; +using Entity = Backbone.BuildingBlocks.Domain.Entity; namespace Backbone.Modules.Devices.Domain.Entities.Identities; -public class Identity +public class Identity : Entity { private readonly List _deletionProcesses; + private TierId? _tierId; - public Identity(string? clientId, IdentityAddress address, byte[] publicKey, TierId tierId, byte identityVersion) + public Identity(string clientId, IdentityAddress address, byte[] publicKey, TierId tierId, byte identityVersion) { ClientId = clientId; Address = address; @@ -23,6 +26,8 @@ public Identity(string? clientId, IdentityAddress address, byte[] publicKey, Tie TierId = tierId; Status = IdentityStatus.Active; _deletionProcesses = []; + + RaiseDomainEvent(new IdentityCreatedDomainEvent(this)); } public string? ClientId { get; } @@ -36,7 +41,23 @@ public Identity(string? clientId, IdentityAddress address, byte[] publicKey, Tie public byte IdentityVersion { get; private set; } public TierId? TierIdBeforeDeletion { get; private set; } - public TierId TierId { get; private set; } + + public TierId TierId + { + get => _tierId!; // the only time the backing field is null is within the constructor, so we can suppress the warning + private set + { + if (value == _tierId) return; + + var oldTier = _tierId; + + _tierId = value; + + // if the oldTier was null, we don't consider it a change + if (oldTier != null) + RaiseDomainEvent(new TierOfIdentityChangedDomainEvent(this, oldTier, value)); + } + } public IReadOnlyList DeletionProcesses => _deletionProcesses; @@ -146,7 +167,7 @@ public void DeletionStarted() var deletionProcess = DeletionProcesses.SingleOrDefault(dp => dp.Status == DeletionProcessStatus.Approved) ?? throw new DomainException(DomainErrors.DeletionProcessMustBeInStatus(DeletionProcessStatus.Approved)); - deletionProcess.DeletionStarted(); + deletionProcess.DeletionStarted(Address); Status = IdentityStatus.Deleting; } diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs index c927edeba4..48f8ccfa37 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcess.cs @@ -1,10 +1,11 @@ using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Tooling; namespace Backbone.Modules.Devices.Domain.Entities.Identities; -public class IdentityDeletionProcess +public class IdentityDeletionProcess : Entity { private readonly List _auditLog; @@ -23,6 +24,8 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeletionProcessStatus Status = status; _auditLog = [IdentityDeletionProcessAuditLogEntry.ProcessStartedBySupport(Id, createdBy)]; + + RaiseDomainEvent(new IdentityDeletionProcessStartedDomainEvent(createdBy, Id, null)); } private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDevice) @@ -30,7 +33,7 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev Id = IdentityDeletionProcessId.Generate(); CreatedAt = SystemTime.UtcNow; - Approve(createdByDevice); + ApproveInternally(createdBy, createdByDevice); _auditLog = [IdentityDeletionProcessAuditLogEntry.ProcessStartedByOwner(Id, createdBy, createdByDevice)]; } @@ -65,12 +68,12 @@ private IdentityDeletionProcess(IdentityAddress createdBy, DeviceId createdByDev public bool HasGracePeriodExpired => Status == DeletionProcessStatus.Approved && SystemTime.UtcNow >= GracePeriodEndsAt; - private void Approve(DeviceId createdByDevice) + private void ApproveInternally(IdentityAddress address, DeviceId createdByDevice) { - Status = DeletionProcessStatus.Approved; ApprovedAt = SystemTime.UtcNow; ApprovedByDevice = createdByDevice; GracePeriodEndsAt = SystemTime.UtcNow.AddDays(IdentityDeletionConfiguration.LengthOfGracePeriod); + ChangeStatus(DeletionProcessStatus.Approved, address, address); } public static IdentityDeletionProcess StartAsSupport(IdentityAddress createdBy) @@ -124,12 +127,12 @@ public void GracePeriodReminder3Sent(IdentityAddress address) _auditLog.Add(IdentityDeletionProcessAuditLogEntry.GracePeriodReminder3Sent(Id, address)); } - internal void DeletionStarted() + internal void DeletionStarted(IdentityAddress address) { EnsureStatus(DeletionProcessStatus.Approved); EnsureGracePeriodHasExpired(); - Status = DeletionProcessStatus.Deleting; + ChangeStatus(DeletionProcessStatus.Deleting, address, address); DeletionStartedAt = SystemTime.UtcNow; } @@ -143,7 +146,7 @@ public void Approve(IdentityAddress address, DeviceId approvedByDevice) { EnsureStatus(DeletionProcessStatus.WaitingForApproval); - Approve(approvedByDevice); + ApproveInternally(address, approvedByDevice); _auditLog.Add(IdentityDeletionProcessAuditLogEntry.ProcessApproved(Id, address, approvedByDevice)); } @@ -151,7 +154,10 @@ public void Reject(IdentityAddress address, DeviceId rejectedByDevice) { EnsureStatus(DeletionProcessStatus.WaitingForApproval); - Reject(rejectedByDevice); + ChangeStatus(DeletionProcessStatus.Rejected, address, address); + RejectedAt = SystemTime.UtcNow; + RejectedByDevice = rejectedByDevice; + _auditLog.Add(IdentityDeletionProcessAuditLogEntry.ProcessRejected(Id, address, rejectedByDevice)); } @@ -161,19 +167,12 @@ public void EnsureStatus(DeletionProcessStatus deletionProcessStatus) throw new DomainException(DomainErrors.DeletionProcessMustBeInStatus(deletionProcessStatus)); } - private void Reject(DeviceId rejectedByDevice) - { - Status = DeletionProcessStatus.Rejected; - RejectedAt = SystemTime.UtcNow; - RejectedByDevice = rejectedByDevice; - } - public void CancelAsOwner(IdentityAddress address, DeviceId cancelledByDevice) { if (Status != DeletionProcessStatus.Approved) throw new DomainException(DomainErrors.DeletionProcessMustBeInStatus(DeletionProcessStatus.Approved)); - Status = DeletionProcessStatus.Cancelled; + ChangeStatus(DeletionProcessStatus.Cancelled, address, address); CancelledAt = SystemTime.UtcNow; CancelledByDevice = cancelledByDevice; @@ -185,7 +184,7 @@ public void CancelAsSupport(IdentityAddress address) if (Status != DeletionProcessStatus.Approved) throw new DomainException(DomainErrors.DeletionProcessMustBeInStatus(DeletionProcessStatus.Approved)); - Status = DeletionProcessStatus.Cancelled; + ChangeStatus(DeletionProcessStatus.Cancelled, address, null); CancelledAt = SystemTime.UtcNow; _auditLog.Add(IdentityDeletionProcessAuditLogEntry.ProcessCancelledBySupport(Id, address)); @@ -195,9 +194,15 @@ public void Cancel(IdentityAddress address) { EnsureStatus(DeletionProcessStatus.WaitingForApproval); - Status = DeletionProcessStatus.Cancelled; + ChangeStatus(DeletionProcessStatus.Cancelled, address, null); CancelledAt = SystemTime.UtcNow; _auditLog.Add(IdentityDeletionProcessAuditLogEntry.ProcessCancelledAutomatically(Id, address)); } + + private void ChangeStatus(DeletionProcessStatus newStatus, IdentityAddress address, string? initiator) + { + Status = newStatus; + RaiseDomainEvent(new IdentityDeletionProcessStatusChangedDomainEvent(address, Id, initiator)); + } } diff --git a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcessAuditLogEntry.cs b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcessAuditLogEntry.cs index ce162892dc..e83a872eb0 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcessAuditLogEntry.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/Identities/IdentityDeletionProcessAuditLogEntry.cs @@ -1,9 +1,10 @@ -using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.BuildingBlocks.Domain; +using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Tooling; namespace Backbone.Modules.Devices.Domain.Entities.Identities; -public class IdentityDeletionProcessAuditLogEntry +public class IdentityDeletionProcessAuditLogEntry : Entity { // ReSharper disable once UnusedMember.Local private IdentityDeletionProcessAuditLogEntry() diff --git a/Modules/Devices/src/Devices.Domain/Entities/OAuthClient.cs b/Modules/Devices/src/Devices.Domain/Entities/OAuthClient.cs index 582dbe6020..02c1cb6a63 100644 --- a/Modules/Devices/src/Devices.Domain/Entities/OAuthClient.cs +++ b/Modules/Devices/src/Devices.Domain/Entities/OAuthClient.cs @@ -1,7 +1,9 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.Modules.Devices.Domain.Aggregates.Tier; namespace Backbone.Modules.Devices.Domain.Entities; -public class OAuthClient + +public class OAuthClient : Entity { public OAuthClient(string clientId, string displayName, TierId defaultTier, DateTime createdAt, int? maxIdentities) { diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/DevicesDbContext.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/DevicesDbContext.cs index 7bec649be0..6c2df1ade0 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/DevicesDbContext.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/DevicesDbContext.cs @@ -1,5 +1,6 @@ using System.Data; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Infrastructure.Persistence.Database; using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.ValueConverters; using Backbone.DevelopmentKit.Identity.ValueObjects; @@ -128,6 +129,42 @@ public List GetApnsBundleIdsForWhichNoConfigurationExists(ICollection SaveChangesAsync(CancellationToken cancellationToken = new()) + { + var entities = GetChangedEntities(); + var result = base.SaveChangesAsync(cancellationToken); + PublishDomainEvents(entities); + + return result; + } + + public override Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new()) + { + var entities = GetChangedEntities(); + var result = base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken); + PublishDomainEvents(entities); + + return result; + } + private List GetAppIdsForWhichNoConfigurationExists(string platform, ICollection supportedAppIds) { var query = PnsRegistrations.FromSqlRaw( @@ -187,4 +224,19 @@ protected override void OnModelCreating(ModelBuilder builder) builder.ApplyConfigurationsFromAssembly(typeof(DeviceEntityTypeConfiguration).Assembly); } + + private List GetChangedEntities() => ChangeTracker + .Entries() + .Where(x => x.Entity is Entity) + .Select(x => (Entity)x.Entity) + .ToList(); + + private void PublishDomainEvents(List entities) + { + foreach (var e in entities) + { + _eventBus.Publish(e.DomainEvents); + e.ClearDomainEvents(); + } + } } diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/ChallengesEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/ChallengesEntityTypeConfiguration.cs index 0438dbeffd..2c8ac034ee 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/ChallengesEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/ChallengesEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Devices.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class ChallengesEntityTypeConfiguration : IEntityTypeConfiguration +public class ChallengesEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.ToTable(nameof(Challenge) + "s", "Challenges", x => x.ExcludeFromMigrations()); builder.Property(x => x.Id).IsUnicode(false).IsFixedLength().HasMaxLength(20); diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/DeviceEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/DeviceEntityTypeConfiguration.cs index f89a73308f..7139ffa377 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/DeviceEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/DeviceEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Devices.Domain.Entities.Identities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class DeviceEntityTypeConfiguration : IEntityTypeConfiguration +public class DeviceEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.Ignore(x => x.IsOnboarded); builder.Property(x => x.CommunicationLanguage).HasDefaultValue(CommunicationLanguage.DEFAULT_LANGUAGE); } diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityDeletionProcessEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityDeletionProcessEntityTypeConfiguration.cs index cdbefc02fd..796bb3c047 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityDeletionProcessEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityDeletionProcessEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ -using Backbone.Modules.Devices.Domain.Entities.Identities; +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; +using Backbone.Modules.Devices.Domain.Entities.Identities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class IdentityDeletionProcessEntityTypeConfiguration : IEntityTypeConfiguration +public class IdentityDeletionProcessEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.ToTable("IdentityDeletionProcesses"); builder.HasKey(x => x.Id); builder.Property(x => x.Status); @@ -22,10 +24,11 @@ public void Configure(EntityTypeBuilder builder) } } -public class IdentityDeletionProcessAuditLogEntryEntityTypeConfiguration : IEntityTypeConfiguration +public class IdentityDeletionProcessAuditLogEntryEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.ToTable("IdentityDeletionProcessAuditLog"); builder.HasKey(x => x.Id); builder.Property(x => x.DeviceIdHash); diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityEntityTypeConfiguration.cs index 0246e7ce09..4cd3545887 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/IdentityEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Devices.Domain.Entities.Identities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class IdentityEntityTypeConfiguration : IEntityTypeConfiguration +public class IdentityEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.HasKey(x => x.Address); builder.Property(x => x.ClientId).HasMaxLength(200); diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/PnsRegistrationEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/PnsRegistrationEntityTypeConfiguration.cs index 5054698618..2ed86a94da 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/PnsRegistrationEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/PnsRegistrationEntityTypeConfiguration.cs @@ -1,12 +1,14 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Devices.Domain.Aggregates.PushNotifications; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class PnsRegistrationEntityTypeConfiguration : IEntityTypeConfiguration + +public class PnsRegistrationEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.HasKey(x => x.DeviceId); builder.Property(x => x.IdentityAddress).IsRequired(); builder.Property(x => x.DevicePushIdentifier); diff --git a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/TierEntityTypeConfiguration.cs b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/TierEntityTypeConfiguration.cs index c8795a196e..43c084962f 100644 --- a/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/TierEntityTypeConfiguration.cs +++ b/Modules/Devices/src/Devices.Infrastructure/Persistence/Database/EntityConfigurations/TierEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Devices.Domain.Aggregates.Tier; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Devices.Infrastructure.Persistence.Database.EntityConfigurations; -public class TierEntityTypeConfiguration : IEntityTypeConfiguration +public class TierEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); builder.HasKey(x => x.Id); builder.HasIndex(x => x.Name).IsUnique(); builder.Property(x => x.CanBeManuallyAssigned).HasDefaultValue(true); diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsOwner/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsOwner/HandlerTests.cs index 9324aff921..0438c328a9 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsOwner/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsOwner/HandlerTests.cs @@ -67,55 +67,12 @@ public void Cannot_start_when_given_identity_does_not_exist() acting.Should().ThrowAsync(); } - [Fact] - public async Task Publishes_domain_events() - { - // Arrange - var activeIdentity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(); - var activeDevice = activeIdentity.Devices[0]; - var deletionProcess = activeIdentity.GetDeletionProcessInStatus(DeletionProcessStatus.Approved)!; - - var fakeIdentitiesRepository = A.Fake(); - var fakeUserContext = A.Fake(); - var mockEventBus = A.Fake(); - - A.CallTo(() => fakeIdentitiesRepository.FindByAddress(activeIdentity.Address, CancellationToken.None, A._)) - .Returns(activeIdentity); - A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity.Address); - A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice.Id); - - var handler = CreateHandler(fakeIdentitiesRepository, fakeUserContext, mockEventBus); - var command = new CancelDeletionProcessAsOwnerCommand(deletionProcess.Id); - - // Act - var response = await handler.Handle(command, CancellationToken.None); - - // Assert - A.CallTo(() => mockEventBus.Publish( - A.That.Matches(e => - e.IdentityAddress == activeIdentity.Address && - e.OldTierId == "TIR00000000000000001")) - ).MustHaveHappenedOnceExactly(); - - A.CallTo(() => mockEventBus.Publish( - A.That.Matches(e => - e.Address == activeIdentity.Address && - e.DeletionProcessId == response.Id)) - ).MustHaveHappenedOnceExactly(); - } - - private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, IUserContext userContext, IPushNotificationSender pushNotificationSender) - { - return CreateHandler(identitiesRepository, userContext, null, pushNotificationSender); - } - - private static Handler CreateHandler(IIdentitiesRepository? identitiesRepository = null, IUserContext? userContext = null, IEventBus? eventBus = null, IPushNotificationSender? pushNotificationSender = null) + private static Handler CreateHandler(IIdentitiesRepository? identitiesRepository = null, IUserContext? userContext = null, IPushNotificationSender? pushNotificationSender = null) { userContext ??= A.Dummy(); identitiesRepository ??= A.Dummy(); - eventBus ??= A.Dummy(); pushNotificationSender ??= A.Dummy(); - return new Handler(identitiesRepository, userContext, eventBus, pushNotificationSender); + return new Handler(identitiesRepository, userContext, pushNotificationSender); } } diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsSupport/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsSupport/HandlerTests.cs index d94198e72f..e7fa9e1599 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsSupport/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelDeletionProcessAsSupport/HandlerTests.cs @@ -1,10 +1,8 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.PushNotifications; using Backbone.Modules.Devices.Application.Identities.Commands.CancelDeletionProcessAsSupport; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Devices.Application.Infrastructure.PushNotifications.DeletionProcess; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; @@ -48,39 +46,6 @@ public async Task Happy_path() A.CallTo(() => mockPushNotificationSender.SendNotification(identity.Address, A._, A._)).MustHaveHappenedOnceExactly(); } - [Fact] - public async Task Publishes_domain_events() - { - // Arrange - var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(DateTime.Parse("2000-01-01")); - var deletionProcess = identity.GetDeletionProcessInStatus(DeletionProcessStatus.Approved)!; - - var fakeIdentitiesRepository = A.Fake(); - A.CallTo(() => fakeIdentitiesRepository - .FindByAddress(identity.Address, A._, true)) - .Returns(identity); - - var mockEventBus = A.Fake(); - - var handler = CreateHandler(fakeIdentitiesRepository, mockEventBus); - - // Act - var response = await handler.Handle(new CancelDeletionAsSupportCommand(identity.Address, deletionProcess.Id), CancellationToken.None); - - // Assert - A.CallTo(() => mockEventBus.Publish( - A.That.Matches(e => - e.IdentityAddress == identity.Address && - e.OldTierId == "TIR00000000000000001")) - ).MustHaveHappenedOnceExactly(); - - A.CallTo(() => mockEventBus.Publish( - A.That.Matches(e => - e.Address == identity.Address && - e.DeletionProcessId == response.Id)) - ).MustHaveHappenedOnceExactly(); - } - [Fact] public void Cannot_start_when_given_identity_does_not_exist() { @@ -96,17 +61,11 @@ public void Cannot_start_when_given_identity_does_not_exist() acting.Should().AwaitThrowAsync().Which.Message.Should().Contain("Identity"); } - private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, IPushNotificationSender pushNotificationSender) - { - return CreateHandler(identitiesRepository, null, pushNotificationSender); - } - - private static Handler CreateHandler(IIdentitiesRepository? identitiesRepository = null, IEventBus? eventBus = null, IPushNotificationSender? pushNotificationSender = null) + private static Handler CreateHandler(IIdentitiesRepository? identitiesRepository = null, IPushNotificationSender? pushNotificationSender = null) { identitiesRepository ??= A.Dummy(); - eventBus ??= A.Dummy(); pushNotificationSender ??= A.Dummy(); - return new Handler(identitiesRepository, eventBus, pushNotificationSender); + return new Handler(identitiesRepository, pushNotificationSender); } } diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelStaleIdentityDeletionProcesses/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelStaleIdentityDeletionProcesses/HandlerTests.cs index 89baaeed77..617d9ed3c5 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelStaleIdentityDeletionProcesses/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/CancelStaleIdentityDeletionProcesses/HandlerTests.cs @@ -1,7 +1,5 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.Modules.Devices.Application.Identities.Commands.CancelStaleIdentityDeletionProcesses; +using Backbone.Modules.Devices.Application.Identities.Commands.CancelStaleIdentityDeletionProcesses; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; @@ -17,7 +15,7 @@ public class HandlerTests : AbstractTestsBase public async Task Empty_list_is_returned_if_no_deletion_process_approvals_are_past_due() { // Arrange - var handler = new Handler(A.Fake(), A.Fake()); + var handler = CreateHandler(); // Act var response = await handler.Handle(new CancelStaleIdentityDeletionProcessesCommand(), CancellationToken.None); @@ -43,7 +41,7 @@ public async Task Only_stale_deletion_processes_are_cancelled() A.CallTo(() => fakeIdentitiesRepository.FindAllWithDeletionProcessInStatus(A._, A._, A._)) .Returns([identityWithStaleDeletionProcess, identityWithDeletionProcess]); - var handler = new Handler(fakeIdentitiesRepository, A.Fake()); + var handler = CreateHandler(fakeIdentitiesRepository); // Act var response = await handler.Handle(new CancelStaleIdentityDeletionProcessesCommand(), CancellationToken.None); @@ -53,36 +51,9 @@ public async Task Only_stale_deletion_processes_are_cancelled() response.First().Should().Be(identityWithStaleDeletionProcess.DeletionProcesses[0].Id); } - [Fact] - public async Task Publishes_DomainEvent_for_cancelled_deletion_process() + private static Handler CreateHandler(IIdentitiesRepository? identitiesRepository = null) { - // Arrange - SystemTime.Set(DateTime.Parse("2020-01-31")); - var elevenDaysAgo = DateTime.Parse("2020-01-20"); - - var identity1 = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(elevenDaysAgo); - var identity2 = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(elevenDaysAgo); - - var fakeIdentitiesRepository = A.Fake(); - var mockEventBus = A.Fake(); - - A.CallTo(() => fakeIdentitiesRepository.FindAllWithDeletionProcessInStatus(A._, A._, A._)) - .Returns([identity1, identity2]); - - var handler = new Handler(fakeIdentitiesRepository, mockEventBus); - - // Act - await handler.Handle(new CancelStaleIdentityDeletionProcessesCommand(), CancellationToken.None); - - // Assert - A.CallTo(() => mockEventBus.Publish(A.That.Matches(i => - i.Address == identity1.Address && - i.DeletionProcessId == identity1.DeletionProcesses[0].Id))) - .MustHaveHappenedOnceExactly(); - - A.CallTo(() => mockEventBus.Publish(A.That.Matches(i => - i.Address == identity2.Address && - i.DeletionProcessId == identity2.DeletionProcesses[0].Id))) - .MustHaveHappenedOnceExactly(); + identitiesRepository ??= A.Fake(); + return new Handler(identitiesRepository); } } diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/StartDeletionProcessAsSupport/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/StartDeletionProcessAsSupport/HandlerTests.cs index c8fb826728..1ffca98bfa 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/StartDeletionProcessAsSupport/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/StartDeletionProcessAsSupport/HandlerTests.cs @@ -1,8 +1,6 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Devices.Application.Identities.Commands.StartDeletionProcessAsSupport; using Backbone.Modules.Devices.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.UnitTestTools.BaseClasses; using Backbone.UnitTestTools.Extensions; @@ -45,31 +43,6 @@ public async Task Happy_path() .MustHaveHappenedOnceExactly(); } - [Fact] - public async Task Publishes_IdentityDeletionProcessStartedEvent() - { - // Arrange - var activeIdentity = TestDataGenerator.CreateIdentityWithOneDevice(); - - var fakeIdentitiesRepository = A.Fake(); - var mockEventBus = A.Fake(); - - A.CallTo(() => fakeIdentitiesRepository.FindByAddress(activeIdentity.Address, A._, A._)) - .Returns(activeIdentity); - - var handler = CreateHandler(fakeIdentitiesRepository, mockEventBus); - - // Act - var response = await handler.Handle(new StartDeletionProcessAsSupportCommand(activeIdentity.Address), CancellationToken.None); - - // Assert - A.CallTo(() => mockEventBus.Publish( - A.That.Matches( - e => e.Address == activeIdentity.Address && - e.DeletionProcessId == response.Id)) - ).MustHaveHappenedOnceExactly(); - } - [Fact] public void Cannot_start_when_given_identity_does_not_exist() { @@ -93,9 +66,8 @@ public void Cannot_start_when_given_identity_does_not_exist() acting.Should().AwaitThrowAsync().Which.Message.Should().Contain("Identity"); } - private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, IEventBus? eventBus = null) + private static Handler CreateHandler(IIdentitiesRepository identitiesRepository) { - eventBus ??= A.Fake(); - return new Handler(identitiesRepository, eventBus); + return new Handler(identitiesRepository); } } diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/UpdateIdentity/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/UpdateIdentity/HandlerTests.cs index 3df2abc398..99743a71e0 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/UpdateIdentity/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Identities/Commands/UpdateIdentity/HandlerTests.cs @@ -46,32 +46,6 @@ public async Task Updates_the_identity_in_the_database() )).MustHaveHappenedOnceExactly(); } - [Fact] - public async Task Publishes_TierOfIdentityChangedDomainEvent() - { - // Arrange - var identitiesRepository = A.Fake(); - var tiersRepository = A.Fake(); - var eventBus = A.Fake(); - - var oldTier = new Tier(TierName.Create("Old tier").Value); - var newTier = new Tier(TierName.Create("New Tier").Value); - - var identity = new Identity(CreateRandomDeviceId(), CreateRandomIdentityAddress(), [1, 1, 1, 1, 1], oldTier.Id, 1); - - A.CallTo(() => identitiesRepository.FindByAddress(identity.Address, A._, A._)).Returns(identity); - A.CallTo(() => tiersRepository.FindByIds(A>._, A._)).Returns(new List() { oldTier, newTier }); - - var handler = CreateHandler(identitiesRepository, tiersRepository, eventBus); - var request = BuildRequest(newTier, identity); - - // Act - await handler.Handle(request, CancellationToken.None); - - // Assert - A.CallTo(() => eventBus.Publish(A._)).MustHaveHappened(); - } - [Fact] public void Fails_when_identity_does_not_exist() { @@ -132,7 +106,6 @@ public void Does_nothing_when_tiers_are_the_same() // Arrange var identitiesRepository = A.Fake(); var tiersRepository = A.Fake(); - var eventBus = A.Fake(); var oldAndNewTier = new Tier(TierName.Create("Tier name").Value); @@ -141,7 +114,7 @@ public void Does_nothing_when_tiers_are_the_same() A.CallTo(() => identitiesRepository.FindByAddress(identity.Address, A._, A._)).Returns(identity); A.CallTo(() => tiersRepository.FindByIds(A>._, A._)).Returns(new List { oldAndNewTier }); - var handler = CreateHandler(identitiesRepository, tiersRepository, eventBus); + var handler = CreateHandler(identitiesRepository, tiersRepository); var request = BuildRequest(oldAndNewTier, identity); // Act @@ -150,7 +123,6 @@ public void Does_nothing_when_tiers_are_the_same() // Assert acting.Should().AwaitThrowAsync(); A.CallTo(() => identitiesRepository.Update(A._, A._)).MustNotHaveHappened(); - A.CallTo(() => eventBus.Publish(A._)).MustNotHaveHappened(); } private static UpdateIdentityCommand BuildRequest(Tier newTier, Identity identity) @@ -164,11 +136,6 @@ private static UpdateIdentityCommand BuildRequest(Tier newTier, Identity identit private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, ITiersRepository tiersRepository) { - return CreateHandler(identitiesRepository, tiersRepository, A.Fake()); - } - - private static Handler CreateHandler(IIdentitiesRepository identitiesRepository, ITiersRepository tiersRepository, IEventBus eventBus) - { - return new Handler(identitiesRepository, tiersRepository, eventBus); + return new Handler(identitiesRepository, tiersRepository); } } diff --git a/Modules/Devices/test/Devices.Application.Tests/Tests/Tiers/Commands/CreateTier/HandlerTests.cs b/Modules/Devices/test/Devices.Application.Tests/Tests/Tiers/Commands/CreateTier/HandlerTests.cs index c70dc23779..fb919624dd 100644 --- a/Modules/Devices/test/Devices.Application.Tests/Tests/Tiers/Commands/CreateTier/HandlerTests.cs +++ b/Modules/Devices/test/Devices.Application.Tests/Tests/Tiers/Commands/CreateTier/HandlerTests.cs @@ -25,9 +25,8 @@ public HandlerTests() private Handler CreateHandler() { - var eventBus = A.Fake(); var logger = A.Fake>(); - return new Handler(_tierRepository, logger, eventBus); + return new Handler(_tierRepository, logger); } [Fact] diff --git a/Modules/Devices/test/Devices.Domain.Tests/Domain/DeviceTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Domain/DeviceTests.cs index da1919208d..47e6604807 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Domain/DeviceTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Domain/DeviceTests.cs @@ -88,7 +88,7 @@ public void IsOnboarded_returns_true_if_user_has_been_used_to_login() public void An_unOnboarded_device_can_be_deleted() { // Arrange - var identity = TestDataGenerator.CreateIdentity(); + var identity = TestDataGenerator.CreateIdentityWithoutDevice(); var activeDevice = CreateOnboardedDevice(identity); var unOnboardedDevice = CreateUnonboardedDevice(identity); @@ -123,7 +123,7 @@ public void A_device_not_owned_by_active_identity_cannot_be_deleted() { // Arrange var activeIdentity = TestDataGenerator.CreateIdentity(); - var otherIdentity = TestDataGenerator.CreateIdentity(); + var otherIdentity = TestDataGenerator.CreateIdentityWithoutDevice(); var activeDevice = CreateOnboardedDevice(activeIdentity); var unOnboardedDeviceOfOtherIdentity = CreateUnonboardedDevice(otherIdentity); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsOwnerTests.cs similarity index 75% rename from Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessTests.cs rename to Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsOwnerTests.cs index 66a36d72bd..d9f793b6d8 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsOwnerTests.cs @@ -1,13 +1,15 @@ using Backbone.BuildingBlocks.Domain; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.FluentAssertions.Extensions; using FluentAssertions; using Xunit; namespace Backbone.Modules.Devices.Domain.Tests.Identities; -public class CancelDeletionProcessTests : AbstractTestsBase +public class CancelDeletionProcessAsOwnerTests : AbstractTestsBase { [Fact] public void Cancel_deletion_process() @@ -59,6 +61,22 @@ public void Throws_when_deletion_process_is_in_wrong_status() acting.Should().Throw().Which.Code.Should().Be("error.platform.validation.device.deletionProcessIsNotInRequiredStatus"); } + [Fact] + public void Raises_IdentityDeletionProcessStatusChangedDomainEvent_when_Cancelling() + { + // Arrange + var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(); + identity.DeletionProcesses[0].ClearDomainEvents(); + + // Act + var deletionProcess = identity.CancelDeletionProcessAsOwner(identity.DeletionProcesses[0].Id, identity.Devices[0].Id); + + var domainEvent = deletionProcess.Should().HaveASingleDomainEvent(); + domainEvent.DeletionProcessId.Should().Be(deletionProcess.Id); + domainEvent.Address.Should().Be(identity.Address); + domainEvent.Initiator.Should().Be(identity.Address); + } + private static void AssertAuditLogEntryWasCreated(IdentityDeletionProcess deletionProcess) { deletionProcess.AuditLog.Should().HaveCount(2); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsSupportTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsSupportTests.cs index 23d3b0a12c..18a59ab5c7 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsSupportTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelDeletionProcessAsSupportTests.cs @@ -1,11 +1,14 @@ using Backbone.BuildingBlocks.Domain; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.FluentAssertions.Extensions; using FluentAssertions; using Xunit; namespace Backbone.Modules.Devices.Domain.Tests.Identities; + public class CancelDeletionProcessAsSupportTests : AbstractTestsBase { [Fact] @@ -57,6 +60,21 @@ public void Throws_when_deletion_process_is_in_wrong_status() acting.Should().Throw().Which.Code.Should().Be("error.platform.validation.device.deletionProcessIsNotInRequiredStatus"); } + [Fact] + public void Raises_IdentityDeletionProcessStatusChangedDomainEvent_when_Cancelling() + { + // Arrange + var identity = TestDataGenerator.CreateIdentityWithApprovedDeletionProcess(); + + // Act + var deletionProcess = identity.CancelDeletionProcessAsSupport(identity.DeletionProcesses[0].Id); + + var domainEvent = deletionProcess.Should().HaveASingleDomainEvent(); + domainEvent.DeletionProcessId.Should().Be(deletionProcess.Id); + domainEvent.Address.Should().Be(identity.Address); + domainEvent.Initiator.Should().Be(null); + } + private static void AssertAuditLogEntryWasCreated(IdentityDeletionProcess deletionProcess) { deletionProcess.AuditLog.Should().HaveCount(2); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs index 02f63ae483..bce348b229 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/CancelStaleDeletionProcessTests.cs @@ -1,6 +1,8 @@ -using Backbone.Modules.Devices.Domain.Entities.Identities; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; +using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.FluentAssertions.Extensions; using FluentAssertions; using Xunit; @@ -64,7 +66,7 @@ public void Cancel_deletion_process_that_is_past_due_approval() } [Fact] - public void Canceling_stale_deletion_process_creates_audit_log_entry_when_executed() + public void Creates_audit_log_entry_when_executed() { // Arrange SystemTime.Set(DateTime.Parse("2020-01-01T00:00:00")); @@ -81,4 +83,26 @@ public void Canceling_stale_deletion_process_creates_audit_log_entry_when_execut result.Value.AuditLog[1].OldStatus.Should().Be(DeletionProcessStatus.WaitingForApproval); result.Value.AuditLog[1].NewStatus.Should().Be(DeletionProcessStatus.Cancelled); } + + [Fact] + public void Raises_IdentityDeletionProcessStatusChangedDomainEvent() + { + // Arrange + SystemTime.Set(DateTime.Parse("2020-01-01T00:00:00")); + var identity = TestDataGenerator.CreateIdentityWithDeletionProcessWaitingForApproval(); + SystemTime.Set(DateTime.Parse("2020-01-08T00:00:00")); + identity.DeletionProcesses[0].ClearDomainEvents(); + + // Act + var deletionProcessResult = identity.CancelStaleDeletionProcess(); + + deletionProcessResult.IsSuccess.Should().BeTrue(); + + var deletionProcess = deletionProcessResult.Value; + + var domainEvent = deletionProcess.Should().HaveASingleDomainEvent(); + domainEvent.DeletionProcessId.Should().Be(deletionProcess.Id); + domainEvent.Address.Should().Be(identity.Address); + domainEvent.Initiator.Should().Be(null); + } } diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/ChangeTierTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/ChangeTierTests.cs new file mode 100644 index 0000000000..a4ef930c3a --- /dev/null +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/ChangeTierTests.cs @@ -0,0 +1,83 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.Modules.Devices.Domain.Aggregates.Tier; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; +using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.FluentAssertions.Extensions; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Devices.Domain.Tests.Identities; + +public class ChangeTierTests : AbstractTestsBase +{ + [Fact] + public void Raises_TierOfIdentityChangedDomainEvent() + { + // Arrange + var identity = TestDataGenerator.CreateIdentity(); + var oldTier = identity.TierId; + + //Act + identity.ChangeTier(TierId.Generate()); + + // Assert + var domainEvent = identity.Should().HaveASingleDomainEvent(); + domainEvent.IdentityAddress.Should().Be(identity.Address); + domainEvent.OldTierId.Should().Be(oldTier); + domainEvent.NewTierId.Should().Be(identity.TierId); + } + + [Fact] + public void Changing_the_tier_to_valid_tier_is_successful() + { + // Arrange + var identity = TestDataGenerator.CreateIdentity(); + var newTier = TierId.Generate(); + + // Act + identity.ChangeTier(newTier); + + // Assert + identity.TierId.Should().Be(newTier); + } + + [Fact] + public void Changing_the_tier_from_QueuedForDeletion_throws_DomainException() + { + // Arrange + var identity = TestDataGenerator.CreateIdentity(Tier.QUEUED_FOR_DELETION.Id); + + // Act + var acting = () => identity.ChangeTier(TierId.Generate()); + + // Assert + acting.Should().Throw().Which.Message.Should().Be(DomainErrors.CannotChangeTierQueuedForDeletion().Message); + } + + [Fact] + public void Changing_the_tier_to_QueuedForDeletion_throws_DomainException() + { + // Arrange + var identity = TestDataGenerator.CreateIdentity(); + + // Act + var acting = () => identity.ChangeTier(Tier.QUEUED_FOR_DELETION.Id); + + // Assert + acting.Should().Throw().Which.Message.Should().Be(DomainErrors.CannotChangeTierQueuedForDeletion().Message); + } + + [Fact] + public void Changing_the_tier_to_the_same_tier_throws_DomainException() + { + // Arrange + var tierId = TierId.Generate(); + var identity = TestDataGenerator.CreateIdentity(tierId); + + // Act + var acting = () => identity.ChangeTier(tierId); + + // Assert + acting.Should().Throw().Which.Message.Should().Contain("cannot be the same"); + } +} diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessGracePeriodTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessGracePeriodTests.cs index e1450bbb06..4faacc21d8 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessGracePeriodTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionProcessGracePeriodTests.cs @@ -102,7 +102,7 @@ public void DeletionGracePeriodReminder3Sent_fails_when_no_approved_deletion_pro { // Arrange SystemTime.Set(DateTime.Parse("2000-01-01")); - var identity = TestDataGenerator.CreateIdentityWithOneDevice(); + var identity = TestDataGenerator.CreateIdentity(); // Act var acting = identity.DeletionGracePeriodReminder3Sent; @@ -125,7 +125,7 @@ private static void AssertAuditLogEntryWasCreated(IdentityDeletionProcess deleti private static Identity CreateIdentityWithApprovedDeletionProcess() { - var identity = TestDataGenerator.CreateIdentityWithOneDevice(); + var identity = TestDataGenerator.CreateIdentity(); Hasher.SetHasher(new DummyHasher([1, 2, 3])); identity.StartDeletionProcessAsOwner(identity.Devices.First().Id); diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionStartedTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionStartedTests.cs index 457b7fd730..0e4f52058f 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionStartedTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/DeletionStartedTests.cs @@ -42,7 +42,7 @@ public void Fails_to_start_if_GracePeriod_is_not_over() public void Fails_to_start_if_no_deletion_process_exists() { // Arrange - var identity = TestDataGenerator.CreateIdentityWithOneDevice(); + var identity = TestDataGenerator.CreateIdentity(); // Act var acting = identity.DeletionStarted; @@ -55,7 +55,7 @@ public void Fails_to_start_if_no_deletion_process_exists() public void Fails_to_start_if_no_approved_deletion_process_exists() { // Arrange - var identity = TestDataGenerator.CreateIdentityWithOneDevice(); + var identity = TestDataGenerator.CreateIdentity(); identity.StartDeletionProcessAsSupport(); // Act @@ -67,7 +67,7 @@ public void Fails_to_start_if_no_approved_deletion_process_exists() private static Identity CreateIdentityWithApprovedDeletionProcess() { - var identity = TestDataGenerator.CreateIdentityWithOneDevice(); + var identity = TestDataGenerator.CreateIdentity(); identity.StartDeletionProcessAsOwner(identity.Devices.First().Id); return identity; } diff --git a/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsSupportTests.cs b/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsSupportTests.cs index 7ff7e21f77..a6710f94fd 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsSupportTests.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/Identities/StartDeletionProcessAsSupportTests.cs @@ -1,10 +1,12 @@ using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Devices.Domain.Aggregates.Tier; +using Backbone.Modules.Devices.Domain.DomainEvents.Outgoing; using Backbone.Modules.Devices.Domain.Entities.Identities; using Backbone.Modules.Devices.Domain.Tests.Identities.TestDoubles; using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.FluentAssertions.Extensions; using FluentAssertions; using Xunit; @@ -50,6 +52,22 @@ public void Only_one_active_deletion_process_is_allowed_when_started() acting.Should().Throw().Which.Code.Should().Be("error.platform.validation.device.onlyOneActiveDeletionProcessAllowed"); } + [Fact] + public void Raises_IdentityDeletionProcessStartedDomainEvent() + { + //Arrange + var activeIdentity = CreateIdentity(); + + //Act + var deletionProcess = activeIdentity.StartDeletionProcessAsSupport(); + + //Assert + var domainEvent = deletionProcess.Should().HaveASingleDomainEvent(); + domainEvent.Address.Should().Be(activeIdentity.Address); + domainEvent.DeletionProcessId.Should().Be(deletionProcess.Id); + domainEvent.Initiator.Should().Be(null); + } + private static void AssertDeletionProcessWasStarted(Identity activeIdentity) { activeIdentity.DeletionProcesses.Should().HaveCount(1); diff --git a/Modules/Devices/test/Devices.Domain.Tests/TestDataGenerator.cs b/Modules/Devices/test/Devices.Domain.Tests/TestDataGenerator.cs index fe06c0039d..d9dc46faad 100644 --- a/Modules/Devices/test/Devices.Domain.Tests/TestDataGenerator.cs +++ b/Modules/Devices/test/Devices.Domain.Tests/TestDataGenerator.cs @@ -1,25 +1,40 @@ using Backbone.Modules.Devices.Domain.Aggregates.Tier; using Backbone.Modules.Devices.Domain.Entities.Identities; -using Backbone.Modules.Devices.Domain.Tests.Identities.TestDoubles; using static Backbone.UnitTestTools.Data.TestDataGenerator; namespace Backbone.Modules.Devices.Domain.Tests; public static class TestDataGenerator { - public static TierId CreateRandomTierId() + public static Identity CreateIdentity(TierId? tierId = null) { - return TierId.Generate(); + var identity = new Identity( + CreateRandomDeviceId(), + CreateRandomIdentityAddress(), + CreateRandomBytes(), + tierId ?? TierId.Generate(), + 1); + + var device = new Device(identity, CommunicationLanguage.DEFAULT_LANGUAGE); + identity.Devices.Add(device); + + identity.ClearDomainEvents(); + + return identity; } - public static Identity CreateIdentity() + public static Identity CreateIdentityWithoutDevice(TierId? tierId = null) { - return new Identity( + var identity = new Identity( CreateRandomDeviceId(), CreateRandomIdentityAddress(), CreateRandomBytes(), - CreateRandomTierId(), + tierId ?? TierId.Generate(), 1); + + identity.ClearDomainEvents(); + + return identity; } public static string GenerateString(int resultLength, char[]? chars = null) @@ -33,30 +48,25 @@ public static string GenerateString(int resultLength, char[]? chars = null) public static Identity CreateIdentityWithApprovedDeletionProcess() { var identity = CreateIdentity(); - var device = new Device(identity, CommunicationLanguage.DEFAULT_LANGUAGE); - identity.Devices.Add(device); - identity.StartDeletionProcessAsOwner(device.Id); + identity.StartDeletionProcessAsOwner(identity.Devices.First().Id); + + foreach (var deletionProcess in identity.DeletionProcesses) + { + deletionProcess.ClearDomainEvents(); + } + return identity; } public static Identity CreateIdentityWithDeletionProcessWaitingForApproval() { var identity = CreateIdentity(); - identity.Devices.Add(new Device(identity, CommunicationLanguage.DEFAULT_LANGUAGE)); - Hasher.SetHasher(new DummyHasher([1, 2, 3])); identity.StartDeletionProcessAsSupport(); - return identity; - } - public static Identity CreateIdentityWithOneDevice() - { - var identity = new Identity( - CreateRandomDeviceId(), - CreateRandomIdentityAddress(), - CreateRandomBytes(), - CreateRandomTierId(), - 1); - identity.Devices.Add(new Device(identity, CommunicationLanguage.DEFAULT_LANGUAGE)); + foreach (var deletionProcess in identity.DeletionProcesses) + { + deletionProcess.ClearDomainEvents(); + } return identity; } diff --git a/Modules/Files/src/Files.Application/Files/Commands/CreateFile/Handler.cs b/Modules/Files/src/Files.Application/Files/Commands/CreateFile/Handler.cs index ee47042f60..efa0ffc7eb 100644 --- a/Modules/Files/src/Files.Application/Files/Commands/CreateFile/Handler.cs +++ b/Modules/Files/src/Files.Application/Files/Commands/CreateFile/Handler.cs @@ -13,14 +13,12 @@ public class Handler : IRequestHandler private readonly IMapper _mapper; private readonly IFilesRepository _filesRepository; private readonly IUserContext _userContext; - private readonly IEventBus _eventBus; - public Handler(IUserContext userContext, IMapper mapper, IFilesRepository filesRepository, IEventBus eventBus) + public Handler(IUserContext userContext, IMapper mapper, IFilesRepository filesRepository) { _userContext = userContext; _mapper = mapper; _filesRepository = filesRepository; - _eventBus = eventBus; } public async Task Handle(CreateFileCommand request, CancellationToken cancellationToken) @@ -42,8 +40,6 @@ await _filesRepository.Add( cancellationToken ); - _eventBus.Publish(new FileUploadedDomainEvent(file)); - var response = _mapper.Map(file); return response; diff --git a/Modules/Files/src/Files.Domain/Entities/File.cs b/Modules/Files/src/Files.Domain/Entities/File.cs index 35d8578ecf..8aaf1fbb2b 100644 --- a/Modules/Files/src/Files.Domain/Entities/File.cs +++ b/Modules/Files/src/Files.Domain/Entities/File.cs @@ -1,10 +1,12 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Files.Domain.DomainEvents.Out; using Backbone.Tooling; namespace Backbone.Modules.Files.Domain.Entities; -public class File +public class File : Entity { // ReSharper disable once UnusedMember.Local private File() @@ -22,7 +24,8 @@ private File() EncryptedProperties = null!; } - public File(IdentityAddress createdBy, DeviceId createdByDevice, IdentityAddress owner, byte[] ownerSignature, byte[] cipherHash, byte[] content, long cipherSize, DateTime expiresAt, byte[] encryptedProperties) + public File(IdentityAddress createdBy, DeviceId createdByDevice, IdentityAddress owner, byte[] ownerSignature, byte[] cipherHash, byte[] content, long cipherSize, DateTime expiresAt, + byte[] encryptedProperties) { Id = FileId.New(); @@ -41,6 +44,8 @@ public File(IdentityAddress createdBy, DeviceId createdByDevice, IdentityAddress ExpiresAt = expiresAt; EncryptedProperties = encryptedProperties; + + RaiseDomainEvent(new FileUploadedDomainEvent(this)); } public FileId Id { get; set; } @@ -71,6 +76,7 @@ public void LoadContent(byte[] content) { throw new InvalidOperationException($"The Content of the file {Id} is already filled. It is not possible to change it."); } + Content = content; } diff --git a/Modules/Files/src/Files.Infrastructure/Persistence/Database/EntityTypeConfigurations/FileEntityTypeConfiguration.cs b/Modules/Files/src/Files.Infrastructure/Persistence/Database/EntityTypeConfigurations/FileEntityTypeConfiguration.cs index 5ab7592677..c7df0025da 100644 --- a/Modules/Files/src/Files.Infrastructure/Persistence/Database/EntityTypeConfigurations/FileEntityTypeConfiguration.cs +++ b/Modules/Files/src/Files.Infrastructure/Persistence/Database/EntityTypeConfigurations/FileEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using File = Backbone.Modules.Files.Domain.Entities.File; namespace Backbone.Modules.Files.Infrastructure.Persistence.Database.EntityTypeConfigurations; -public class FileEntityTypeConfiguration : IEntityTypeConfiguration +public class FileEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.ToTable("FileMetadata"); builder.Property(m => m.CipherHash).IsRequired(); diff --git a/Modules/Messages/src/Messages.Application/Messages/Commands/SendMessage/Handler.cs b/Modules/Messages/src/Messages.Application/Messages/Commands/SendMessage/Handler.cs index a690708802..80cd8398e2 100644 --- a/Modules/Messages/src/Messages.Application/Messages/Commands/SendMessage/Handler.cs +++ b/Modules/Messages/src/Messages.Application/Messages/Commands/SendMessage/Handler.cs @@ -1,9 +1,7 @@ using AutoMapper; using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Messages.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Messages.Domain.DomainEvents.Outgoing; using Backbone.Modules.Messages.Domain.Entities; using Backbone.Modules.Messages.Domain.Ids; using MediatR; @@ -14,7 +12,6 @@ namespace Backbone.Modules.Messages.Application.Messages.Commands.SendMessage; public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly ILogger _logger; private readonly IMapper _mapper; private readonly ApplicationOptions _options; @@ -25,7 +22,6 @@ public class Handler : IRequestHandler public Handler( IUserContext userContext, IMapper mapper, - IEventBus eventBus, IOptionsSnapshot options, ILogger logger, IMessagesRepository messagesRepository, @@ -33,7 +29,6 @@ public Handler( { _userContext = userContext; _mapper = mapper; - _eventBus = eventBus; _logger = logger; _options = options.Value; _messagesRepository = messagesRepository; @@ -53,8 +48,6 @@ public async Task Handle(SendMessageCommand request, Cancel await _messagesRepository.Add(message, cancellationToken); - _eventBus.Publish(new MessageCreatedDomainEvent(message)); - return _mapper.Map(message); } diff --git a/Modules/Messages/src/Messages.Domain/Entities/Attachment.cs b/Modules/Messages/src/Messages.Domain/Entities/Attachment.cs index 3a13c5e3a4..e18dc48084 100644 --- a/Modules/Messages/src/Messages.Domain/Entities/Attachment.cs +++ b/Modules/Messages/src/Messages.Domain/Entities/Attachment.cs @@ -1,8 +1,9 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.Modules.Messages.Domain.Ids; namespace Backbone.Modules.Messages.Domain.Entities; -public class Attachment +public class Attachment : Entity { public Attachment(FileId id) { diff --git a/Modules/Messages/src/Messages.Domain/Entities/Message.cs b/Modules/Messages/src/Messages.Domain/Entities/Message.cs index b1adff426d..866bed7d81 100644 --- a/Modules/Messages/src/Messages.Domain/Entities/Message.cs +++ b/Modules/Messages/src/Messages.Domain/Entities/Message.cs @@ -1,11 +1,13 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Messages.Domain.DomainEvents.Outgoing; using Backbone.Modules.Messages.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Messages.Domain.Entities; -public class Message : IIdentifiable +public class Message : Entity, IIdentifiable { // ReSharper disable once UnusedMember.Local private Message() @@ -29,6 +31,8 @@ public Message(IdentityAddress createdBy, DeviceId createdByDevice, byte[] body, CreatedByDevice = createdByDevice; Body = body; Attachments = attachments.ToList(); + + RaiseDomainEvent(new MessageCreatedDomainEvent(this)); } public MessageId Id { get; } diff --git a/Modules/Messages/src/Messages.Domain/Entities/RecipientInformation.cs b/Modules/Messages/src/Messages.Domain/Entities/RecipientInformation.cs index fea3b5d5dd..b5af12800b 100644 --- a/Modules/Messages/src/Messages.Domain/Entities/RecipientInformation.cs +++ b/Modules/Messages/src/Messages.Domain/Entities/RecipientInformation.cs @@ -1,10 +1,11 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Messages.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Messages.Domain.Entities; -public class RecipientInformation +public class RecipientInformation : Entity { // ReSharper disable once UnusedMember.Local private RecipientInformation() diff --git a/Modules/Messages/src/Messages.Domain/Entities/Relationship.cs b/Modules/Messages/src/Messages.Domain/Entities/Relationship.cs index 9a5ac3ed27..0955bc965e 100644 --- a/Modules/Messages/src/Messages.Domain/Entities/Relationship.cs +++ b/Modules/Messages/src/Messages.Domain/Entities/Relationship.cs @@ -1,9 +1,10 @@ +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Messages.Domain.Ids; namespace Backbone.Modules.Messages.Domain.Entities; -public class Relationship +public class Relationship : Entity { // ReSharper disable once UnusedMember.Local private Relationship() diff --git a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/AttachmentEntityTypeConfiguration.cs b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/AttachmentEntityTypeConfiguration.cs index 42e756532b..613b32cef7 100644 --- a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/AttachmentEntityTypeConfiguration.cs +++ b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/AttachmentEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Messages.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Messages.Infrastructure.Persistence.Database.EntityConfigurations; -public class AttachmentEntityTypeConfiguration : IEntityTypeConfiguration +public class AttachmentEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.ToTable($"{nameof(Attachment)}s"); builder diff --git a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/MessageEntityTypeConfiguration.cs b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/MessageEntityTypeConfiguration.cs index e55760c242..adf71b931d 100644 --- a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/MessageEntityTypeConfiguration.cs +++ b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/MessageEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Messages.Domain.Entities; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Messages.Infrastructure.Persistence.Database.EntityConfigurations; -public class MessageEntityTypeConfiguration : IEntityTypeConfiguration +public class MessageEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.HasIndex(m => m.CreatedBy); builder.Property(m => m.Body).IsRequired(false); diff --git a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RecipientInformationEntityTypeConfiguration.cs b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RecipientInformationEntityTypeConfiguration.cs index 4cc20f518e..b40370beda 100644 --- a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RecipientInformationEntityTypeConfiguration.cs +++ b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RecipientInformationEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Messages.Domain.Entities; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Messages.Infrastructure.Persistence.Database.EntityConfigurations; -public class RecipientInformationEntityTypeConfiguration : IEntityTypeConfiguration +public class RecipientInformationEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.HasKey(r => r.Id); builder.HasIndex(m => m.ReceivedAt); diff --git a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RelationshipEntityTypeConfiguration.cs b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RelationshipEntityTypeConfiguration.cs index cbc8c73ed1..f193d8bad1 100644 --- a/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RelationshipEntityTypeConfiguration.cs +++ b/Modules/Messages/src/Messages.Infrastructure/Persistence/Database/EntityConfigurations/RelationshipEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Messages.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Messages.Infrastructure.Persistence.Database.EntityConfigurations; -public class RelationshipEntityTypeConfiguration : IEntityTypeConfiguration +public class RelationshipEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.HasKey(r => r.Id); builder.ToTable(nameof(Relationship) + "s", "Relationships", x => x.ExcludeFromMigrations()); diff --git a/Modules/Messages/test/Messages.Domain.Tests/Messages/MessageTests.cs b/Modules/Messages/test/Messages.Domain.Tests/Messages/MessageTests.cs new file mode 100644 index 0000000000..1e79377a03 --- /dev/null +++ b/Modules/Messages/test/Messages.Domain.Tests/Messages/MessageTests.cs @@ -0,0 +1,37 @@ +using Backbone.Modules.Messages.Domain.DomainEvents.Outgoing; +using Backbone.Modules.Messages.Domain.Entities; +using Backbone.Modules.Messages.Domain.Ids; +using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.Data; +using Backbone.UnitTestTools.FluentAssertions.Extensions; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Messages.Domain.Tests.Messages; + +public class MessageTests : AbstractTestsBase +{ + [Fact] + public void Raises_MessageCreatedDomainEvent_when_created() + { + // Arrange + var sender = TestDataGenerator.CreateRandomIdentityAddress(); + var recipient = new RecipientInformation(TestDataGenerator.CreateRandomIdentityAddress(), RelationshipId.New(), []); + + // Act + var message = new Message( + sender, + TestDataGenerator.CreateRandomDeviceId(), + [], + [], + [recipient] + ); + + // Assert + var domainEvent = message.Should().HaveASingleDomainEvent(); + domainEvent.CreatedBy.Should().Be(sender); + domainEvent.Id.Should().Be(message.Id); + domainEvent.Recipients.Should().HaveCount(1); + domainEvent.Recipients.First().Should().Be(recipient.Address); + } +} diff --git a/Modules/Quotas/test/Quotas.Domain.Tests/Tests/Tiers/TierTests.cs b/Modules/Quotas/test/Quotas.Domain.Tests/Tests/Tiers/TierTests.cs index 3654545be8..74409cb98a 100644 --- a/Modules/Quotas/test/Quotas.Domain.Tests/Tests/Tiers/TierTests.cs +++ b/Modules/Quotas/test/Quotas.Domain.Tests/Tests/Tiers/TierTests.cs @@ -189,7 +189,7 @@ public void AddQuotaForAllMetricsOnQueuedForDeletion_only_creates_missing_quotas } [Fact] - public void Deleting_a_quota_triggers_TierQuotaDefinitionDeletedDomainEvent() + public void Deleting_a_quota_raises_TierQuotaDefinitionDeletedDomainEvent() { // Arrange var tierId = TierId.Parse("tier-id"); @@ -209,7 +209,7 @@ public void Deleting_a_quota_triggers_TierQuotaDefinitionDeletedDomainEvent() } [Fact] - public void Creating_a_quota_triggers_TierQuotaDefinitionCreatedDomainEvent() + public void Creating_a_quota_raises_TierQuotaDefinitionCreatedDomainEvent() { // Arrange var tierId = TierId.Parse("TIRsomeTierId1111111"); diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs index c1f8beae99..1ca6b345d4 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs @@ -1,8 +1,6 @@ using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; using Backbone.Modules.Relationships.Domain.Entities; using MediatR; @@ -13,14 +11,12 @@ public class Handler : IRequestHandler Handle(CreateRelationshipTemplateCommand request, CancellationToken cancellationToken) @@ -34,14 +30,6 @@ public async Task Handle(CreateRelationshipT await _relationshipTemplatesRepository.Add(template, cancellationToken); - PublishDomainEvent(template); - return _mapper.Map(template); } - - private void PublishDomainEvent(RelationshipTemplate template) - { - var evt = new RelationshipTemplateCreatedDomainEvent(template); - _eventBus.Publish(evt); - } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs index ce1f51164c..7419f47dbc 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs @@ -1,46 +1,33 @@ using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationshipChangeRequest; public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IMapper _mapper; private readonly IRelationshipsRepository _relationshipsRepository; private readonly IUserContext _userContext; - public Handler(IUserContext userContext, IMapper mapper, IEventBus eventBus, IRelationshipsRepository relationshipsRepository) + public Handler(IUserContext userContext, IMapper mapper, IRelationshipsRepository relationshipsRepository) { _userContext = userContext; _relationshipsRepository = relationshipsRepository; _mapper = mapper; - _eventBus = eventBus; } public async Task Handle(AcceptRelationshipChangeRequestCommand changeRequest, CancellationToken cancellationToken) { var relationship = await _relationshipsRepository.FindRelationship(changeRequest.Id, _userContext.GetAddress(), cancellationToken, track: true); - var change = relationship.AcceptChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); + relationship.AcceptChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); await _relationshipsRepository.Update(relationship); - PublishDomainEvent(change); - var response = _mapper.Map(relationship); return response; } - - private void PublishDomainEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedDomainEvent(change); - _eventBus.Publish(evt); - } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs index b04f7e7d94..f8ca705ea5 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs @@ -1,9 +1,7 @@ using AutoMapper; using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; using Backbone.Modules.Relationships.Domain.Entities; using MediatR; @@ -11,7 +9,6 @@ namespace Backbone.Modules.Relationships.Application.Relationships.Commands.Crea public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IMapper _mapper; private readonly IRelationshipsRepository _relationshipsRepository; private readonly IRelationshipTemplatesRepository _relationshipTemplatesRepository; @@ -21,13 +18,12 @@ public class Handler : IRequestHandler Handle(CreateRelationshipCommand r await ReadTemplateFromDb(); await EnsureRelationshipCanBeEstablished(); await CreateAndSaveRelationship(); - PublishDomainEvent(); return CreateResponse(); } @@ -83,13 +78,6 @@ private async Task CreateAndSaveRelationship() await _relationshipsRepository.Add(_relationship, _cancellationToken); } - private void PublishDomainEvent() - { - var change = _relationship.Changes.First(); // there is always one change, because the relationship was just created - var evt = new RelationshipChangeCreatedDomainEvent(change); - _eventBus.Publish(evt); - } - private CreateRelationshipResponse CreateResponse() { return _mapper.Map(_relationship); diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/Handler.cs index ee5f1fb5e9..805265aae8 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/Handler.cs @@ -1,46 +1,33 @@ using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationshipChangeRequest; public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IMapper _mapper; private readonly IRelationshipsRepository _relationshipsRepository; private readonly IUserContext _userContext; - public Handler(IUserContext userContext, IMapper mapper, IEventBus eventBus, IRelationshipsRepository relationshipsRepository) + public Handler(IUserContext userContext, IMapper mapper, IRelationshipsRepository relationshipsRepository) { _userContext = userContext; _relationshipsRepository = relationshipsRepository; _mapper = mapper; - _eventBus = eventBus; } public async Task Handle(RejectRelationshipChangeRequestCommand changeRequest, CancellationToken cancellationToken) { var relationship = await _relationshipsRepository.FindRelationship(changeRequest.Id, _userContext.GetAddress(), cancellationToken, track: true); - var change = relationship.RejectChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); + relationship.RejectChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); await _relationshipsRepository.Update(relationship); - PublishDomainEvent(change); - var response = _mapper.Map(relationship); return response; } - - private void PublishDomainEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedDomainEvent(change); - _eventBus.Publish(evt); - } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs index a35ca713c1..eed059ac29 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs @@ -1,46 +1,33 @@ using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipChangeRequest; public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IMapper _mapper; private readonly IRelationshipsRepository _relationshipsRepository; private readonly IUserContext _userContext; - public Handler(IUserContext userContext, IMapper mapper, IEventBus eventBus, IRelationshipsRepository relationshipsRepository) + public Handler(IUserContext userContext, IMapper mapper, IRelationshipsRepository relationshipsRepository) { _userContext = userContext; _relationshipsRepository = relationshipsRepository; _mapper = mapper; - _eventBus = eventBus; } public async Task Handle(RevokeRelationshipChangeRequestCommand changeRequest, CancellationToken cancellationToken) { var relationship = await _relationshipsRepository.FindRelationship(changeRequest.Id, _userContext.GetAddress(), cancellationToken, track: true); - var change = relationship.RevokeChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); + relationship.RevokeChange(changeRequest.ChangeId, _userContext.GetAddress(), _userContext.GetDeviceId(), changeRequest.ResponseContent); await _relationshipsRepository.Update(relationship); - PublishDomainEvent(change); - var response = _mapper.Map(relationship); return response; } - - private void PublishDomainEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedDomainEvent(change); - _eventBus.Publish(evt); - } } diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs b/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs index 9dc707af78..98dc25d1b8 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs +++ b/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs @@ -7,7 +7,7 @@ namespace Backbone.Modules.Relationships.Domain.Entities; -public class Relationship +public class Relationship : Entity { private readonly RelationshipChangeLog _changes = []; @@ -148,9 +148,11 @@ private void EnsureCanBeTerminated() } #region Selectors + public static Expression> HasParticipant(string identity) { return r => r.From == identity || r.To == identity; } + #endregion } diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChange.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChange.cs index aa4ce6bff3..e8c3a63158 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChange.cs +++ b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChange.cs @@ -1,12 +1,13 @@ using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; using Backbone.Modules.Relationships.Domain.Errors; using Backbone.Modules.Relationships.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Relationships.Domain.Entities; -public class RelationshipChange +public class RelationshipChange : Entity { // ReSharper disable once UnusedMember.Local protected RelationshipChange() @@ -27,6 +28,8 @@ protected RelationshipChange(Relationship relationship, IdentityAddress createdB Status = RelationshipChangeStatus.Pending; Request = new RelationshipChangeRequest(Id, createdBy, createdByDevice, requestContent); CreatedAt = SystemTime.UtcNow; + + RaiseDomainEvent(new RelationshipChangeCreatedDomainEvent(this)); } public RelationshipChangeId Id { get; } @@ -47,6 +50,8 @@ internal void Accept(IdentityAddress by, DeviceId byDevice, byte[]? content = nu EnsureCanBeAccepted(by, content); Status = RelationshipChangeStatus.Accepted; Response = new RelationshipChangeResponse(Id, by, byDevice, content); + + RaiseDomainEvent(new RelationshipChangeCompletedDomainEvent(this)); } protected virtual void EnsureCanBeAccepted(IdentityAddress by, byte[]? content) @@ -63,6 +68,8 @@ internal virtual void Reject(IdentityAddress by, DeviceId byDevice, byte[]? cont EnsureCanBeRejected(by, content); Status = RelationshipChangeStatus.Rejected; Response = new RelationshipChangeResponse(Id, by, byDevice, content); + + RaiseDomainEvent(new RelationshipChangeCompletedDomainEvent(this)); } protected virtual void EnsureCanBeRejected(IdentityAddress by, byte[]? content) @@ -79,6 +86,8 @@ internal virtual void Revoke(IdentityAddress by, DeviceId byDevice, byte[]? cont EnsureCanBeRevoked(by, content); Status = RelationshipChangeStatus.Revoked; Response = new RelationshipChangeResponse(Id, by, byDevice, content); + + RaiseDomainEvent(new RelationshipChangeCompletedDomainEvent(this)); } protected virtual void EnsureCanBeRevoked(IdentityAddress by, byte[]? content) diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs index 354a7d6e54..890b0e0a59 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs +++ b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs @@ -1,13 +1,14 @@ using System.Linq.Expressions; using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; using Backbone.Modules.Relationships.Domain.Errors; using Backbone.Modules.Relationships.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Relationships.Domain.Entities; -public class RelationshipTemplate +public class RelationshipTemplate : Entity { // ReSharper disable once UnusedMember.Local private RelationshipTemplate() @@ -28,6 +29,8 @@ public RelationshipTemplate(IdentityAddress createdBy, DeviceId createdByDevice, MaxNumberOfAllocations = maxNumberOfAllocations; ExpiresAt = expiresAt; Content = content; + + RaiseDomainEvent(new RelationshipTemplateCreatedDomainEvent(this)); } public RelationshipTemplateId Id { get; set; } diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs index 9934d1c77e..35065bfbd3 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs +++ b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs @@ -1,11 +1,12 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Relationships.Domain.Ids; using Backbone.Tooling; namespace Backbone.Modules.Relationships.Domain.Entities; -public class RelationshipTemplateAllocation +public class RelationshipTemplateAllocation : Entity { public RelationshipTemplateAllocation(RelationshipTemplateId relationshipTemplateId, IdentityAddress allocatedBy, DeviceId allocatedByDevice) { diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs index 824cd81d2c..59204dcb2e 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Relationships.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; -public class RelationshipChangeEntityTypeConfiguration : IEntityTypeConfiguration +public class RelationshipChangeEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.ToTable("RelationshipChanges"); builder.Ignore(x => x.IsCompleted); diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs index 4a4355ede7..d9a4302d53 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Relationships.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; -public class RelationshipEntityTypeConfiguration : IEntityTypeConfiguration +public class RelationshipEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.HasIndex(x => x.From); builder.HasIndex(x => x.To); diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs index 35295a35e3..3a74266d6a 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Relationships.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; -public class RelationshipTemplateAllocationEntityTypeConfiguration : IEntityTypeConfiguration +public class RelationshipTemplateAllocationEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.ToTable(nameof(RelationshipTemplateAllocation) + "s"); builder.HasKey(x => x.Id); diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs index bfb1ed43d0..2eab5bfd2e 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs @@ -1,13 +1,16 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Relationships.Domain.Entities; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; -public class RelationshipTemplateEntityTypeConfiguration : IEntityTypeConfiguration +public class RelationshipTemplateEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder .HasMany(x => x.Relationships) .WithOne(x => x.RelationshipTemplate) diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Commands/CreateRelationshipTemplate/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Commands/CreateRelationshipTemplate/HandlerTests.cs deleted file mode 100644 index 5e885b1e4c..0000000000 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Commands/CreateRelationshipTemplate/HandlerTests.cs +++ /dev/null @@ -1,58 +0,0 @@ -using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; -using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.UnitTestTools.BaseClasses; -using FakeItEasy; -using FluentAssertions.Execution; -using Xunit; - -namespace Backbone.Modules.Relationships.Application.Tests.Tests.RelationshipTemplates.Commands.CreateRelationshipTemplate; - -public class HandlerTests : AbstractTestsBase -{ - private readonly IUserContext _userContext; - private readonly IMapper _mapper; - private readonly IEventBus _eventBus; - - public HandlerTests() - { - _userContext = A.Fake(); - _mapper = A.Fake(); - _eventBus = A.Fake(); - AssertionScope.Current.FormattingOptions.MaxLines = 1000; - } - - [Fact] - public async Task Triggers_RelationshipTemplateCreatedDomainEvent() - { - // Arrange - var command = new CreateRelationshipTemplateCommand - { - ExpiresAt = DateTime.UtcNow, - Content = [1, 1, 1, 1, 1, 1, 1, 1] - }; - - var relationshipTemplatesRepository = A.Fake(); - A.CallTo(() => relationshipTemplatesRepository.Add(A._, CancellationToken.None)).Returns(Task.CompletedTask); - A.CallTo(() => _userContext.GetAddress()).Returns("some-identity-address"); - A.CallTo(() => _userContext.GetDeviceId()).Returns(DeviceId.Parse("DVCsomedeviceid12345")); - - var handler = CreateHandler(relationshipTemplatesRepository); - - // Act - await handler.Handle(command, CancellationToken.None); - - // Assert - A.CallTo(() => _eventBus.Publish(A._)).MustHaveHappened(); - } - - private Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository) - { - return new Handler(relationshipTemplatesRepository, _userContext, _mapper, _eventBus); - } -} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTemplateTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTemplateTests.cs new file mode 100644 index 0000000000..49973d50ec --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTemplateTests.cs @@ -0,0 +1,30 @@ +using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; +using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.Data; +using Backbone.UnitTestTools.FluentAssertions.Extensions; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests; + +public class RelationshipTemplateTests : AbstractTestsBase +{ + [Fact] + public void Raises_RelationshipTemplateCreatedDomainEvent_when_creating() + { + // Arrange + var address = TestDataGenerator.CreateRandomIdentityAddress(); + var deviceId = TestDataGenerator.CreateRandomDeviceId(); + var expiresAt = DateTime.UtcNow; + byte[] content = [1, 1, 1, 1, 1, 1, 1, 1]; + + // Act + var template = new RelationshipTemplate(address, deviceId, null, expiresAt, content); + + // Assert + var domainEvent = template.Should().HaveASingleDomainEvent(); + domainEvent.TemplateId.Should().Be(template.Id); + domainEvent.CreatedBy.Should().Be(address); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs index d72d277691..7d46cc2e8f 100644 --- a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs @@ -1,6 +1,7 @@ using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Domain.Errors; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.DomainEvents.Outgoing; using Backbone.Modules.Relationships.Domain.Entities; using Backbone.Modules.Relationships.Domain.Errors; using Backbone.Modules.Relationships.Domain.Ids; @@ -8,6 +9,7 @@ using Backbone.Tooling; using Backbone.UnitTestTools.BaseClasses; using Backbone.UnitTestTools.Data; +using Backbone.UnitTestTools.FluentAssertions.Extensions; using FluentAssertions; using Xunit; @@ -50,6 +52,20 @@ public void New_Relationship_Has_Correct_Data() change.Response.Should().BeNull(); } + [Fact] + public void Raises_RelationshipChangeCreatedDomainEvent_when_creating() + { + // Act + var relationship = new Relationship(TEMPLATE, FROM_IDENTITY, FROM_DEVICE, REQUEST_CONTENT); + + // Assert + var change = relationship.Changes.GetOpenCreation()!; + var domainEvent = change.Should().HaveASingleDomainEvent(); + domainEvent.ChangeId.Should().Be(change.Id); + domainEvent.RelationshipId.Should().Be(relationship.Id); + domainEvent.ChangeCreatedBy.Should().Be(change.Request.CreatedBy); + } + #region Accept Creation [Fact] @@ -116,6 +132,25 @@ public void Relationship_Cannot_Be_Accepted_By_Creator() acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); } + [Fact] + public void Raises_RelationshipChangeCompletedDomainEvent_when_accepting() + { + // Arrange + var relationship = CreatePendingRelationship(); + var change = relationship.Changes.GetOpenCreation()!; + change.ClearDomainEvents(); + + // Act + relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); + + // Assert + var domainEvent = change.Should().HaveASingleDomainEvent(); + domainEvent.ChangeId.Should().Be(change.Id); + domainEvent.RelationshipId.Should().Be(relationship.Id); + domainEvent.ChangeCreatedBy.Should().Be(change.Request.CreatedBy); + domainEvent.ChangeResult.Should().Be("Accepted"); + } + #endregion #region Reject Creation @@ -184,6 +219,25 @@ public void CreationRequest_Cannot_Be_Rejected_By_Creator() acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeRejectedByCreator()); } + [Fact] + public void Raises_RelationshipChangeCompletedDomainEvent_when_rejecting() + { + // Arrange + var relationship = CreatePendingRelationship(); + var change = relationship.Changes.GetOpenCreation()!; + change.ClearDomainEvents(); + + // Act + relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); + + // Assert + var domainEvent = change.Should().HaveASingleDomainEvent(); + domainEvent.ChangeId.Should().Be(change.Id); + domainEvent.RelationshipId.Should().Be(relationship.Id); + domainEvent.ChangeCreatedBy.Should().Be(change.Request.CreatedBy); + domainEvent.ChangeResult.Should().Be("Rejected"); + } + #endregion #region Revoke Creation @@ -252,6 +306,25 @@ public void CreationRequest_Cannot_Be_Revoked_By_Recipient() acting.Should().Throw().WithError(DomainErrors.ChangeRequestCanOnlyBeRevokedByCreator()); } + [Fact] + public void Raises_RelationshipChangeCompletedDomainEvent_when_revoking() + { + // Arrange + var relationship = CreatePendingRelationship(); + var change = relationship.Changes.GetOpenCreation()!; + change.ClearDomainEvents(); + + // Act + relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); + + // Assert + var domainEvent = change.Should().HaveASingleDomainEvent(); + domainEvent.ChangeId.Should().Be(change.Id); + domainEvent.RelationshipId.Should().Be(relationship.Id); + domainEvent.ChangeCreatedBy.Should().Be(change.Request.CreatedBy); + domainEvent.ChangeResult.Should().Be("Revoked"); + } + #endregion #endregion @@ -314,7 +387,7 @@ public void Requesting_Termination_Sets_Relevant_Data() relationship.Changes.Should().HaveCount(2); var termination = relationship.Changes.GetOpenTermination()!; - termination.Should().NotBeNull(); + AssertionExtensions.Should(termination).NotBeNull(); termination.Status.Should().Be(RelationshipChangeStatus.Pending); termination.Request.Should().NotBeNull(); termination.Request.CreatedBy.Should().Be(FROM_IDENTITY); diff --git a/Modules/Tokens/src/Tokens.Application/Tokens/Commands/CreateToken/Handler.cs b/Modules/Tokens/src/Tokens.Application/Tokens/Commands/CreateToken/Handler.cs index 3bf2aaeada..0fe396604a 100644 --- a/Modules/Tokens/src/Tokens.Application/Tokens/Commands/CreateToken/Handler.cs +++ b/Modules/Tokens/src/Tokens.Application/Tokens/Commands/CreateToken/Handler.cs @@ -1,8 +1,6 @@ using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Tokens.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Tokens.Domain.DomainEvents; using Backbone.Modules.Tokens.Domain.Entities; using MediatR; @@ -10,17 +8,15 @@ namespace Backbone.Modules.Tokens.Application.Tokens.Commands.CreateToken; public class Handler : IRequestHandler { - private readonly IEventBus _eventBus; private readonly IMapper _mapper; private readonly ITokensRepository _tokensRepository; private readonly IUserContext _userContext; - public Handler(IUserContext userContext, IMapper mapper, IEventBus eventBus, ITokensRepository tokensRepository) + public Handler(IUserContext userContext, IMapper mapper, ITokensRepository tokensRepository) { _userContext = userContext; _mapper = mapper; _tokensRepository = tokensRepository; - _eventBus = eventBus; } public async Task Handle(CreateTokenCommand request, CancellationToken cancellationToken) @@ -29,14 +25,6 @@ public async Task Handle(CreateTokenCommand request, Cancel await _tokensRepository.Add(newTokenEntity); - PublishDomainEvent(newTokenEntity); - return _mapper.Map(newTokenEntity); } - - private void PublishDomainEvent(Token newToken) - { - var evt = new TokenCreatedDomainEvent(newToken); - _eventBus.Publish(evt); - } } diff --git a/Modules/Tokens/src/Tokens.Domain/Entities/Token.cs b/Modules/Tokens/src/Tokens.Domain/Entities/Token.cs index 1d8767d6b7..80c8ffc20b 100644 --- a/Modules/Tokens/src/Tokens.Domain/Entities/Token.cs +++ b/Modules/Tokens/src/Tokens.Domain/Entities/Token.cs @@ -1,10 +1,12 @@ using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Tokens.Domain.DomainEvents; using Backbone.Tooling; namespace Backbone.Modules.Tokens.Domain.Entities; -public class Token +public class Token : Entity { // ReSharper disable once UnusedMember.Local private Token() @@ -27,6 +29,8 @@ public Token(IdentityAddress createdBy, DeviceId createdByDevice, byte[] content ExpiresAt = expiresAt; Content = content; + + RaiseDomainEvent(new TokenCreatedDomainEvent(this)); } public TokenId Id { get; set; } diff --git a/Modules/Tokens/src/Tokens.Infrastructure/Persistence/Database/EntityConfigurations/TokenEntityTypeConfiguration.cs b/Modules/Tokens/src/Tokens.Infrastructure/Persistence/Database/EntityConfigurations/TokenEntityTypeConfiguration.cs index ac6c2419cd..58ec0d0e26 100644 --- a/Modules/Tokens/src/Tokens.Infrastructure/Persistence/Database/EntityConfigurations/TokenEntityTypeConfiguration.cs +++ b/Modules/Tokens/src/Tokens.Infrastructure/Persistence/Database/EntityConfigurations/TokenEntityTypeConfiguration.cs @@ -1,13 +1,15 @@ +using Backbone.BuildingBlocks.Infrastructure.Persistence.Database.EntityTypeConfigurations; using Backbone.Modules.Tokens.Domain.Entities; -using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Backbone.Modules.Tokens.Infrastructure.Persistence.Database.EntityConfigurations; -public class TokenEntityTypeConfiguration : IEntityTypeConfiguration +public class TokenEntityTypeConfiguration : EntityEntityTypeConfiguration { - public void Configure(EntityTypeBuilder builder) + public override void Configure(EntityTypeBuilder builder) { + base.Configure(builder); + builder.Property(r => r.Content).IsRequired(false); } } diff --git a/Modules/Tokens/test/Tokens.Application.Tests/Tests/Tokens/CreateToken/HandlerTests.cs b/Modules/Tokens/test/Tokens.Application.Tests/Tests/Tokens/CreateToken/HandlerTests.cs deleted file mode 100644 index 683914ddf2..0000000000 --- a/Modules/Tokens/test/Tokens.Application.Tests/Tests/Tokens/CreateToken/HandlerTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; -using Backbone.BuildingBlocks.Domain; -using Backbone.BuildingBlocks.Domain.Events; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Tokens.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Tokens.Application.Tokens.Commands.CreateToken; -using Backbone.Modules.Tokens.Domain.DomainEvents; -using Backbone.Modules.Tokens.Domain.Entities; -using Backbone.UnitTestTools.BaseClasses; -using FakeItEasy; -using FluentAssertions.Execution; -using Xunit; - -namespace Backbone.Modules.Tokens.Application.Tests.Tests.Tokens.CreateToken; - -public class HandlerTests : AbstractTestsBase -{ - private readonly IUserContext _userContext; - private readonly IMapper _mapper; - private readonly IEventBus _eventBus; - - public HandlerTests() - { - _userContext = A.Fake(); - _mapper = A.Fake(); - _eventBus = A.Fake(); - AssertionScope.Current.FormattingOptions.MaxLines = 1000; - } - - [Fact] - public async Task Triggers_TokenCreatedDomainEvent() - { - // Arrange - var command = new CreateTokenCommand - { - ExpiresAt = DateTime.UtcNow, - Content = [1, 1, 1, 1, 1, 1, 1, 1] - }; - - var tokenRepository = A.Fake(); - A.CallTo(() => tokenRepository.Add(A._)).Returns(Task.CompletedTask); - A.CallTo(() => _userContext.GetAddress()).Returns("some-identity-address"); - A.CallTo(() => _userContext.GetDeviceId()).Returns(DeviceId.Parse("DVCsomedeviceid12345")); - - var handler = CreateHandler(tokenRepository); - - // Act - await handler.Handle(command, CancellationToken.None); - - // Assert - A.CallTo(() => _eventBus.Publish(A.That.IsInstanceOf(typeof(TokenCreatedDomainEvent)))).MustHaveHappened(); - } - - private Handler CreateHandler(ITokensRepository tokens) - { - return new Handler(_userContext, _mapper, _eventBus, tokens); - } -} diff --git a/Modules/Tokens/test/Tokens.Domain.Tests/Tests/TokenTests.cs b/Modules/Tokens/test/Tokens.Domain.Tests/Tests/TokenTests.cs new file mode 100644 index 0000000000..7e8c108f82 --- /dev/null +++ b/Modules/Tokens/test/Tokens.Domain.Tests/Tests/TokenTests.cs @@ -0,0 +1,30 @@ +using Backbone.Modules.Tokens.Domain.DomainEvents; +using Backbone.Modules.Tokens.Domain.Entities; +using Backbone.UnitTestTools.BaseClasses; +using Backbone.UnitTestTools.Data; +using Backbone.UnitTestTools.FluentAssertions.Extensions; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Tokens.Domain.Tests.Tests; + +public class TokenTests : AbstractTestsBase +{ + [Fact] + public void Raises_TemplateCreatedDomainEvent_on_creation() + { + // Arrange + var address = TestDataGenerator.CreateRandomIdentityAddress(); + var deviceId = TestDataGenerator.CreateRandomDeviceId(); + var expiresAt = DateTime.UtcNow; + byte[] content = [1, 1, 1, 1, 1, 1, 1, 1]; + + // Act + var token = new Token(address, deviceId, content, expiresAt); + + // Assert + var domainEvent = token.Should().HaveASingleDomainEvent(); + domainEvent.TokenId.Should().Be(token.Id); + domainEvent.CreatedBy.Should().Be(address); + } +} diff --git a/Modules/Tokens/test/Tokens.Domain.Tests/Tokens.Domain.Tests.csproj b/Modules/Tokens/test/Tokens.Domain.Tests/Tokens.Domain.Tests.csproj new file mode 100644 index 0000000000..06f39f2c38 --- /dev/null +++ b/Modules/Tokens/test/Tokens.Domain.Tests/Tokens.Domain.Tests.csproj @@ -0,0 +1,26 @@ + + + + false + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + +