Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consumer Api: Decompose Relationships during Identity Deletion #940

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
526ad3a
feat: Add relationship audit log reason for decomposition due to iden…
MH321Productions Nov 8, 2024
6d5f477
feat: Make relationship participants writable internally and write sk…
MH321Productions Nov 8, 2024
8f114d3
Merge branch 'main' into decompose-relationships-during-identity-dele…
MH321Productions Nov 8, 2024
b8814bf
Merge branch 'main' into decompose-relationships-during-identity-dele…
MH321Productions Nov 12, 2024
b87c915
Merge branch 'main' into decompose-relationships-during-identity-dele…
MH321Productions Nov 13, 2024
1209a9c
chore: Rename DeleteRelationshipsOfIdentityCommand to DecomposeRelati…
MH321Productions Nov 14, 2024
a32e753
feat: Make CreatedBy property in Relationship Audit Log nullable
MH321Productions Nov 14, 2024
7fb11e4
chore: Clear cache when deleting Relationships and Relationship Templ…
MH321Productions Nov 14, 2024
db3eb7e
fix: Include every properties when querying for relationships
MH321Productions Nov 14, 2024
33d73bb
feat: Add method to decompose relationship due to identity deletion
MH321Productions Nov 14, 2024
6c162c7
feat: Add methods and command for anonymizing a relationship
MH321Productions Nov 14, 2024
dbbd831
feat: Use the decomposition and anonymization commands
MH321Productions Nov 14, 2024
75bbc0a
Merge branch 'main' into decompose-relationships-during-identity-dele…
MH321Productions Nov 14, 2024
e2bfc52
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 15, 2024
3031858
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 15, 2024
7f250b4
chore: Rename tests, methods and variables, resolve pr comments
MH321Productions Nov 15, 2024
68abbd3
chore: Merge Decomposition and Anonymization into one command
MH321Productions Nov 18, 2024
f3849dd
chore: Remove cache clearing from repositories
MH321Productions Nov 18, 2024
e9b91f5
chore: Write unit tests for Relationship Decomposition due to Identit…
MH321Productions Nov 18, 2024
2df8e9e
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 18, 2024
dc8736b
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 19, 2024
7f65900
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 19, 2024
a1e7bd7
chore: Include Anonymization method in the Decomposition, remove unne…
MH321Productions Nov 19, 2024
28b40a4
Merge branch 'main' into decompose-relationships-during-identity-dele…
mergify[bot] Nov 20, 2024
bf5fc24
chore: Add unit test for anonymization#
MH321Productions Nov 20, 2024
1461f41
fix: Fix formatting
MH321Productions Nov 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Backbone.BuildingBlocks.Application.Identities;
using Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeRelationshipsOfIdentity;
using Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;
using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity;
using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.DeleteRelationshipTemplatesOfIdentity;
using FakeItEasy;
Expand All @@ -23,7 +23,7 @@ public async Task Deleter_calls_correct_command()

// Assert
A.CallTo(() => mockMediator.Send(
A<DecomposeRelationshipsOfIdentityCommand>.That.Matches(i => i.IdentityAddress == identityAddress),
A<DecomposeAndAnonymizeRelationshipsOfIdentityCommand>.That.Matches(i => i.IdentityAddress == identityAddress),
A<CancellationToken>._)).MustHaveHappenedOnceExactly();
A.CallTo(() => mockMediator.Send(
A<DeleteRelationshipTemplatesOfIdentityCommand>.That.Matches(i => i.IdentityAddress == identityAddress),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Backbone.BuildingBlocks.Application.Identities;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.Modules.Relationships.Application.Relationships.Commands.AnonymizeRelationshipsOfIdentity;
using Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeRelationshipsOfIdentity;
using Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;
using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity;
using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.DeleteRelationshipTemplatesOfIdentity;
using MediatR;
Expand All @@ -21,12 +20,11 @@ public IdentityDeleter(IMediator mediator, IDeletionProcessLogger deletionProces

public async Task Delete(IdentityAddress identityAddress)
{
await _mediator.Send(new DecomposeRelationshipsOfIdentityCommand(identityAddress));
await _mediator.Send(new DecomposeAndAnonymizeRelationshipsOfIdentityCommand(identityAddress));
await _deletionProcessLogger.LogDeletion(identityAddress, "Relationships");
await _mediator.Send(new DeleteRelationshipTemplatesOfIdentityCommand(identityAddress));
await _deletionProcessLogger.LogDeletion(identityAddress, "RelationshipTemplates");
await _mediator.Send(new AnonymizeRelationshipTemplateAllocationsAllocatedByIdentityCommand(identityAddress));
await _deletionProcessLogger.LogDeletion(identityAddress, "RelationshipTemplateAllocations");
await _mediator.Send(new AnonymizeRelationshipsOfIdentityCommand(identityAddress));
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using MediatR;

namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;

public class DecomposeAndAnonymizeRelationshipsOfIdentityCommand : IRequest
{
public DecomposeAndAnonymizeRelationshipsOfIdentityCommand(string identityAddress)
{
IdentityAddress = identityAddress;
}

public string IdentityAddress { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
using System.Linq.Expressions;
using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Relationships.Domain.Aggregates.Relationships;
using FakeItEasy;
using Microsoft.Extensions.Options;

namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeRelationshipsOfIdentity;
namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;

public class HandlerTests : AbstractTestsBase
{
[Fact]
public async Task Command_calls_find_on_repository()
public async Task Command_calls_update_on_repository()
{
// Arrange
var mockRelationshipTemplatesRepository = A.Fake<IRelationshipsRepository>();
var mockOptions = A.Dummy<IOptions<ApplicationOptions>>();

var handler = new Handler(mockRelationshipTemplatesRepository);
var request = new DecomposeRelationshipsOfIdentityCommand(CreateRandomIdentityAddress());
var handler = new Handler(mockRelationshipTemplatesRepository, mockOptions);
var request = new DecomposeAndAnonymizeRelationshipsOfIdentityCommand(CreateRandomIdentityAddress());

// Act
await handler.Handle(request, CancellationToken.None);

// Assert
A.CallTo(() => mockRelationshipTemplatesRepository.FindRelationships(A<Expression<Func<Relationship, bool>>>._, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => mockRelationshipTemplatesRepository.Update(A<IEnumerable<Relationship>>._)).MustHaveHappened();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository;
using Backbone.Modules.Relationships.Domain.Aggregates.Relationships;
using MediatR;
using Microsoft.Extensions.Options;

namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;

public class Handler : IRequestHandler<DecomposeAndAnonymizeRelationshipsOfIdentityCommand>
{
private readonly IRelationshipsRepository _relationshipsRepository;
private readonly ApplicationOptions _applicationOptions;

public Handler(IRelationshipsRepository relationshipsRepository, IOptions<ApplicationOptions> applicationOptions)
{
_relationshipsRepository = relationshipsRepository;
_applicationOptions = applicationOptions.Value;
}

public async Task Handle(DecomposeAndAnonymizeRelationshipsOfIdentityCommand request, CancellationToken cancellationToken)
{
var relationships = (await _relationshipsRepository.FindRelationships(Relationship.HasParticipant(request.IdentityAddress), cancellationToken)).ToList();

foreach (var relationship in relationships)
{
relationship.DecomposeDueToIdentityDeletion(request.IdentityAddress);
relationship.AnonymizeParticipant(request.IdentityAddress, _applicationOptions.DidDomainName);
}

await _relationshipsRepository.Update(relationships);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Backbone.BuildingBlocks.Application.Extensions;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using FluentValidation;

namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DecomposeAndAnonymizeRelationshipsOfIdentity;

public class Validator : AbstractValidator<DecomposeAndAnonymizeRelationshipsOfIdentityCommand>
{
public Validator()
{
RuleFor(x => x.IdentityAddress).ValidId<DecomposeAndAnonymizeRelationshipsOfIdentityCommand, IdentityAddress>();
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Backbone.BuildingBlocks.Domain.Exceptions;
using Backbone.DevelopmentKit.Identity.ValueObjects;
using Backbone.UnitTestTools.Extensions;
using static Backbone.Modules.Relationships.Domain.TestHelpers.TestData;

namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships;

public class RelationshipAnonymizeTests : AbstractTestsBase
{
private const string DID_DOMAIN_NAME = "localhost";

[Theory]
[InlineData(RelationshipStatus.DeletionProposed)]
[InlineData(RelationshipStatus.ReadyForDeletion)]
public void Anonymize_can_be_performed_for_decomposed_relationship(RelationshipStatus status)
{
// Arrange
var relationship = CreateRelationshipInStatus(status, IDENTITY_1, IDENTITY_2);

// Act
var acting = () => relationship.AnonymizeParticipant(IDENTITY_1, DID_DOMAIN_NAME);

// Assert
acting.Should().NotThrow();
relationship.From.Should().Be(IdentityAddress.GetAnonymized(DID_DOMAIN_NAME));
}

[Fact]
public void Anonymize_can_be_performed_for_other_participant()
{
// Arrange
var relationship = CreateRelationshipReadyForDeletion(IDENTITY_1, IDENTITY_2);

// Act
var acting = () => relationship.AnonymizeParticipant(IDENTITY_2, DID_DOMAIN_NAME);

// Assert
acting.Should().NotThrow();
relationship.To.Should().Be(IdentityAddress.GetAnonymized(DID_DOMAIN_NAME));
}

[Fact]
public void Anonymize_can_not_be_performed_by_other_identities()
{
// Arrange
var relationship = CreateRelationshipReadyForDeletion(IDENTITY_1, IDENTITY_2);

// Act
var acting = () => relationship.AnonymizeParticipant(CreateRandomIdentityAddress(), DID_DOMAIN_NAME);

// Assert
acting.Should().Throw<DomainException>().WithError("error.platform.validation.relationship.requestingIdentityDoesNotBelongToRelationship");
}

[Theory]
[InlineData(RelationshipStatus.Pending)]
[InlineData(RelationshipStatus.Active)]
[InlineData(RelationshipStatus.Rejected)]
[InlineData(RelationshipStatus.Revoked)]
[InlineData(RelationshipStatus.Terminated)]
public void Anonymize_can_not_be_performed_when_not_decomposed(RelationshipStatus status)
{
// Arrange
var relationship = CreateRelationshipInStatus(status, IDENTITY_1, IDENTITY_2);

// Act
var acting = () => relationship.AnonymizeParticipant(IDENTITY_1, DID_DOMAIN_NAME);

// Assert
acting.Should().Throw<DomainException>().WithError("error.platform.validation.relationship.relationshipIsNotInCorrectStatus");
}

[Fact]
public void Anonymize_anonymizes_the_audit_logs()
{
// Arrange
var relationship = CreateActiveRelationship(IDENTITY_1, IDENTITY_2);
relationship.DecomposeDueToIdentityDeletion(IDENTITY_1);
var anonymousIdentity = IdentityAddress.GetAnonymized(DID_DOMAIN_NAME);

// Act
relationship.AnonymizeParticipant(IDENTITY_1, DID_DOMAIN_NAME);

// Assert
relationship.AuditLog.Should().HaveCount(3);
relationship.AuditLog[0].CreatedBy.Should().Be(anonymousIdentity);
relationship.AuditLog[2].CreatedBy.Should().Be(anonymousIdentity);
}
}
Loading