diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20231117103711_RelationshipsOverview.cs b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20231117103711_RelationshipsOverview.cs index ea5c9d7c54..8dbcaf0209 100644 --- a/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20231117103711_RelationshipsOverview.cs +++ b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20231117103711_RelationshipsOverview.cs @@ -11,24 +11,36 @@ public partial class RelationshipsOverview : Migration protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.Sql(""" - CREATE VIEW "RelationshipOverviews" AS - SELECT - "Relationships"."From" AS "From", - "Relationships"."To" AS "To", - "Relationships"."RelationshipTemplateId" AS "RelationshipTemplateId", - "Relationships"."Status" AS "Status", - "Relationships"."CreatedAt" AS "CreatedAt", - "RelationshipChanges"."Res_CreatedAt" AS "AnsweredAt", - "RelationshipChanges"."Req_CreatedByDevice" AS "CreatedByDevice", - "RelationshipChanges"."Res_CreatedByDevice" AS "AnsweredByDevice" - FROM - "Relationships"."Relationships" AS "Relationships" - LEFT JOIN - "Relationships"."RelationshipChanges" AS "RelationshipChanges" - ON - "Relationships"."Id" = "RelationshipChanges"."RelationshipId" - WHERE - "RelationshipChanges"."Type" = 10 + DO + $$ + BEGIN + IF EXISTS ( + SELECT FROM information_schema.tables + WHERE table_schema = 'Relationships' + AND table_name = 'RelationshipChanges' + ) THEN + CREATE VIEW "RelationshipOverviews" AS + SELECT + "Relationships"."From" AS "From", + "Relationships"."To" AS "To", + "Relationships"."RelationshipTemplateId" AS "RelationshipTemplateId", + "Relationships"."Status" AS "Status", + "Relationships"."CreatedAt" AS "CreatedAt", + "RelationshipChanges"."Res_CreatedAt" AS "AnsweredAt", + "RelationshipChanges"."Req_CreatedByDevice" AS "CreatedByDevice", + "RelationshipChanges"."Res_CreatedByDevice" AS "AnsweredByDevice" + FROM + "Relationships"."Relationships" AS "Relationships" + LEFT JOIN + "Relationships"."RelationshipChanges" AS "RelationshipChanges" + ON + "Relationships"."Id" = "RelationshipChanges"."RelationshipId" + WHERE + "RelationshipChanges"."Type" = 10; + END IF; + END; + $$ + """); } diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.Designer.cs b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.Designer.cs new file mode 100644 index 0000000000..8b58d5593d --- /dev/null +++ b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.Designer.cs @@ -0,0 +1,205 @@ +// +using System; +using Backbone.AdminApi.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Backbone.AdminApi.Infrastructure.Database.Postgres.Migrations +{ + [DbContext(typeof(AdminApiDbContext))] + [Migration("20240412142555_RelationshipsRevamp")] + partial class RelationshipsRevamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.ClientOverview", b => + { + b.Property("ClientId") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("text"); + + b.Property("MaxIdentities") + .HasColumnType("integer"); + + b.Property("NumberOfIdentities") + .HasColumnType("integer"); + + b.HasKey("ClientId"); + + b.ToTable((string)null); + + b.ToView("ClientOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.IdentityOverview", b => + { + b.Property("Address") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedWithClient") + .HasColumnType("text"); + + b.Property("DatawalletVersion") + .HasColumnType("integer"); + + b.Property("IdentityVersion") + .HasColumnType("smallint"); + + b.Property("LastLoginAt") + .HasColumnType("timestamp with time zone"); + + b.Property("NumberOfDevices") + .HasColumnType("integer"); + + b.HasKey("Address"); + + b.ToTable((string)null); + + b.ToView("IdentityOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.RelationshipOverview", b => + { + b.Property("AnsweredAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AnsweredByDevice") + .HasColumnType("text"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedByDevice") + .IsRequired() + .HasColumnType("text"); + + b.Property("From") + .IsRequired() + .HasColumnType("text"); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasColumnType("text"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("To") + .IsRequired() + .HasColumnType("text"); + + b.ToTable((string)null); + + b.ToView("RelationshipOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.TierOverview", b => + { + b.Property("CanBeManuallyAssigned") + .HasColumnType("boolean"); + + b.Property("CanBeUsedAsDefaultForClient") + .HasColumnType("boolean"); + + b.Property("Id") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NumberOfIdentities") + .HasColumnType("integer"); + + b.ToTable((string)null); + + b.ToView("TierOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.ClientOverview", b => + { + b.OwnsOne("Backbone.AdminApi.Infrastructure.DTOs.TierDTO", "DefaultTier", b1 => + { + b1.Property("ClientOverviewClientId") + .HasColumnType("text"); + + b1.Property("Id") + .IsRequired() + .HasColumnType("text") + .HasColumnName("DefaultTierId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("DefaultTierName"); + + b1.HasKey("ClientOverviewClientId"); + + b1.ToTable((string)null); + + b1.ToView("ClientOverviews"); + + b1.WithOwner() + .HasForeignKey("ClientOverviewClientId"); + }); + + b.Navigation("DefaultTier") + .IsRequired(); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.IdentityOverview", b => + { + b.OwnsOne("Backbone.AdminApi.Infrastructure.DTOs.TierDTO", "Tier", b1 => + { + b1.Property("IdentityOverviewAddress") + .HasColumnType("text"); + + b1.Property("Id") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TierId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("TierName"); + + b1.HasKey("IdentityOverviewAddress"); + + b1.ToTable((string)null); + + b1.ToView("IdentityOverviews"); + + b1.WithOwner() + .HasForeignKey("IdentityOverviewAddress"); + }); + + b.Navigation("Tier") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.cs b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.cs new file mode 100644 index 0000000000..4f62886da8 --- /dev/null +++ b/AdminApi/src/AdminApi.Infrastructure.Database.Postgres/Migrations/20240412142555_RelationshipsRevamp.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Backbone.AdminApi.Infrastructure.Database.Postgres.Migrations +{ + /// + public partial class RelationshipsRevamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql(""" + CREATE OR REPLACE VIEW "RelationshipOverviews" AS + SELECT + "Relationships"."From" AS "From", + "Relationships"."To" AS "To", + "Relationships"."RelationshipTemplateId" AS "RelationshipTemplateId", + "Relationships"."Status" AS "Status", + "AuditLog1"."CreatedAt" AS "CreatedAt", + "AuditLog1"."CreatedByDevice" AS "CreatedByDevice", + "AuditLog2"."CreatedAt" AS "AnsweredAt", + "AuditLog2"."CreatedByDevice" AS "AnsweredByDevice" + FROM "Relationships"."Relationships" AS "Relationships" + LEFT JOIN "Relationships"."RelationshipAuditLog" AS "AuditLog1" + ON "Relationships"."Id" = "AuditLog1"."RelationshipId" AND "AuditLog1"."Reason" = 0 + LEFT JOIN "Relationships"."RelationshipAuditLog" AS "AuditLog2" + ON "Relationships"."Id" = "AuditLog2"."RelationshipId" AND "AuditLog2"."Reason" = 1 + """); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql(""" + CREATE OR REPLACE VIEW "RelationshipOverviews" AS + SELECT + "Relationships"."From" AS "From", + "Relationships"."To" AS "To", + "Relationships"."RelationshipTemplateId" AS "RelationshipTemplateId", + "Relationships"."Status" AS "Status", + "Relationships"."CreatedAt" AS "CreatedAt", + "RelationshipChanges"."Res_CreatedAt" AS "AnsweredAt", + "RelationshipChanges"."Req_CreatedByDevice" AS "CreatedByDevice", + "RelationshipChanges"."Res_CreatedByDevice" AS "AnsweredByDevice" + FROM + "Relationships"."Relationships" AS "Relationships" + LEFT JOIN + "Relationships"."RelationshipChanges" AS "RelationshipChanges" + ON + "Relationships"."Id" = "RelationshipChanges"."RelationshipId" + WHERE + "RelationshipChanges"."Type" = 10 + """); + } + } +} diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20231117101915_RelationshipsOverview.cs b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20231117101915_RelationshipsOverview.cs index 46685be8b8..32e75e5824 100644 --- a/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20231117101915_RelationshipsOverview.cs +++ b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20231117101915_RelationshipsOverview.cs @@ -11,24 +11,27 @@ public partial class RelationshipsOverview : Migration protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.Sql(""" - CREATE VIEW RelationshipOverviews AS - SELECT - [RELATIONSHIPS].[From] AS [From], - [RELATIONSHIPS].[To] AS [To], - [RELATIONSHIPS].[RelationshipTemplateId] AS [RelationshipTemplateId], - [RELATIONSHIPS].[Status] AS [Status], - [RELATIONSHIPS].[CreatedAt] AS [CreatedAt], - [RELATIONSHIPCHANGES].[Res_CreatedAt] AS [AnsweredAt], - [RELATIONSHIPCHANGES].[Req_CreatedByDevice] AS [CreatedByDevice], - [RELATIONSHIPCHANGES].[Res_CreatedByDevice] AS [AnsweredByDevice] - FROM - [Relationships].[Relationships] AS RELATIONSHIPS - LEFT JOIN - [Relationships].[RelationshipChanges] AS RELATIONSHIPCHANGES - ON - [RELATIONSHIPS].[Id] = [RELATIONSHIPCHANGES].[RelationshipId] - WHERE - [RELATIONSHIPCHANGES].[Type] = 10 + IF EXISTS (SELECT * FROM information_schema.tables WHERE table_schema = 'Relationships' AND table_name = 'RelationshipChanges') + BEGIN + EXECUTE('CREATE OR ALTER VIEW RelationshipOverviews AS + SELECT + [RELATIONSHIPS].[From] AS [From], + [RELATIONSHIPS].[To] AS [To], + [RELATIONSHIPS].[RelationshipTemplateId] AS [RelationshipTemplateId], + [RELATIONSHIPS].[Status] AS [Status], + [RELATIONSHIPS].[CreatedAt] AS [CreatedAt], + [RELATIONSHIPCHANGES].[Res_CreatedAt] AS [AnsweredAt], + [RELATIONSHIPCHANGES].[Req_CreatedByDevice] AS [CreatedByDevice], + [RELATIONSHIPCHANGES].[Res_CreatedByDevice] AS [AnsweredByDevice] + FROM + [Relationships].[Relationships] AS RELATIONSHIPS + LEFT JOIN + [Relationships].[RelationshipChanges] AS RELATIONSHIPCHANGES + ON + [RELATIONSHIPS].[Id] = [RELATIONSHIPCHANGES].[RelationshipId] + WHERE + [RELATIONSHIPCHANGES].[Type] = 10') + END """); } diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.Designer.cs b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.Designer.cs new file mode 100644 index 0000000000..53357b5345 --- /dev/null +++ b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.Designer.cs @@ -0,0 +1,205 @@ +// +using System; +using Backbone.AdminApi.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Backbone.AdminApi.Infrastructure.Database.SqlServer.Migrations +{ + [DbContext(typeof(AdminApiDbContext))] + [Migration("20240412142551_RelationshipsRevamp")] + partial class RelationshipsRevamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.ClientOverview", b => + { + b.Property("ClientId") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("DisplayName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MaxIdentities") + .HasColumnType("int"); + + b.Property("NumberOfIdentities") + .HasColumnType("int"); + + b.HasKey("ClientId"); + + b.ToTable((string)null); + + b.ToView("ClientOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.IdentityOverview", b => + { + b.Property("Address") + .HasColumnType("nvarchar(450)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedWithClient") + .HasColumnType("nvarchar(max)"); + + b.Property("DatawalletVersion") + .HasColumnType("int"); + + b.Property("IdentityVersion") + .HasColumnType("tinyint"); + + b.Property("LastLoginAt") + .HasColumnType("datetime2"); + + b.Property("NumberOfDevices") + .HasColumnType("int"); + + b.HasKey("Address"); + + b.ToTable((string)null); + + b.ToView("IdentityOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.RelationshipOverview", b => + { + b.Property("AnsweredAt") + .HasColumnType("datetime2"); + + b.Property("AnsweredByDevice") + .HasColumnType("nvarchar(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedByDevice") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("From") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("To") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.ToTable((string)null); + + b.ToView("RelationshipOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.TierOverview", b => + { + b.Property("CanBeManuallyAssigned") + .HasColumnType("bit"); + + b.Property("CanBeUsedAsDefaultForClient") + .HasColumnType("bit"); + + b.Property("Id") + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("NumberOfIdentities") + .HasColumnType("int"); + + b.ToTable((string)null); + + b.ToView("TierOverviews", (string)null); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.ClientOverview", b => + { + b.OwnsOne("Backbone.AdminApi.Infrastructure.DTOs.TierDTO", "DefaultTier", b1 => + { + b1.Property("ClientOverviewClientId") + .HasColumnType("nvarchar(450)"); + + b1.Property("Id") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("DefaultTierId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("DefaultTierName"); + + b1.HasKey("ClientOverviewClientId"); + + b1.ToTable((string)null); + + b1.ToView("ClientOverviews"); + + b1.WithOwner() + .HasForeignKey("ClientOverviewClientId"); + }); + + b.Navigation("DefaultTier") + .IsRequired(); + }); + + modelBuilder.Entity("Backbone.AdminApi.Infrastructure.DTOs.IdentityOverview", b => + { + b.OwnsOne("Backbone.AdminApi.Infrastructure.DTOs.TierDTO", "Tier", b1 => + { + b1.Property("IdentityOverviewAddress") + .HasColumnType("nvarchar(450)"); + + b1.Property("Id") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("TierId"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("TierName"); + + b1.HasKey("IdentityOverviewAddress"); + + b1.ToTable((string)null); + + b1.ToView("IdentityOverviews"); + + b1.WithOwner() + .HasForeignKey("IdentityOverviewAddress"); + }); + + b.Navigation("Tier") + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.cs b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.cs new file mode 100644 index 0000000000..e51fdaeb96 --- /dev/null +++ b/AdminApi/src/AdminApi.Infrastructure.Database.SqlServer/Migrations/20240412142551_RelationshipsRevamp.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Backbone.AdminApi.Infrastructure.Database.SqlServer.Migrations +{ + /// + public partial class RelationshipsRevamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql(""" + CREATE OR ALTER VIEW RelationshipOverviews AS + SELECT + [RELATIONSHIPS].[From] AS [From], + [RELATIONSHIPS].[To] AS [To], + [RELATIONSHIPS].[RelationshipTemplateId] AS [RelationshipTemplateId], + [RELATIONSHIPS].[Status] AS [Status], + [AUDITLOG1].[CreatedAt] AS [CreatedAt], + [AUDITLOG1].[CreatedByDevice] AS [CreatedByDevice], + [AUDITLOG2].[CreatedAt] AS [AnsweredAt], + [AUDITLOG2].[CreatedByDevice] AS [AnsweredByDevice] + FROM + [Relationships].[Relationships] AS RELATIONSHIPS + LEFT JOIN + [Relationships].[RelationshipAuditLog] AS AUDITLOG1 + ON + [RELATIONSHIPS].[Id] = [AUDITLOG1].[RelationshipId] AND [AUDITLOG1].[Reason] = 0 + LEFT JOIN + [Relationships].[RelationshipAuditLog] AS AUDITLOG2 + ON + [RELATIONSHIPS].[Id] = [AUDITLOG2].[RelationshipId] AND [AUDITLOG2].[Reason] = 1 + """); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.Sql(""" + CREATE OR ALTER VIEW RelationshipOverviews AS + SELECT + [RELATIONSHIPS].[From] AS [From], + [RELATIONSHIPS].[To] AS [To], + [RELATIONSHIPS].[RelationshipTemplateId] AS [RelationshipTemplateId], + [RELATIONSHIPS].[Status] AS [Status], + [RELATIONSHIPS].[CreatedAt] AS [CreatedAt], + [RELATIONSHIPCHANGES].[Res_CreatedAt] AS [AnsweredAt], + [RELATIONSHIPCHANGES].[Req_CreatedByDevice] AS [CreatedByDevice], + [RELATIONSHIPCHANGES].[Res_CreatedByDevice] AS [AnsweredByDevice] + FROM + [Relationships].[Relationships] AS RELATIONSHIPS + LEFT JOIN + [Relationships].[RelationshipChanges] AS RELATIONSHIPCHANGES + ON + [RELATIONSHIPS].[Id] = [RELATIONSHIPCHANGES].[RelationshipId] + WHERE + [RELATIONSHIPCHANGES].[Type] = 10 + """); + } + } +} diff --git a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipChangeIdJsonConverter.cs b/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipChangeIdJsonConverter.cs deleted file mode 100644 index 069034add2..0000000000 --- a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipChangeIdJsonConverter.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; -using Backbone.BuildingBlocks.Domain; -using Backbone.Modules.Relationships.Domain.Ids; - -namespace Backbone.ConsumerApi.Mvc.JsonConverters.Relationships; - -public class RelationshipChangeIdJsonConverter : JsonConverter -{ - public override bool CanConvert(Type objectType) - { - return objectType == typeof(RelationshipChangeId); - } - - public override RelationshipChangeId Read(ref Utf8JsonReader reader, Type typeToConvert, - JsonSerializerOptions options) - { - var id = reader.GetString() ?? throw new JsonException("The id cannot be null."); - try - { - return RelationshipChangeId.Parse(id); - } - catch (InvalidIdException ex) - { - throw new JsonException(ex.Message); - } - } - - public override void Write(Utf8JsonWriter writer, RelationshipChangeId value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.StringValue); - } -} diff --git a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipIdJsonConverter.cs b/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipIdJsonConverter.cs index 4242a67510..09255f09e7 100644 --- a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipIdJsonConverter.cs +++ b/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipIdJsonConverter.cs @@ -1,7 +1,7 @@ -using System.Text.Json; +using System.Text.Json; using System.Text.Json.Serialization; using Backbone.BuildingBlocks.Domain; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; namespace Backbone.ConsumerApi.Mvc.JsonConverters.Relationships; diff --git a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipTemplateIdJsonConverter.cs b/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipTemplateIdJsonConverter.cs index 35a24e6f90..ea908b0c90 100644 --- a/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipTemplateIdJsonConverter.cs +++ b/ConsumerApi/Mvc/JsonConverters/Relationships/RelationshipTemplateIdJsonConverter.cs @@ -1,7 +1,7 @@ -using System.Text.Json; +using System.Text.Json; using System.Text.Json.Serialization; using Backbone.BuildingBlocks.Domain; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.ConsumerApi.Mvc.JsonConverters.Relationships; diff --git a/InsomniaWorkspace.json b/InsomniaWorkspace.json new file mode 100644 index 0000000000..1eb6b2a9a7 --- /dev/null +++ b/InsomniaWorkspace.json @@ -0,0 +1,263 @@ +{ + "_type": "export", + "__export_format": 4, + "__export_date": "2024-03-28T10:33:12.142Z", + "__export_source": "insomnia.desktop.app:v2023.5.8", + "resources": [ + { + "_id": "req_000de284112744048b6106914eb98cff", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615587835, + "created": 1711615540626, + "url": "{{ _.base_url }}/api/v1/RelationshipTemplates", + "name": "/api/v1/RelationshipTemplates (USRa)", + "description": "", + "method": "POST", + "body": { "mimeType": "application/json", "text": "{\n \"content\": \"ZXhhbXBsZQ==\"\n}" }, + "parameters": [], + "headers": [{ "name": "Content-Type", "disabled": false, "value": "application/json" }], + "authentication": { + "type": "oauth2", + "grantType": "password", + "authorizationUrl": "", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "username": "USRa", + "password": "a", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806878, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "wrk_09461e5e27dd4faaabb6933aa654e418", + "parentId": null, + "modified": 1711615489420, + "created": 1711614752309, + "name": "New Relationships API", + "description": "", + "scope": "collection", + "_type": "workspace" + }, + { + "_id": "req_e4e4441973f045e38c6b515aa94855fa", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615706345, + "created": 1711614806676, + "url": "{{ _.base_url }}/api/v1/Relationships", + "name": "/api/v1/Relationships (USRb)", + "description": "", + "method": "POST", + "body": { "mimeType": "application/json", "text": "{\n \"relationshipTemplateId\": \"RLTDCZMO7oVjwm1PH7h5\",\n \"creationContent\": \"ZXhhbXBsZQ==\"\n}" }, + "parameters": [], + "headers": [{ "name": "Content-Type", "disabled": false, "value": "application/json" }], + "authentication": { + "type": "oauth2", + "grantType": "password", + "authorizationUrl": "", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "username": "USRb", + "password": "b", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806778, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_97fec46007214c61866080e94bc5ced5", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615732625, + "created": 1711614806677, + "url": "{{ _.base_url }}/api/v1/Relationships/RELG9SeLgIKj8J4DG1xx/Accept", + "name": "/api/v1/Relationships/{id}/Accept", + "description": "", + "method": "PUT", + "body": {}, + "parameters": [], + "headers": [], + "authentication": { + "type": "oauth2", + "grantType": "password", + "username": "USRa", + "password": "a", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806728, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_1bd35826ed324a6e95c52e613b995be1", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615786068, + "created": 1711614806677, + "url": "{{ _.base_url }}/api/v1/Relationships/RELXWWcVgCC3RdfNNfoG/Reject", + "name": "/api/v1/Relationships/{id}/Reject", + "description": "", + "method": "PUT", + "body": {}, + "parameters": [], + "headers": [], + "authentication": { + "type": "oauth2", + "grantType": "password", + "username": "USRa", + "password": "a", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806703, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_123a5778107c46b8b21312d3f8367a92", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615743005, + "created": 1711614806678, + "url": "{{ _.base_url }}/api/v1/Relationships/RELG9SeLgIKj8J4DG1xx/Revoke", + "name": "/api/v1/Relationships/{id}/Revoke", + "description": "", + "method": "PUT", + "body": {}, + "parameters": [], + "headers": [], + "authentication": { + "type": "oauth2", + "grantType": "password", + "username": "USRb", + "password": "b", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806678, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_28d21314f8074fbfa49e7d57b751e87a", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615796615, + "created": 1711614806675, + "url": "{{ _.base_url }}/api/v1/Relationships", + "name": "/api/v1/Relationships", + "description": "", + "method": "GET", + "body": {}, + "parameters": [ + { "name": "PageNumber", "disabled": true, "value": "0", "id": "pair_8db3034a7e454b2697bf3f287e11bbf9" }, + { "name": "PageSize", "disabled": true, "value": "0", "id": "pair_a91d8a37690b43b28b7023f66c0a6c47" }, + { "name": "ids", "disabled": false, "value": "RELXWWcVgCC3RdfNNfoG", "id": "pair_2033f0941e87496e8f105e4c93d22805" } + ], + "headers": [], + "authentication": { + "type": "oauth2", + "grantType": "password", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "username": "USRa", + "password": "a", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806675, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "req_8a7c44320024424397e57cfd6fec10ce", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711615800493, + "created": 1711614806673, + "url": "{{ _.base_url }}/api/v1/Relationships/RELXWWcVgCC3RdfNNfoG", + "name": "/api/v1/Relationships/{id}", + "description": "", + "method": "GET", + "body": {}, + "parameters": [], + "headers": [], + "authentication": { + "type": "oauth2", + "grantType": "password", + "username": "USRa", + "password": "a", + "accessTokenUrl": "{{ _.base_url }}/connect/token", + "clientId": "test", + "clientSecret": "test" + }, + "metaSortKey": -1711614806673, + "isPrivate": false, + "settingStoreCookies": true, + "settingSendCookies": true, + "settingDisableRenderRequestBody": false, + "settingEncodeUrl": true, + "settingRebuildPath": true, + "settingFollowRedirects": "global", + "_type": "request" + }, + { + "_id": "env_057711fe3dac2e95034fec4771acf9fe68b588e4", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711614899758, + "created": 1711614752313, + "name": "Base Environment", + "data": { "base_url": "http://localhost:8081" }, + "dataPropertyOrder": { "&": ["base_url"] }, + "color": null, + "isPrivate": false, + "metaSortKey": 1711614752313, + "_type": "environment" + }, + { + "_id": "jar_057711fe3dac2e95034fec4771acf9fe68b588e4", + "parentId": "wrk_09461e5e27dd4faaabb6933aa654e418", + "modified": 1711614752315, + "created": 1711614752315, + "name": "Default Jar", + "cookies": [], + "_type": "cookie_jar" + } + ] +} diff --git a/Jobs/test/Job.IdentityDeletion.Tests/Tests/ActualDeletionWorkerTests.cs b/Jobs/test/Job.IdentityDeletion.Tests/Tests/ActualDeletionWorkerTests.cs index 2274292215..94a612c72d 100644 --- a/Jobs/test/Job.IdentityDeletion.Tests/Tests/ActualDeletionWorkerTests.cs +++ b/Jobs/test/Job.IdentityDeletion.Tests/Tests/ActualDeletionWorkerTests.cs @@ -5,7 +5,7 @@ using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Devices.Application.Identities.Commands.TriggerRipeDeletionProcesses; using Backbone.Modules.Relationships.Application.Relationships.Commands.FindRelationshipsOfIdentity; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Backbone.UnitTestTools.Data; using CSharpFunctionalExtensions; using FakeItEasy; diff --git a/Modules/Devices/src/Devices.AdminCli/Properties/launchSettings.json b/Modules/Devices/src/Devices.AdminCli/Properties/launchSettings.json index 82d1320fe1..c7d0aa16f1 100644 --- a/Modules/Devices/src/Devices.AdminCli/Properties/launchSettings.json +++ b/Modules/Devices/src/Devices.AdminCli/Properties/launchSettings.json @@ -1,16 +1,18 @@ { - "profiles": { - "Start": { - "commandName": "Project", - "commandLineArgs": "tier list", // enter an existing command here in order to debug it - //"commandLineArgs": "client list", // enter an existing command here in order to debug it - //"commandLineArgs": "client create --clientId test --clientSecret test --defaultTier Basic --maxIdentities 100", // enter an existing command here in order to debug it - //"commandLineArgs": "client delete test", // enter an existing command here in order to debug it - "environmentVariables": { - "Database__Provider": "SqlServer", - "Database__ConnectionString": "Server=localhost;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True;" //SqlServer - //"Database__ConnectionString": "User ID=devices;Password=Passw0rd;Server=host.docker.internal;Port=5432;Database=enmeshed;" //Postgres - } - } + "profiles": { + "Start": { + "commandName": "Project", + "commandLineArgs": "tier list", + // enter an existing command here in order to debug it + //"commandLineArgs": "client list", // enter an existing command here in order to debug it + //"commandLineArgs": "client create --clientId test --clientSecret test --defaultTier Basic --maxIdentities 100", // enter an existing command here in order to debug it + //"commandLineArgs": "client delete test", // enter an existing command here in order to debug it + "environmentVariables": { + "Database__Provider": "Postgres", + //"Database__ConnectionString": "Server=localhost;Database=enmeshed;User Id=devices;Password=Passw0rd;TrustServerCertificate=True;" //SqlServer + "Database__ConnectionString": "User ID=devices;Password=Passw0rd;Server=host.docker.internal;Port=5432;Database=enmeshed;" + //Postgres + } } + } } diff --git a/Modules/Quotas/src/Quotas.Application/Extensions/IEventBusExtensions.cs b/Modules/Quotas/src/Quotas.Application/Extensions/IEventBusExtensions.cs index 7a45ee7a2c..0462441a4c 100644 --- a/Modules/Quotas/src/Quotas.Application/Extensions/IEventBusExtensions.cs +++ b/Modules/Quotas/src/Quotas.Application/Extensions/IEventBusExtensions.cs @@ -3,8 +3,8 @@ using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.IdentityCreated; using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.MessageCreated; using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.QuotaCreatedForTier; -using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; -using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; +using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipCreated; +using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipTemplateCreated; using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.TierCreated; using Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.TierDeleted; @@ -31,8 +31,8 @@ private static void SubscribeToSynchronizationEvents(IEventBus eventBus) eventBus.Subscribe(); eventBus.Subscribe(); eventBus.Subscribe(); - eventBus.Subscribe(); - eventBus.Subscribe(); + eventBus.Subscribe(); + eventBus.Subscribe(); eventBus.Subscribe(); eventBus.Subscribe(); eventBus.Subscribe(); diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs deleted file mode 100644 index d16a7433d9..0000000000 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; - -namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; -public class RelationshipChangeCompletedIntegrationEvent : IntegrationEvent -{ - public required string ChangeId { get; set; } - public required string RelationshipId { get; set; } - public required string ChangeCreatedBy { get; set; } - public required string ChangeRecipient { get; set; } - public required string ChangeResult { get; set; } -} diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs deleted file mode 100644 index 07156bbdff..0000000000 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.Modules.Quotas.Application.Metrics; -using Backbone.Modules.Quotas.Domain.Aggregates.Metrics; - -namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; -public class RelationshipChangeCompletedIntegrationEventHandler : IIntegrationEventHandler -{ - private readonly IMetricStatusesService _metricStatusesService; - - public RelationshipChangeCompletedIntegrationEventHandler(IMetricStatusesService metricStatusesService) - { - _metricStatusesService = metricStatusesService; - } - - public async Task Handle(RelationshipChangeCompletedIntegrationEvent @event) - { - var identities = new List { @event.ChangeCreatedBy, @event.ChangeRecipient }; - var metrics = new List { MetricKey.NumberOfRelationships.Value }; - - await _metricStatusesService.RecalculateMetricStatuses(identities, metrics, CancellationToken.None); - } -} diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs deleted file mode 100644 index 969a62456f..0000000000 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; - -namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; -public class RelationshipChangeCreatedIntegrationEvent : IntegrationEvent -{ - public required string ChangeId { get; set; } - public required string RelationshipId { get; set; } - public required string ChangeCreatedBy { get; set; } - public required string ChangeRecipient { get; set; } -} - diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs new file mode 100644 index 0000000000..9d9b383dd4 --- /dev/null +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs @@ -0,0 +1,10 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; + +namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipCreated; + +public class RelationshipCreatedIntegrationEvent : IntegrationEvent +{ + public required string RelationshipId { get; set; } + public required string From { get; set; } + public required string To { get; set; } +} diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs new file mode 100644 index 0000000000..375b3d8c4f --- /dev/null +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs @@ -0,0 +1,22 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.Modules.Quotas.Application.Metrics; +using MetricKey = Backbone.Modules.Quotas.Domain.Aggregates.Metrics.MetricKey; + +namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipCreated; + +public class RelationshipCreatedIntegrationEventHandler : IIntegrationEventHandler +{ + private readonly IMetricStatusesService _metricStatusesService; + + public RelationshipCreatedIntegrationEventHandler(IMetricStatusesService metricStatusesService) + { + _metricStatusesService = metricStatusesService; + } + + public async Task Handle(RelationshipCreatedIntegrationEvent @event) + { + var affectedIdentities = new List { @event.From }; + + await _metricStatusesService.RecalculateMetricStatuses(affectedIdentities, [MetricKey.NumberOfRelationships], CancellationToken.None); + } +} diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs new file mode 100644 index 0000000000..df399f7e77 --- /dev/null +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs @@ -0,0 +1,9 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; + +namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; + +public class RelationshipStatusChangedIntegrationEvent : IntegrationEvent +{ + public required string Initiator { get; set; } + public required string Peer { get; set; } +} diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs similarity index 55% rename from Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs rename to Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs index d611585878..9afc97f6a9 100644 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs @@ -1,24 +1,23 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Quotas.Application.Metrics; using Backbone.Modules.Quotas.Domain.Aggregates.Metrics; -namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; +namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; -public class RelationshipChangeCreatedIntegrationEventHandler : IIntegrationEventHandler +public class RelationshipStatusChangedIntegrationEventHandler : IIntegrationEventHandler { private readonly IMetricStatusesService _metricStatusesService; - public RelationshipChangeCreatedIntegrationEventHandler(IMetricStatusesService metricStatusesService) + public RelationshipStatusChangedIntegrationEventHandler(IMetricStatusesService metricStatusesService) { _metricStatusesService = metricStatusesService; } - public async Task Handle(RelationshipChangeCreatedIntegrationEvent @event) + public async Task Handle(RelationshipStatusChangedIntegrationEvent @event) { - var identities = new List { @event.ChangeCreatedBy, @event.ChangeRecipient }; + var identities = new List { @event.Initiator, @event.Peer }; var metrics = new List { MetricKey.NumberOfRelationships.Value }; await _metricStatusesService.RecalculateMetricStatuses(identities, metrics, CancellationToken.None); } } - diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipTemplateCreated/RelationshipTemplateCreatedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipTemplateCreated/RelationshipTemplateCreatedIntegrationEventHandler.cs index 1c106fd069..04a8f6ab0a 100644 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipTemplateCreated/RelationshipTemplateCreatedIntegrationEventHandler.cs +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/RelationshipTemplateCreated/RelationshipTemplateCreatedIntegrationEventHandler.cs @@ -1,8 +1,9 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Quotas.Application.Metrics; using Backbone.Modules.Quotas.Domain.Aggregates.Metrics; namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.RelationshipTemplateCreated; + public class RelationshipTemplateCreatedIntegrationEventHandler : IIntegrationEventHandler { private readonly IMetricStatusesService _metricStatusesService; diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierCreated/TierCreatedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierCreated/TierCreatedIntegrationEventHandler.cs index 5b2e53db24..5da15385e1 100644 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierCreated/TierCreatedIntegrationEventHandler.cs +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierCreated/TierCreatedIntegrationEventHandler.cs @@ -1,9 +1,10 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Quotas.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Quotas.Domain.Aggregates.Tiers; using Microsoft.Extensions.Logging; namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.TierCreated; + public class TierCreatedIntegrationEventHandler : IIntegrationEventHandler { private readonly ITiersRepository _tiersRepository; diff --git a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierOfIdentityChanged/TierOfIdentityChangedIntegrationEventHandler.cs b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierOfIdentityChanged/TierOfIdentityChangedIntegrationEventHandler.cs index 158d4fc073..9e8d51c3bb 100644 --- a/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierOfIdentityChanged/TierOfIdentityChangedIntegrationEventHandler.cs +++ b/Modules/Quotas/src/Quotas.Application/IntegrationEvents/Incoming/TierOfIdentityChanged/TierOfIdentityChangedIntegrationEventHandler.cs @@ -1,4 +1,4 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; +using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Quotas.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Quotas.Domain.Aggregates.Identities; @@ -6,6 +6,7 @@ using Backbone.Modules.Quotas.Domain.Metrics; namespace Backbone.Modules.Quotas.Application.IntegrationEvents.Incoming.TierOfIdentityChanged; + public class TierOfIdentityChangedIntegrationEventHandler : IIntegrationEventHandler { private readonly IIdentitiesRepository _identitiesRepository; diff --git a/Modules/Relationships/src/Relationships.Application/ApplicationErrors.cs b/Modules/Relationships/src/Relationships.Application/ApplicationErrors.cs index 6aefb44e98..7a61fb769f 100644 --- a/Modules/Relationships/src/Relationships.Application/ApplicationErrors.cs +++ b/Modules/Relationships/src/Relationships.Application/ApplicationErrors.cs @@ -1,21 +1,3 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; - namespace Backbone.Modules.Relationships.Application; -public static class ApplicationErrors -{ - public static class Relationship - { - public static ApplicationError RelationshipToTargetAlreadyExists(string targetIdentity = "") - { - var targetIdentityString = string.IsNullOrEmpty(targetIdentity) ? "the target identity" : targetIdentity; - - return new ApplicationError("error.platform.validation.relationshipRequest.relationshipToTargetAlreadyExists", $"A relationship to {targetIdentityString} already exists."); - } - - public static ApplicationError CannotSendRelationshipRequestToYourself() - { - return new ApplicationError("error.platform.validation.relationshipRequest.cannotSendRelationshipRequestToYourself", "The template you provided is your own. You cannot send a relationship request to yourself."); - } - } -} +public static class ApplicationErrors; diff --git a/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipTemplatesRepository.cs b/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipTemplatesRepository.cs index 195f77a8d0..0f17f37782 100644 --- a/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipTemplatesRepository.cs +++ b/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipTemplatesRepository.cs @@ -2,14 +2,16 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Persistence.Database; using Backbone.BuildingBlocks.Application.Pagination; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; + public interface IRelationshipTemplatesRepository { - Task> FindTemplatesWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, CancellationToken cancellationToken, bool track = false); - Task Find(RelationshipTemplateId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false, bool fillContent = true); + Task> FindTemplatesWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, + CancellationToken cancellationToken, bool track = false); + + Task Find(RelationshipTemplateId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false); Task Add(RelationshipTemplate template, CancellationToken cancellationToken); Task Update(RelationshipTemplate template); Task Delete(Expression> filter, CancellationToken cancellationToken); diff --git a/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipsRepository.cs b/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipsRepository.cs index 5f70913f22..8217ced768 100644 --- a/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipsRepository.cs +++ b/Modules/Relationships/src/Relationships.Application/Infrastructure/Persistence/Repository/IRelationshipsRepository.cs @@ -2,20 +2,17 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Persistence.Database; using Backbone.BuildingBlocks.Application.Pagination; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; public interface IRelationshipsRepository { - Task> FindRelationshipsWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, CancellationToken cancellationToken, bool track = false); - Task> FindChangesWithIds(IEnumerable ids, RelationshipChangeType? relationshipChangeType, - RelationshipChangeStatus? relationshipChangeStatus, OptionalDateRange? modifiedAt, OptionalDateRange? createdAt, OptionalDateRange? completedAt, IdentityAddress? createdBy, - IdentityAddress? completedBy, IdentityAddress activeIdentity, PaginationFilter paginationFilter, CancellationToken cancellationToken, bool onlyPeerChanges = false, bool track = false); + Task> FindRelationshipsWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, + CancellationToken cancellationToken, bool track = false); + Task FindRelationship(RelationshipId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false); - Task FindRelationshipChange(RelationshipChangeId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false); Task Add(Relationship relationship, CancellationToken cancellationToken); Task Update(Relationship relationship); Task> FindRelationships(Expression> filter, CancellationToken cancellationToken); diff --git a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCompletedIntegrationEvent.cs b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCompletedIntegrationEvent.cs deleted file mode 100644 index 7f66525547..0000000000 --- a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCompletedIntegrationEvent.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; -using Backbone.Modules.Relationships.Domain.Entities; - -namespace Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; - -public class RelationshipChangeCompletedIntegrationEvent : IntegrationEvent -{ - public RelationshipChangeCompletedIntegrationEvent(RelationshipChange change) : base($"{change.Id}/Completed") - { - ChangeId = change.Id; - RelationshipId = change.RelationshipId; - ChangeCreatedBy = change.Request.CreatedBy; - ChangeRecipient = change.Request.CreatedBy == change.Relationship.From ? change.Relationship.To : change.Relationship.From; - ChangeResult = MapStatusToResult(change.Status); - } - - public string ChangeId { get; } - public string RelationshipId { get; } - public string ChangeCreatedBy { get; } - public string ChangeRecipient { get; } - public string ChangeResult { get; } - - private static string MapStatusToResult(RelationshipChangeStatus status) - { - return status switch - { - RelationshipChangeStatus.Accepted => "Accepted", - RelationshipChangeStatus.Rejected => "Rejected", - RelationshipChangeStatus.Revoked => "Revoked", - _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) - }; - } -} diff --git a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCreatedIntegrationEvent.cs b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCreatedIntegrationEvent.cs deleted file mode 100644 index 16459a3a50..0000000000 --- a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipChangeCreatedIntegrationEvent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; -using Backbone.Modules.Relationships.Domain.Entities; - -namespace Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; -public class RelationshipChangeCreatedIntegrationEvent : IntegrationEvent -{ - public RelationshipChangeCreatedIntegrationEvent(RelationshipChange change) : base($"{change.Id}/Created") - { - ChangeId = change.Id; - RelationshipId = change.RelationshipId; - ChangeCreatedBy = change.Request.CreatedBy; - ChangeRecipient = change.Request.CreatedBy == change.Relationship.From ? change.Relationship.To : change.Relationship.From; - } - - public string ChangeId { get; } - public string RelationshipId { get; } - public string ChangeCreatedBy { get; } - public string ChangeRecipient { get; } -} diff --git a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipCreatedIntegrationEvent.cs b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipCreatedIntegrationEvent.cs new file mode 100644 index 0000000000..d2138c3dd3 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipCreatedIntegrationEvent.cs @@ -0,0 +1,18 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; + +public class RelationshipCreatedIntegrationEvent : IntegrationEvent +{ + public RelationshipCreatedIntegrationEvent(Relationship relationship) : base($"{relationship.Id}/Created") + { + RelationshipId = relationship.Id; + From = relationship.From; + To = relationship.To; + } + + public string RelationshipId { get; set; } + public string From { get; } + public string To { get; } +} diff --git a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipStatusChangedIntegrationEvent.cs b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipStatusChangedIntegrationEvent.cs new file mode 100644 index 0000000000..0092471b24 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipStatusChangedIntegrationEvent.cs @@ -0,0 +1,22 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Tooling.Extensions; + +namespace Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; + +public class RelationshipStatusChangedIntegrationEvent : IntegrationEvent +{ + public RelationshipStatusChangedIntegrationEvent(Relationship relationship) : base($"{relationship.Id}/StatusChanged/{relationship.AuditLog.Last().CreatedAt.ToUniversalString()}") + { + RelationshipId = relationship.Id; + Status = relationship.Status.ToDtoString(); + Initiator = relationship.LastModifiedBy; + Peer = relationship.LastModifiedBy == relationship.From ? relationship.To : relationship.From; + } + + public string RelationshipId { get; set; } + public string Status { get; set; } + public string Initiator { get; set; } + public string Peer { get; set; } +} diff --git a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipTemplateCreatedIntegrationEvent.cs b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipTemplateCreatedIntegrationEvent.cs index 1343137db9..d651cdbd5a 100644 --- a/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipTemplateCreatedIntegrationEvent.cs +++ b/Modules/Relationships/src/Relationships.Application/IntegrationEvents/Outgoing/RelationshipTemplateCreatedIntegrationEvent.cs @@ -1,7 +1,8 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; + public class RelationshipTemplateCreatedIntegrationEvent : IntegrationEvent { public RelationshipTemplateCreatedIntegrationEvent(RelationshipTemplate template) : base($"{template.Id}/Created") diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/Handler.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/Handler.cs index 2b94f8522b..153d79871e 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/Handler.cs @@ -1,5 +1,5 @@ using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity; diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateCommand.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateCommand.cs index 42d2284f8b..883788a994 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateCommand.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateCommand.cs @@ -1,6 +1,6 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; using Backbone.BuildingBlocks.Application.Attributes; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateResponse.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateResponse.cs index b3b7249283..3eaee098df 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateResponse.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/CreateRelationshipTemplateResponse.cs @@ -1,6 +1,5 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; 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 b420239a10..45b3b02309 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/CreateRelationshipTemplate/Handler.cs @@ -3,7 +3,7 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/DeleteRelationshipTemplatesOfIdentity/Handler.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/DeleteRelationshipTemplatesOfIdentity/Handler.cs index 75a24f4720..4b5b3456d8 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/DeleteRelationshipTemplatesOfIdentity/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Commands/DeleteRelationshipTemplatesOfIdentity/Handler.cs @@ -1,5 +1,5 @@ using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.DeleteRelationshipTemplatesOfIdentity; diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/GetRelationshipTemplateQuery.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/GetRelationshipTemplateQuery.cs index f81263697d..c617f6f7f5 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/GetRelationshipTemplateQuery.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/GetRelationshipTemplateQuery.cs @@ -1,5 +1,5 @@ -using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.GetRelationshipTemplate; diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/Handler.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/Handler.cs index 345b140488..101e57e8fa 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/GetRelationshipTemplate/Handler.cs @@ -1,7 +1,9 @@ using AutoMapper; +using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.GetRelationshipTemplate; @@ -21,7 +23,7 @@ public Handler(IUserContext userContext, IMapper mapper, IRelationshipTemplatesR public async Task Handle(GetRelationshipTemplateQuery request, CancellationToken cancellationToken) { - var template = await _relationshipTemplatesRepository.Find(request.Id, _userContext.GetAddress(), cancellationToken, track: true); + var template = await _relationshipTemplatesRepository.Find(request.Id, _userContext.GetAddress(), cancellationToken, track: true) ?? throw new NotFoundException(nameof(RelationshipTemplate)); template.AllocateFor(_userContext.GetAddress(), _userContext.GetDeviceId()); diff --git a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesQuery.cs b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesQuery.cs index efee4f877b..bcd00bbaf2 100644 --- a/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesQuery.cs +++ b/Modules/Relationships/src/Relationships.Application/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesQuery.cs @@ -1,5 +1,5 @@ using Backbone.BuildingBlocks.Application.Pagination; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.ListRelationshipTemplates; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipCommand.cs new file mode 100644 index 0000000000..6550b840ce --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipCommand.cs @@ -0,0 +1,9 @@ +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationship; + +public class AcceptRelationshipCommand : IRequest +{ + public required string RelationshipId { get; set; } + public byte[]? AcceptanceContent { get; set; } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipResponse.cs new file mode 100644 index 0000000000..2da15def8b --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/AcceptRelationshipResponse.cs @@ -0,0 +1,11 @@ +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationship; + +public class AcceptRelationshipResponse : RelationshipMetadataDTO +{ + public AcceptRelationshipResponse(Relationship relationship) : base(relationship) + { + } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/Handler.cs new file mode 100644 index 0000000000..a08b682b8a --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationship/Handler.cs @@ -0,0 +1,39 @@ +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.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationship; + +public class Handler : IRequestHandler +{ + private readonly IRelationshipsRepository _relationshipsRepository; + private readonly IEventBus _eventBus; + private readonly IdentityAddress _activeIdentity; + private readonly DeviceId _activeDevice; + + public Handler(IRelationshipsRepository relationshipsRepository, IUserContext userContext, IEventBus eventBus) + { + _relationshipsRepository = relationshipsRepository; + _eventBus = eventBus; + _activeIdentity = userContext.GetAddress(); + _activeDevice = userContext.GetDeviceId(); + } + + public async Task Handle(AcceptRelationshipCommand request, CancellationToken cancellationToken) + { + var relationshipId = RelationshipId.Parse(request.RelationshipId); + var relationship = await _relationshipsRepository.FindRelationship(relationshipId, _activeIdentity, cancellationToken, track: true); + + relationship.Accept(_activeIdentity, _activeDevice, request.AcceptanceContent); + + await _relationshipsRepository.Update(relationship); + + _eventBus.Publish(new RelationshipStatusChangedIntegrationEvent(relationship)); + + return new AcceptRelationshipResponse(relationship); + } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommand.cs deleted file mode 100644 index 52b50b9df9..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Ids; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationshipChangeRequest; - -public class AcceptRelationshipChangeRequestCommand : IRequest -{ - public required RelationshipId Id { get; set; } - public required RelationshipChangeId ChangeId { get; set; } - public byte[]? ResponseContent { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommandValidator.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommandValidator.cs deleted file mode 100644 index 10738b4f49..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestCommandValidator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Backbone.BuildingBlocks.Application.FluentValidation; -using Backbone.Tooling.Extensions; -using FluentValidation; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationshipChangeRequest; - -// ReSharper disable once UnusedMember.Global -public class AcceptRelationshipChangeRequestCommandValidator : AbstractValidator -{ - public AcceptRelationshipChangeRequestCommandValidator() - { - RuleFor(c => c.Id).DetailedNotNull(); - RuleFor(c => c.ResponseContent).NumberOfBytes(0, 10.Mebibytes()); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestResponse.cs deleted file mode 100644 index 880e5b8aae..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/AcceptRelationshipChangeRequestResponse.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Backbone.Modules.Relationships.Application.Relationships.DTOs; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationshipChangeRequest; - -public class AcceptRelationshipChangeRequestResponse : RelationshipMetadataDTO; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs deleted file mode 100644 index c7f7875e61..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/AcceptRelationshipChangeRequest/Handler.cs +++ /dev/null @@ -1,46 +0,0 @@ -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.Application.IntegrationEvents.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) - { - _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); - - await _relationshipsRepository.Update(relationship); - - PublishIntegrationEvent(change); - - var response = _mapper.Map(relationship); - - return response; - } - - private void PublishIntegrationEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedIntegrationEvent(change); - _eventBus.Publish(evt); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipCommand.cs index d2aad49130..deddcf98e1 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipCommand.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipCommand.cs @@ -1,5 +1,4 @@ using Backbone.BuildingBlocks.Application.Attributes; -using Backbone.Modules.Relationships.Domain.Ids; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.CreateRelationship; @@ -7,6 +6,6 @@ namespace Backbone.Modules.Relationships.Application.Relationships.Commands.Crea [ApplyQuotasForMetrics("NumberOfRelationships")] public class CreateRelationshipCommand : IRequest { - public required RelationshipTemplateId RelationshipTemplateId { get; set; } - public byte[]? Content { get; set; } + public required string RelationshipTemplateId { get; set; } + public byte[]? CreationContent { get; set; } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipRequestValidator.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipRequestValidator.cs index efc5cdfda1..d75b9eeed2 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipRequestValidator.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipRequestValidator.cs @@ -10,6 +10,6 @@ public class CreateRelationshipCommandValidator : AbstractValidator c.RelationshipTemplateId).DetailedNotEmpty(); - RuleFor(c => c.Content).NumberOfBytes(0, 10.Mebibytes()); + RuleFor(c => c.CreationContent).NumberOfBytes(0, 10.Mebibytes()); } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipResponse.cs index 1e83a29192..35cb6f5a5e 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipResponse.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/CreateRelationshipResponse.cs @@ -1,5 +1,11 @@ using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.CreateRelationship; -public class CreateRelationshipResponse : RelationshipMetadataDTO; +public class CreateRelationshipResponse : RelationshipMetadataDTO +{ + public CreateRelationshipResponse(Relationship relationship) : base(relationship) + { + } +} 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 24b9b04700..a9e8a30f7c 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/CreateRelationship/Handler.cs @@ -1,10 +1,11 @@ -using AutoMapper; using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; 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.IntegrationEvents.Outgoing; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.CreateRelationship; @@ -12,19 +13,20 @@ 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; - private readonly IUserContext _userContext; + private readonly IdentityAddress _activeIdentity; + private readonly DeviceId _activeDevice; + private CancellationToken _cancellationToken; private CreateRelationshipCommand _request; private RelationshipTemplate _template; private Relationship _relationship; - public Handler(IUserContext userContext, IMapper mapper, IEventBus eventBus, IRelationshipsRepository relationshipsRepository, IRelationshipTemplatesRepository relationshipTemplatesRepository) + public Handler(IUserContext userContext, IEventBus eventBus, IRelationshipsRepository relationshipsRepository, IRelationshipTemplatesRepository relationshipTemplatesRepository) { - _userContext = userContext; - _mapper = mapper; + _activeIdentity = userContext.GetAddress(); + _activeDevice = userContext.GetDeviceId(); _relationshipsRepository = relationshipsRepository; _relationshipTemplatesRepository = relationshipTemplatesRepository; _eventBus = eventBus; @@ -40,58 +42,42 @@ public async Task Handle(CreateRelationshipCommand r _request = request; await ReadTemplateFromDb(); - await EnsureRelationshipCanBeEstablished(); await CreateAndSaveRelationship(); PublishIntegrationEvent(); - return CreateResponse(); + return new CreateRelationshipResponse(_relationship); } private async Task ReadTemplateFromDb() { - _template = await _relationshipTemplatesRepository.Find(_request.RelationshipTemplateId, _userContext.GetAddress(), _cancellationToken, track: true, fillContent: false); - } - - private async Task EnsureRelationshipCanBeEstablished() - { - EnsureActiveIdentityIsNotTemplateOwner(); - await EnsureThereIsNoExistingRelationshipBetweenActiveIdentityAndTemplateOwner(); - } - - private void EnsureActiveIdentityIsNotTemplateOwner() - { - if (_template.CreatedBy == _userContext.GetAddress()) - throw new OperationFailedException(ApplicationErrors.Relationship.CannotSendRelationshipRequestToYourself()); - } - - private async Task EnsureThereIsNoExistingRelationshipBetweenActiveIdentityAndTemplateOwner() - { - var relationshipExists = await _relationshipsRepository.RelationshipBetweenTwoIdentitiesExists(_userContext.GetAddress(), _template.CreatedBy, _cancellationToken); + var templateId = RelationshipTemplateId.Parse(_request.RelationshipTemplateId); - if (relationshipExists) - throw new OperationFailedException(ApplicationErrors.Relationship.RelationshipToTargetAlreadyExists(_template.CreatedBy)); + _template = await _relationshipTemplatesRepository.Find(templateId, _activeIdentity, _cancellationToken, track: true) ?? + throw new NotFoundException(nameof(RelationshipTemplate)); } private async Task CreateAndSaveRelationship() { + var existingRelationships = await _relationshipsRepository.FindRelationships( + r => + (r.From == _activeIdentity && r.To == _template.CreatedBy) || + (r.From == _template.CreatedBy && r.To == _activeIdentity), + _cancellationToken + ); + _relationship = new Relationship( _template, - _userContext.GetAddress(), - _userContext.GetDeviceId(), - _request.Content); + _activeIdentity, + _activeDevice, + _request.CreationContent, + existingRelationships.ToList() + ); await _relationshipsRepository.Add(_relationship, _cancellationToken); } private void PublishIntegrationEvent() { - var change = _relationship.Changes.First(); // there is always one change, because the relationship was just created - var evt = new RelationshipChangeCreatedIntegrationEvent(change); - _eventBus.Publish(evt); - } - - private CreateRelationshipResponse CreateResponse() - { - return _mapper.Map(_relationship); + _eventBus.Publish(new RelationshipCreatedIntegrationEvent(_relationship)); } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/DeleteRelationshipsOfIdentity/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/DeleteRelationshipsOfIdentity/Handler.cs index 582899be43..101abd7a8b 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/DeleteRelationshipsOfIdentity/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/DeleteRelationshipsOfIdentity/Handler.cs @@ -1,5 +1,5 @@ using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.DeleteRelationshipsOfIdentity; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/DeleteRelationshipsOfIdentityResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/DeleteRelationshipsOfIdentityResponse.cs index f18844dc52..38d4d5b04d 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/DeleteRelationshipsOfIdentityResponse.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/DeleteRelationshipsOfIdentityResponse.cs @@ -1,5 +1,5 @@ using Backbone.BuildingBlocks.Application.CQRS.BaseClasses; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.FindRelationshipsOfIdentity; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/Handler.cs index a8e78aacf1..9fe6e90a00 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/Handler.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/FindRelationshipsOfIdentity/Handler.cs @@ -1,5 +1,5 @@ using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Commands.FindRelationshipsOfIdentity; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/Handler.cs new file mode 100644 index 0000000000..2b6f38f1ee --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/Handler.cs @@ -0,0 +1,42 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; +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.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationship; + +public class Handler : IRequestHandler +{ + private readonly IRelationshipsRepository _relationshipsRepository; + private readonly IEventBus _eventBus; + private readonly DeviceId _activeDevice; + private readonly IdentityAddress _activeIdentity; + + public Handler(IRelationshipsRepository relationshipsRepository, IUserContext userContext, IEventBus eventBus) + { + _relationshipsRepository = relationshipsRepository; + _eventBus = eventBus; + _activeIdentity = userContext.GetAddress(); + _activeDevice = userContext.GetDeviceId(); + } + + public async Task Handle(RejectRelationshipCommand request, CancellationToken cancellationToken) + { + var relationshipId = RelationshipId.Parse(request.RelationshipId); + + var relationship = await _relationshipsRepository.FindRelationship(relationshipId, _activeIdentity, cancellationToken, track: true) ?? + throw new NotFoundException(nameof(Relationship)); + + relationship.Reject(_activeIdentity, _activeDevice); + + await _relationshipsRepository.Update(relationship); + + _eventBus.Publish(new RelationshipStatusChangedIntegrationEvent(relationship)); + + return new RejectRelationshipResponse(relationship); + } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipCommand.cs new file mode 100644 index 0000000000..cd0577d8a2 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipCommand.cs @@ -0,0 +1,8 @@ +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationship; + +public class RejectRelationshipCommand : IRequest +{ + public required string RelationshipId { get; set; } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipResponse.cs new file mode 100644 index 0000000000..9a8b24a99e --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationship/RejectRelationshipResponse.cs @@ -0,0 +1,11 @@ +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationship; + +public class RejectRelationshipResponse : RelationshipMetadataDTO +{ + public RejectRelationshipResponse(Relationship relationship) : base(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 deleted file mode 100644 index c894cba6d1..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/Handler.cs +++ /dev/null @@ -1,46 +0,0 @@ -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.Application.IntegrationEvents.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) - { - _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); - - await _relationshipsRepository.Update(relationship); - - PublishIntegrationEvent(change); - - var response = _mapper.Map(relationship); - - return response; - } - - private void PublishIntegrationEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedIntegrationEvent(change); - _eventBus.Publish(evt); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommand.cs deleted file mode 100644 index 6498b60d9f..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Ids; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationshipChangeRequest; - -public class RejectRelationshipChangeRequestCommand : IRequest -{ - public required RelationshipId Id { get; set; } - public required RelationshipChangeId ChangeId { get; set; } - public byte[]? ResponseContent { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommandValidator.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommandValidator.cs deleted file mode 100644 index 620e69dc26..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestCommandValidator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Backbone.BuildingBlocks.Application.FluentValidation; -using Backbone.Tooling.Extensions; -using FluentValidation; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationshipChangeRequest; - -// ReSharper disable once UnusedMember.Global -public class RejectRelationshipChangeRequestCommandValidator : AbstractValidator -{ - public RejectRelationshipChangeRequestCommandValidator() - { - RuleFor(c => c.Id).DetailedNotNull(); - RuleFor(c => c.ResponseContent).NumberOfBytes(0, 10.Mebibytes()); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestResponse.cs deleted file mode 100644 index baed444dd9..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RejectRelationshipChangeRequest/RejectRelationshipChangeRequestResponse.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Backbone.Modules.Relationships.Application.Relationships.DTOs; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationshipChangeRequest; - -public class RejectRelationshipChangeRequestResponse : RelationshipMetadataDTO; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/Handler.cs new file mode 100644 index 0000000000..1f1813be96 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/Handler.cs @@ -0,0 +1,39 @@ +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.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationship; + +public class Handler : IRequestHandler +{ + private readonly IRelationshipsRepository _relationshipsRepository; + private readonly IEventBus _eventBus; + private readonly IdentityAddress _activeIdentity; + private readonly DeviceId _activeDevice; + + public Handler(IRelationshipsRepository relationshipsRepository, IUserContext userContext, IEventBus eventBus) + { + _relationshipsRepository = relationshipsRepository; + _eventBus = eventBus; + _activeIdentity = userContext.GetAddress(); + _activeDevice = userContext.GetDeviceId(); + } + + public async Task Handle(RevokeRelationshipCommand request, CancellationToken cancellationToken) + { + var relationshipId = RelationshipId.Parse(request.RelationshipId); + var relationship = await _relationshipsRepository.FindRelationship(relationshipId, _activeIdentity, cancellationToken, track: true); + + relationship.Revoke(_activeIdentity, _activeDevice); + + await _relationshipsRepository.Update(relationship); + + _eventBus.Publish(new RelationshipStatusChangedIntegrationEvent(relationship)); + + return new RevokeRelationshipResponse(relationship); + } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipCommand.cs new file mode 100644 index 0000000000..32241f9acc --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipCommand.cs @@ -0,0 +1,8 @@ +using MediatR; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationship; + +public class RevokeRelationshipCommand : IRequest +{ + public required string RelationshipId { get; set; } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipResponse.cs new file mode 100644 index 0000000000..3ba4766c0d --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationship/RevokeRelationshipResponse.cs @@ -0,0 +1,11 @@ +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationship; + +public class RevokeRelationshipResponse : RelationshipMetadataDTO +{ + public RevokeRelationshipResponse(Relationship relationship) : base(relationship) + { + } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs deleted file mode 100644 index ccc9b7b64e..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/Handler.cs +++ /dev/null @@ -1,46 +0,0 @@ -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.Application.IntegrationEvents.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) - { - _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); - - await _relationshipsRepository.Update(relationship); - - PublishIntegrationEvent(change); - - var response = _mapper.Map(relationship); - - return response; - } - - private void PublishIntegrationEvent(RelationshipChange change) - { - var evt = new RelationshipChangeCompletedIntegrationEvent(change); - _eventBus.Publish(evt); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommand.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommand.cs deleted file mode 100644 index 5f0741fe5e..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommand.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Ids; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipChangeRequest; - -public class RevokeRelationshipChangeRequestCommand : IRequest -{ - public required RelationshipId Id { get; set; } - public required RelationshipChangeId ChangeId { get; set; } - public byte[]? ResponseContent { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommandValidator.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommandValidator.cs deleted file mode 100644 index 5d85ff57b5..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestCommandValidator.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Backbone.BuildingBlocks.Application.FluentValidation; -using Backbone.Tooling.Extensions; -using FluentValidation; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipChangeRequest; - -// ReSharper disable once UnusedMember.Global -public class RevokeRelationshipChangeRequestCommandValidator : AbstractValidator -{ - public RevokeRelationshipChangeRequestCommandValidator() - { - RuleFor(c => c.Id).DetailedNotNull(); - RuleFor(c => c.ResponseContent).NumberOfBytes(0, 10.Mebibytes()); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestResponse.cs deleted file mode 100644 index a0eceefa8f..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Commands/RevokeRelationshipChangeRequest/RevokeRelationshipChangeRequestResponse.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Backbone.Modules.Relationships.Application.Relationships.DTOs; - -namespace Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipChangeRequest; - -public class RevokeRelationshipChangeRequestResponse : RelationshipMetadataDTO; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipAuditLogEntryDTO.cs b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipAuditLogEntryDTO.cs new file mode 100644 index 0000000000..79bbcccdee --- /dev/null +++ b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipAuditLogEntryDTO.cs @@ -0,0 +1,35 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Application.Relationships.DTOs; + +public class RelationshipAuditLogEntryDTO : IMapTo +{ + // This constructor is only used by AutoMapper. + // ReSharper disable once UnusedMember.Local + private RelationshipAuditLogEntryDTO() + { + CreatedBy = null!; + CreatedByDevice = null!; + Reason = null!; + NewStatus = null!; + } + + public RelationshipAuditLogEntryDTO(RelationshipAuditLogEntry entry) + { + CreatedAt = entry.CreatedAt; + CreatedBy = entry.CreatedBy; + CreatedByDevice = entry.CreatedByDevice; + Reason = entry.Reason.ToString(); + OldStatus = entry.OldStatus.ToDtoString(); + NewStatus = entry.NewStatus.ToDtoString(); + } + + public DateTime CreatedAt { get; set; } + public string CreatedBy { get; set; } + public string CreatedByDevice { get; set; } + public string Reason { get; set; } + + public string? OldStatus { get; set; } + public string NewStatus { get; set; } +} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipChangeDTO.cs b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipChangeDTO.cs deleted file mode 100644 index 6b992d031d..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipChangeDTO.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; - -namespace Backbone.Modules.Relationships.Application.Relationships.DTOs; - -public class RelationshipChangeDTO : IMapTo -{ - public required RelationshipChangeId Id { get; set; } - - public required RelationshipId RelationshipId { get; set; } - - public required RelationshipChangeRequestDTO Request { get; set; } - public required RelationshipChangeResponseDTO? Response { get; set; } - - public required RelationshipChangeType Type { get; set; } - - public required RelationshipChangeStatus Status { get; set; } -} - -public class RelationshipChangeRequestDTO : IMapTo -{ - public required DateTime CreatedAt { get; set; } - public required IdentityAddress CreatedBy { get; set; } - public required DeviceId CreatedByDevice { get; set; } - public required byte[]? Content { get; set; } -} - -public class RelationshipChangeResponseDTO : IMapTo -{ - public required DateTime CreatedAt { get; set; } - public required IdentityAddress CreatedBy { get; set; } - public required DeviceId CreatedByDevice { get; set; } - public required byte[]? Content { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipDTO.cs b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipDTO.cs index 4096d830cd..f606deed07 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipDTO.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipDTO.cs @@ -1,7 +1,7 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.Relationships.DTOs; @@ -12,9 +12,13 @@ public class RelationshipDTO : IMapTo public required IdentityAddress From { get; set; } public required IdentityAddress To { get; set; } - public required IEnumerable Changes { get; set; } + + public required byte[]? CreationContent { get; set; } + public required byte[]? AcceptanceContent { get; set; } public required DateTime CreatedAt { get; set; } public required RelationshipStatus Status { get; set; } + + public required List AuditLog { get; set; } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipMetadataDTO.cs b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipMetadataDTO.cs index 665bff1faa..784711fffe 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipMetadataDTO.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipMetadataDTO.cs @@ -1,48 +1,56 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.Relationships.DTOs; -public class RelationshipMetadataDTO : IMapTo +public class RelationshipMetadataDTO { - public required RelationshipId Id { get; set; } - public required RelationshipTemplateId RelationshipTemplateId { get; set; } + public RelationshipMetadataDTO(Relationship relationship) + { + Id = relationship.Id; + RelationshipTemplateId = relationship.RelationshipTemplateId; + From = relationship.From; + To = relationship.To; + CreatedAt = relationship.CreatedAt; + Status = relationship.Status; + AuditLog = relationship.AuditLog.Select(a => new RelationshipAuditLogEntryDTO(a)).ToList(); + } - public required IdentityAddress From { get; set; } - public required IdentityAddress To { get; set; } - public required IEnumerable Changes { get; set; } + public RelationshipId Id { get; set; } + public RelationshipTemplateId RelationshipTemplateId { get; set; } - public required DateTime CreatedAt { get; set; } + public IdentityAddress From { get; set; } + public IdentityAddress To { get; set; } - public RelationshipStatus Status { get; set; } -} - -public class RelationshipChangeMetadataDTO : IMapTo -{ - public required RelationshipChangeId Id { get; set; } - - public required RelationshipId RelationshipId { get; set; } + public DateTime CreatedAt { get; set; } - public required RelationshipChangeRequestMetadataDTO Request { get; set; } - public required RelationshipChangeResponseMetadataDTO? Response { get; set; } - - public required RelationshipChangeType Type { get; set; } - - public required RelationshipChangeStatus Status { get; set; } -} + public RelationshipStatus Status { get; set; } -public class RelationshipChangeRequestMetadataDTO : IMapTo -{ - public required DateTime CreatedAt { get; set; } - public required IdentityAddress CreatedBy { get; set; } - public required DeviceId CreatedByDevice { get; set; } + public List AuditLog { get; set; } } -public class RelationshipChangeResponseMetadataDTO : IMapTo +public static class RelationshipStatusExtensions { - public required DateTime CreatedAt { get; set; } - public required IdentityAddress CreatedBy { get; set; } - public required DeviceId CreatedByDevice { get; set; } + public static string ToDtoString(this RelationshipStatus status) + { + return status.ToDtoStringInternal(); + } + + public static string? ToDtoString(this RelationshipStatus? status) + { + return status?.ToDtoStringInternal(); + } + + private static string ToDtoStringInternal(this RelationshipStatus status) + { + return status switch + { + RelationshipStatus.Pending => "Pending", + RelationshipStatus.Active => "Active", + RelationshipStatus.Rejected => "Rejected", + RelationshipStatus.Revoked => "Revoked", + _ => throw new ArgumentOutOfRangeException(nameof(status), status, null) + }; + } } diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipTemplateDTO.cs b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipTemplateDTO.cs index f148722fc3..e15dee4089 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipTemplateDTO.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/DTOs/RelationshipTemplateDTO.cs @@ -1,7 +1,6 @@ using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Mapping; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; namespace Backbone.Modules.Relationships.Application.Relationships.DTOs; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/GetChangeQuery.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/GetChangeQuery.cs deleted file mode 100644 index ac25005fd4..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/GetChangeQuery.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using Backbone.Modules.Relationships.Domain.Ids; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.GetChange; - -public class GetChangeQuery : IRequest -{ - public required RelationshipChangeId Id { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/Handler.cs deleted file mode 100644 index abea442e70..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetChange/Handler.cs +++ /dev/null @@ -1,28 +0,0 @@ -using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; -using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.GetChange; - -public class Handler : IRequestHandler -{ - private readonly IMapper _mapper; - private readonly IUserContext _userContext; - private readonly IRelationshipsRepository _relationshipsRepository; - - public Handler(IUserContext userContext, IMapper mapper, IRelationshipsRepository relationshipsRepository) - { - _userContext = userContext; - _mapper = mapper; - _relationshipsRepository = relationshipsRepository; - } - - public async Task Handle(GetChangeQuery query, CancellationToken cancellationToken) - { - var change = await _relationshipsRepository.FindRelationshipChange(query.Id, _userContext.GetAddress(), cancellationToken, track: false); - - return _mapper.Map(change); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetRelationship/GetRelationshipQuery.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetRelationship/GetRelationshipQuery.cs index f8005d391d..bfa2043b59 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetRelationship/GetRelationshipQuery.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/GetRelationship/GetRelationshipQuery.cs @@ -1,5 +1,5 @@ using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Queries.GetRelationship; diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/Handler.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/Handler.cs deleted file mode 100644 index 4fd646ad33..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/Handler.cs +++ /dev/null @@ -1,28 +0,0 @@ -using AutoMapper; -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.UserContext; -using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.ListChanges; - -public class Handler : IRequestHandler -{ - private readonly IMapper _mapper; - private readonly IRelationshipsRepository _relationshipsRepository; - private readonly IUserContext _userContext; - - public Handler(IUserContext userContext, IMapper mapper, IRelationshipsRepository relationshipsRepository) - { - _mapper = mapper; - _relationshipsRepository = relationshipsRepository; - _userContext = userContext; - } - - public async Task Handle(ListChangesQuery request, CancellationToken cancellationToken) - { - var dbPaginationResult = await _relationshipsRepository.FindChangesWithIds(request.Ids, request.Type, request.Status, request.ModifiedAt, request.CreatedAt, request.CompletedAt, request.CreatedBy, request.CompletedBy, _userContext.GetAddress(), request.PaginationFilter, cancellationToken, track: false); - - return new ListChangesResponse(_mapper.Map(dbPaginationResult.ItemsOnPage), request.PaginationFilter, dbPaginationResult.TotalNumberOfItems); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQuery.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQuery.cs deleted file mode 100644 index b6bb056422..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQuery.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Backbone.BuildingBlocks.Application.Pagination; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; -using MediatR; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.ListChanges; - -public class ListChangesQuery : IRequest -{ - public ListChangesQuery(PaginationFilter paginationFilter, IEnumerable ids, OptionalDateRange? createdAt, OptionalDateRange? completedAt, OptionalDateRange? modifiedAt, RelationshipChangeStatus? status, RelationshipChangeType? type, IdentityAddress? createdBy, IdentityAddress? completedBy, bool onlyPeerChanges) - { - PaginationFilter = paginationFilter; - Ids = ids; - CreatedAt = createdAt; - CompletedAt = completedAt; - ModifiedAt = modifiedAt; - Status = status; - Type = type; - CreatedBy = createdBy; - CompletedBy = completedBy; - OnlyPeerChanges = onlyPeerChanges; - } - - public PaginationFilter PaginationFilter { get; set; } - public IEnumerable Ids { get; set; } - public OptionalDateRange? CreatedAt { get; set; } - public OptionalDateRange? CompletedAt { get; set; } - public OptionalDateRange? ModifiedAt { get; } - public RelationshipChangeStatus? Status { get; } - public IdentityAddress? CreatedBy { get; set; } - public IdentityAddress? CompletedBy { get; set; } - public bool OnlyPeerChanges { get; set; } - public RelationshipChangeType? Type { get; set; } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQueryValidator.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQueryValidator.cs deleted file mode 100644 index 56f9318904..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesQueryValidator.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Common.FluentValidation; -using FluentValidation; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.ListChanges; - -// ReSharper disable once UnusedMember.Global -public class ListChangesQueryValidator : AbstractValidator -{ - public ListChangesQueryValidator() - { - RuleFor(query => query.CreatedAt) - .IsValidRange().WithErrorCode(GenericApplicationErrors.Validation.InvalidPropertyValue().Code); - } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesResponse.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesResponse.cs deleted file mode 100644 index 1a9cb572c7..0000000000 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListChanges/ListChangesResponse.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Backbone.BuildingBlocks.Application.Pagination; -using Backbone.Modules.Relationships.Application.Relationships.DTOs; - -namespace Backbone.Modules.Relationships.Application.Relationships.Queries.ListChanges; - -public class ListChangesResponse : PagedResponse -{ - public ListChangesResponse(IEnumerable items, PaginationFilter previousPaginationFilter, int totalRecords) : base(items, previousPaginationFilter, totalRecords) { } -} diff --git a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListRelationships/ListRelationshipsQuery.cs b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListRelationships/ListRelationshipsQuery.cs index f57a44645e..30153b363a 100644 --- a/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListRelationships/ListRelationshipsQuery.cs +++ b/Modules/Relationships/src/Relationships.Application/Relationships/Queries/ListRelationships/ListRelationshipsQuery.cs @@ -1,5 +1,5 @@ using Backbone.BuildingBlocks.Application.Pagination; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using MediatR; namespace Backbone.Modules.Relationships.Application.Relationships.Queries.ListRelationships; diff --git a/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipTemplatesController.cs b/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipTemplatesController.cs index 6d01320d3f..ff3aec6385 100644 --- a/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipTemplatesController.cs +++ b/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipTemplatesController.cs @@ -8,7 +8,7 @@ using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.GetRelationshipTemplate; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.ListRelationshipTemplates; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; diff --git a/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipsController.cs b/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipsController.cs index d69a8024e2..b844f989b7 100644 --- a/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipsController.cs +++ b/Modules/Relationships/src/Relationships.ConsumerApi/Controllers/RelationshipsController.cs @@ -3,20 +3,15 @@ using Backbone.BuildingBlocks.API.Mvc.ControllerAttributes; using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.BuildingBlocks.Application.Pagination; -using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Relationships.Application; -using Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationshipChangeRequest; +using Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationship; using Backbone.Modules.Relationships.Application.Relationships.Commands.CreateRelationship; -using Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationshipChangeRequest; -using Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationshipChangeRequest; +using Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationship; +using Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationship; using Backbone.Modules.Relationships.Application.Relationships.DTOs; -using Backbone.Modules.Relationships.Application.Relationships.Queries.GetChange; using Backbone.Modules.Relationships.Application.Relationships.Queries.GetRelationship; -using Backbone.Modules.Relationships.Application.Relationships.Queries.ListChanges; using Backbone.Modules.Relationships.Application.Relationships.Queries.ListRelationships; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; @@ -63,111 +58,48 @@ public async Task ListRelationships([FromQuery] PaginationFilter return Paged(relationships); } - [HttpGet("Changes")] - [ProducesResponseType(typeof(PagedHttpResponseEnvelope), StatusCodes.Status200OK)] - public async Task ListChanges( - [FromQuery] PaginationFilter paginationFilter, - [FromQuery] IEnumerable ids, - [FromQuery] OptionalDateRange? createdAt, - [FromQuery] OptionalDateRange? completedAt, - [FromQuery] OptionalDateRange? modifiedAt, - [FromQuery] bool? onlyPeerChanges, - [FromQuery] IdentityAddress? createdBy, - [FromQuery] IdentityAddress? completedBy, - [FromQuery] string? status, - [FromQuery] string? type, CancellationToken cancellationToken) - { - var query = new ListChangesQuery( - paginationFilter, - ids, - createdAt, - completedAt, - modifiedAt, - status == null ? null : Enum.Parse(status), - type == null ? null : Enum.Parse(type), - createdBy, - completedBy, - onlyPeerChanges ?? false); - - query.PaginationFilter.PageSize ??= _options.Pagination.DefaultPageSize; - - if (paginationFilter.PageSize > _options.Pagination.MaxPageSize) - throw new ApplicationException( - GenericApplicationErrors.Validation.InvalidPageSize(_options.Pagination.MaxPageSize)); - - var changes = await _mediator.Send(query, cancellationToken); - return Paged(changes); - } - - [HttpGet("Changes/{id}")] - [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] - [ProducesError(StatusCodes.Status404NotFound)] - public async Task GetChangeById(RelationshipChangeId id, CancellationToken cancellationToken) - { - var relationship = await _mediator.Send(new GetChangeQuery { Id = id }, cancellationToken); - return Ok(relationship); - } - [HttpPost] [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] + [ProducesError(StatusCodes.Status400BadRequest)] + [ProducesError(StatusCodes.Status404NotFound)] public async Task CreateRelationship(CreateRelationshipCommand request, CancellationToken cancellationToken) { var relationship = await _mediator.Send(request, cancellationToken); return Created(relationship); } - [HttpPut("{relationshipId}/Changes/{changeId}/Accept")] - [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] - public async Task AcceptRelationshipChange([FromRoute] RelationshipId relationshipId, - [FromRoute] RelationshipChangeId changeId, CompleteRelationshipChangeRequest request, CancellationToken cancellationToken) + [HttpPut("{id}/Accept")] + [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] + [ProducesError(StatusCodes.Status400BadRequest)] + [ProducesError(StatusCodes.Status404NotFound)] + public async Task AcceptRelationship([FromRoute] string id, [FromBody] AcceptRelationshipRequest request, CancellationToken cancellationToken) { - var change = await _mediator.Send(new AcceptRelationshipChangeRequestCommand - { - Id = relationshipId, - ChangeId = changeId, - ResponseContent = request.Content - }, cancellationToken); - - return Ok(change); + var response = await _mediator.Send(new AcceptRelationshipCommand { RelationshipId = id, AcceptanceContent = request.AcceptanceContent }, cancellationToken); + return Ok(response); } - [HttpPut("{relationshipId}/Changes/{changeId}/Reject")] - [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] - public async Task RejectRelationshipChange([FromRoute] RelationshipId relationshipId, - [FromRoute(Name = "changeId")] RelationshipChangeId changeId, CompleteRelationshipChangeRequest request, CancellationToken cancellationToken) + [HttpPut("{id}/Reject")] + [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] + [ProducesError(StatusCodes.Status400BadRequest)] + [ProducesError(StatusCodes.Status404NotFound)] + public async Task RejectRelationship([FromRoute] string id, CancellationToken cancellationToken) { - var change = await _mediator.Send(new RejectRelationshipChangeRequestCommand - { - Id = relationshipId, - ChangeId = changeId, - ResponseContent = request.Content - }, cancellationToken); - - return Ok(change); + var response = await _mediator.Send(new RejectRelationshipCommand { RelationshipId = id }, cancellationToken); + return Ok(response); } - [HttpPut("{relationshipId}/Changes/{changeId}/Revoke")] - [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] - public async Task RevokeRelationshipChange([FromRoute] RelationshipId relationshipId, - [FromRoute(Name = "changeId")] RelationshipChangeId changeId, CompleteRelationshipChangeRequest request, CancellationToken cancellationToken) + [HttpPut("{id}/Revoke")] + [ProducesResponseType(typeof(HttpResponseEnvelopeResult), StatusCodes.Status200OK)] + [ProducesError(StatusCodes.Status400BadRequest)] + [ProducesError(StatusCodes.Status404NotFound)] + public async Task RevokeRelationship([FromRoute] string id, CancellationToken cancellationToken) { - var change = await _mediator.Send(new RevokeRelationshipChangeRequestCommand - { - Id = relationshipId, - ChangeId = changeId, - ResponseContent = request.Content - }, cancellationToken); - - return Ok(change); + var response = await _mediator.Send(new RevokeRelationshipCommand { RelationshipId = id }, cancellationToken); + return Ok(response); } } -public class CreateRelationshipChangeRequest -{ - public RelationshipChangeType Type { get; set; } -} - -public class CompleteRelationshipChangeRequest +public class AcceptRelationshipRequest { - public byte[] Content { get; set; } = Array.Empty(); + public byte[]? AcceptanceContent { get; set; } } diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplate.cs similarity index 93% rename from Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplate.cs index 354a7d6e54..93f405604b 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplate.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplate.cs @@ -1,11 +1,10 @@ using System.Linq.Expressions; using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Backbone.Tooling; -namespace Backbone.Modules.Relationships.Domain.Entities; +namespace Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; public class RelationshipTemplate { diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateAllocation.cs similarity index 91% rename from Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateAllocation.cs index 9934d1c77e..9583f1aeeb 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTemplateAllocation.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateAllocation.cs @@ -1,9 +1,8 @@ using System.Linq.Expressions; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Ids; using Backbone.Tooling; -namespace Backbone.Modules.Relationships.Domain.Entities; +namespace Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; public class RelationshipTemplateAllocation { diff --git a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipTemplateId.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateId.cs similarity index 94% rename from Modules/Relationships/src/Relationships.Domain/Ids/RelationshipTemplateId.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateId.cs index ba1c2520e9..8a0b9d4179 100644 --- a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipTemplateId.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/RelationshipTemplates/RelationshipTemplateId.cs @@ -3,7 +3,7 @@ using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Domain.StronglyTypedIds.Classes; -namespace Backbone.Modules.Relationships.Domain.Ids; +namespace Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; [Serializable] [TypeConverter(typeof(RelationshipTemplateIdTypeConverter))] @@ -13,7 +13,9 @@ public class RelationshipTemplateId : StronglyTypedId private const string PREFIX = "RLT"; private static readonly StronglyTypedIdHelpers UTILS = new(PREFIX, DEFAULT_VALID_CHARS, MAX_LENGTH); - private RelationshipTemplateId(string stringValue) : base(stringValue) { } + private RelationshipTemplateId(string stringValue) : base(stringValue) + { + } public static RelationshipTemplateId Parse(string stringValue) { diff --git a/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/Relationship.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/Relationship.cs new file mode 100644 index 0000000000..d016732a70 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/Relationship.cs @@ -0,0 +1,158 @@ +using System.Linq.Expressions; +using Backbone.BuildingBlocks.Domain; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; +using Backbone.Tooling; + +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +public class Relationship +{ + // ReSharper disable once UnusedMember.Local + private Relationship() + { + // This constructor is for EF Core only; initializing the properties with null is therefore not a problem + Id = null!; + RelationshipTemplateId = null!; + RelationshipTemplate = null!; + From = null!; + To = null!; + AuditLog = null!; + } + + public Relationship(RelationshipTemplate relationshipTemplate, IdentityAddress activeIdentity, DeviceId activeDevice, byte[]? creationContent, List existingRelationships) + { + EnsureTargetIsNotSelf(relationshipTemplate, activeIdentity); + EnsureNoActiveRelationshipToTargetExists(relationshipTemplate.CreatedBy, existingRelationships); + + Id = RelationshipId.New(); + RelationshipTemplateId = relationshipTemplate.Id; + RelationshipTemplate = relationshipTemplate; + + From = activeIdentity; + To = relationshipTemplate.CreatedBy; + Status = RelationshipStatus.Pending; + + CreatedAt = SystemTime.UtcNow; + + CreationContent = creationContent; + + AuditLog = new List + { + new(RelationshipAuditLogEntryReason.Creation, null, RelationshipStatus.Pending, activeIdentity, activeDevice) + }; + } + + public RelationshipId Id { get; } + public RelationshipTemplateId RelationshipTemplateId { get; } + public RelationshipTemplate RelationshipTemplate { get; } + + public IdentityAddress From { get; } + public IdentityAddress To { get; } + + public DateTime CreatedAt { get; } + + public RelationshipStatus Status { get; private set; } + public byte[]? CreationContent { get; } + public byte[]? AcceptanceContent { get; private set; } + public List AuditLog { get; } + + public IdentityAddress LastModifiedBy => AuditLog.Last().CreatedBy; + + private static void EnsureTargetIsNotSelf(RelationshipTemplate relationshipTemplate, IdentityAddress activeIdentity) + { + if (activeIdentity == relationshipTemplate.CreatedBy) + throw new DomainException(DomainErrors.CannotSendRelationshipRequestToYourself()); + } + + private static void EnsureNoActiveRelationshipToTargetExists(IdentityAddress target, List existingRelationships) + { + if (existingRelationships.Any(r => r.Status == RelationshipStatus.Active)) + throw new DomainException(DomainErrors.RelationshipToTargetAlreadyExists(target)); + } + + public void Accept(IdentityAddress activeIdentity, DeviceId activeDevice, byte[]? acceptanceContent) + { + EnsureStatus(RelationshipStatus.Pending); + EnsureRelationshipRequestIsAddressedToSelf(activeIdentity); + + Status = RelationshipStatus.Active; + AcceptanceContent = acceptanceContent; + + var auditLogEntry = new RelationshipAuditLogEntry( + RelationshipAuditLogEntryReason.AcceptanceOfCreation, + RelationshipStatus.Pending, + RelationshipStatus.Active, + activeIdentity, + activeDevice + ); + AuditLog.Add(auditLogEntry); + } + + private void EnsureRelationshipRequestIsAddressedToSelf(IdentityAddress activeIdentity) + { + if (To != activeIdentity) + throw new DomainException(DomainErrors.CannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse()); + } + + private void EnsureRelationshipRequestIsCreatedBySelf(IdentityAddress activeIdentity) + { + if (From != activeIdentity) + throw new DomainException(DomainErrors.CannotRevokeRelationshipRequestNotCreatedByYourself()); + } + + public void Reject(IdentityAddress activeIdentity, DeviceId activeDevice) + { + EnsureStatus(RelationshipStatus.Pending); + EnsureRelationshipRequestIsAddressedToSelf(activeIdentity); + + Status = RelationshipStatus.Rejected; + + var auditLogEntry = new RelationshipAuditLogEntry( + RelationshipAuditLogEntryReason.RejectionOfCreation, + RelationshipStatus.Pending, + RelationshipStatus.Rejected, + activeIdentity, + activeDevice + ); + AuditLog.Add(auditLogEntry); + } + + private void EnsureStatus(RelationshipStatus status) + { + if (Status != status) + throw new DomainException(DomainErrors.RelationshipIsNotInCorrectStatus(status)); + } + + public void Revoke(IdentityAddress activeIdentity, DeviceId activeDevice) + { + EnsureStatus(RelationshipStatus.Pending); + EnsureRelationshipRequestIsCreatedBySelf(activeIdentity); + + Status = RelationshipStatus.Revoked; + + var auditLogEntry = new RelationshipAuditLogEntry( + RelationshipAuditLogEntryReason.RevocationOfCreation, + RelationshipStatus.Pending, + RelationshipStatus.Revoked, + activeIdentity, + activeDevice + ); + AuditLog.Add(auditLogEntry); + } + + #region Expressions + + public static Expression> HasParticipant(string identity) + { + return r => r.From == identity || r.To == identity; + } + + public static Expression> CountsAsActive() + { + return r => r.Status != RelationshipStatus.Rejected && + r.Status != RelationshipStatus.Revoked; + } + + #endregion +} diff --git a/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntry.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntry.cs new file mode 100644 index 0000000000..b81aa47bc2 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntry.cs @@ -0,0 +1,35 @@ +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Tooling; + +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +public class RelationshipAuditLogEntry +{ + // ReSharper disable once UnusedMember.Local + private RelationshipAuditLogEntry() + { + // This constructor is for EF Core only; initializing the properties with null is therefore not a problem + Id = null!; + CreatedBy = null!; + CreatedByDevice = null!; + } + + public RelationshipAuditLogEntry(RelationshipAuditLogEntryReason reason, RelationshipStatus? oldStatus, RelationshipStatus newStatus, IdentityAddress createdBy, DeviceId createdByDevice) + { + Id = RelationshipAuditLogEntryId.New(); + Reason = reason; + OldStatus = oldStatus; + NewStatus = newStatus; + CreatedBy = createdBy; + CreatedByDevice = createdByDevice; + CreatedAt = SystemTime.UtcNow; + } + + public RelationshipAuditLogEntryId Id { get; } + public RelationshipAuditLogEntryReason Reason { get; } + public RelationshipStatus? OldStatus { get; } + public RelationshipStatus NewStatus { get; } + public IdentityAddress CreatedBy { get; } + public DeviceId CreatedByDevice { get; } + public DateTime CreatedAt { get; } +} diff --git a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipChangeId.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryId.cs similarity index 63% rename from Modules/Relationships/src/Relationships.Domain/Ids/RelationshipChangeId.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryId.cs index c5b2dd0151..8eca1db27c 100644 --- a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipChangeId.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryId.cs @@ -3,23 +3,25 @@ using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Domain.StronglyTypedIds.Classes; -namespace Backbone.Modules.Relationships.Domain.Ids; +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; [Serializable] -[TypeConverter(typeof(RelationshipChangeIdTypeConverter))] -public class RelationshipChangeId : StronglyTypedId +[TypeConverter(typeof(RelationshipAuditLogEntryIdTypeConverter))] +public class RelationshipAuditLogEntryId : StronglyTypedId { public const int MAX_LENGTH = DEFAULT_MAX_LENGTH; - private const string PREFIX = "RCH"; + private const string PREFIX = "RAL"; private static readonly StronglyTypedIdHelpers UTILS = new(PREFIX, DEFAULT_VALID_CHARS, MAX_LENGTH); - private RelationshipChangeId(string stringValue) : base(stringValue) { } + private RelationshipAuditLogEntryId(string stringValue) : base(stringValue) + { + } - public static RelationshipChangeId Parse(string stringValue) + public static RelationshipAuditLogEntryId Parse(string stringValue) { UTILS.Validate(stringValue); - return new RelationshipChangeId(stringValue); + return new RelationshipAuditLogEntryId(stringValue); } public static bool IsValid(string stringValue) @@ -27,13 +29,13 @@ public static bool IsValid(string stringValue) return UTILS.IsValid(stringValue); } - public static RelationshipChangeId New() + public static RelationshipAuditLogEntryId New() { var stringValue = StringUtils.Generate(DEFAULT_VALID_CHARS, DEFAULT_MAX_LENGTH_WITHOUT_PREFIX); - return new RelationshipChangeId(PREFIX + stringValue); + return new RelationshipAuditLogEntryId(PREFIX + stringValue); } - public class RelationshipChangeIdTypeConverter : TypeConverter + public class RelationshipAuditLogEntryIdTypeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { diff --git a/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryReason.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryReason.cs new file mode 100644 index 0000000000..f4c65a485f --- /dev/null +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipAuditLogEntryReason.cs @@ -0,0 +1,9 @@ +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +public enum RelationshipAuditLogEntryReason +{ + Creation = 0, + AcceptanceOfCreation = 1, + RejectionOfCreation = 2, + RevocationOfCreation = 3 +} diff --git a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipId.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipId.cs similarity index 94% rename from Modules/Relationships/src/Relationships.Domain/Ids/RelationshipId.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipId.cs index 0d18b1842c..74e46d9d51 100644 --- a/Modules/Relationships/src/Relationships.Domain/Ids/RelationshipId.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipId.cs @@ -3,7 +3,7 @@ using Backbone.BuildingBlocks.Domain; using Backbone.BuildingBlocks.Domain.StronglyTypedIds.Classes; -namespace Backbone.Modules.Relationships.Domain.Ids; +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; [Serializable] [TypeConverter(typeof(RelationshipIdTypeConverter))] @@ -13,7 +13,9 @@ public class RelationshipId : StronglyTypedId private const string PREFIX = "REL"; private static readonly StronglyTypedIdHelpers UTILS = new(PREFIX, DEFAULT_VALID_CHARS, MAX_LENGTH); - private RelationshipId(string stringValue) : base(stringValue) { } + private RelationshipId(string stringValue) : base(stringValue) + { + } public static RelationshipId Parse(string stringValue) { diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipStatus.cs b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipStatus.cs similarity index 51% rename from Modules/Relationships/src/Relationships.Domain/Entities/RelationshipStatus.cs rename to Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipStatus.cs index a43cd3dc5f..4e56892afc 100644 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipStatus.cs +++ b/Modules/Relationships/src/Relationships.Domain/Aggregates/Relationships/RelationshipStatus.cs @@ -1,4 +1,4 @@ -namespace Backbone.Modules.Relationships.Domain.Entities; +namespace Backbone.Modules.Relationships.Domain.Aggregates.Relationships; public enum RelationshipStatus { @@ -6,6 +6,4 @@ public enum RelationshipStatus Active = 20, Rejected = 30, Revoked = 40, - Terminating = 50, - Terminated = 60 } diff --git a/Modules/Relationships/src/Relationships.Domain/DomainErrors.cs b/Modules/Relationships/src/Relationships.Domain/DomainErrors.cs new file mode 100644 index 0000000000..2058c9a1f9 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Domain/DomainErrors.cs @@ -0,0 +1,42 @@ +using Backbone.BuildingBlocks.Domain.Errors; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; + +namespace Backbone.Modules.Relationships.Domain; + +public static class DomainErrors +{ + public static DomainError MaxNumberOfAllocationsExhausted() + { + return new DomainError("error.platform.validation.relationshipTemplate.maxNumberOfAllocationsExhausted", + "The maximum number of allocations (maxNumberOfAllocations) of the template you are trying to read is exhausted."); + } + + public static DomainError CannotSendRelationshipRequestToYourself() + { + return new DomainError("error.platform.validation.relationshipRequest.cannotSendRelationshipRequestToYourself", + "You cannot send a relationship request to yourself."); + } + + public static DomainError CannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse() + { + return new DomainError("error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse", + "You cannot accept or reject a relationship request that is addressed to someone else."); + } + + public static DomainError CannotRevokeRelationshipRequestNotCreatedByYourself() + { + return new DomainError("error.platform.validation.relationshipRequest.cannotRevokeRelationshipRequestNotCreatedByYourself", + "You cannot revoke a relationship request that was not created by yourself."); + } + + public static DomainError RelationshipIsNotInCorrectStatus(RelationshipStatus expectedStatus) + { + return new DomainError("error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus", + $"The relationship has to be in status '{expectedStatus}' to perform this action."); + } + + public static DomainError RelationshipToTargetAlreadyExists(string targetIdentity) + { + return new DomainError("error.platform.validation.relationshipRequest.relationshipToTargetAlreadyExists", $"A relationship to '{targetIdentity}' already exists."); + } +} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs b/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs deleted file mode 100644 index 9dc707af78..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/Relationship.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System.Linq.Expressions; -using Backbone.BuildingBlocks.Domain; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Ids; -using Backbone.Tooling; - -namespace Backbone.Modules.Relationships.Domain.Entities; - -public class Relationship -{ - private readonly RelationshipChangeLog _changes = []; - - // ReSharper disable once UnusedMember.Local - private Relationship() - { - // This constructor is for EF Core only; initializing the properties with null is therefore not a problem - Id = null!; - RelationshipTemplateId = null!; - RelationshipTemplate = null!; - From = null!; - To = null!; - } - - public Relationship(RelationshipTemplate relationshipTemplate, IdentityAddress from, DeviceId fromDevice, byte[]? requestContent) - { - Id = RelationshipId.New(); - RelationshipTemplateId = relationshipTemplate.Id; - RelationshipTemplate = relationshipTemplate; - - From = from; - To = relationshipTemplate.CreatedBy; - Status = RelationshipStatus.Pending; - - CreatedAt = SystemTime.UtcNow; - - _changes.Add(new RelationshipCreationChange(this, from, fromDevice, requestContent)); - } - - public RelationshipId Id { get; } - public RelationshipTemplateId RelationshipTemplateId { get; } - public RelationshipTemplate RelationshipTemplate { get; } - - public IdentityAddress From { get; } - public IdentityAddress To { get; } - public IRelationshipChangeLog Changes => _changes; - - public DateTime CreatedAt { get; } - - public RelationshipStatus Status { get; private set; } - - public RelationshipChange AcceptChange(RelationshipChangeId changeId, IdentityAddress acceptedBy, DeviceId acceptedByDevice, byte[]? content) - { - var change = _changes.GetById(changeId); - - change.Accept(acceptedBy, acceptedByDevice, content); - Status = GetStatusAfterChange(change); - - return change; - } - - public RelationshipChange RejectChange(RelationshipChangeId changeId, IdentityAddress rejectedBy, DeviceId rejectedByDevice, byte[]? content) - { - var change = _changes.GetById(changeId); - - if (change.IsCompleted) - throw new DomainException(DomainErrors.ChangeRequestIsAlreadyCompleted(change.Status)); - - if (rejectedBy == change.Request.CreatedBy) - throw new DomainException(DomainErrors.ChangeRequestCannotBeRejectedByCreator()); - - change.Reject(rejectedBy, rejectedByDevice, content); - Status = GetStatusAfterChange(change); - - return change; - } - - public RelationshipChange RevokeChange(RelationshipChangeId changeId, IdentityAddress revokedBy, DeviceId revokedByDevice, byte[]? content) - { - var change = _changes.GetById(changeId); - - if (change.IsCompleted) - throw new DomainException(DomainErrors.ChangeRequestIsAlreadyCompleted(change.Status)); - - if (revokedBy != change.Request.CreatedBy) - throw new DomainException(DomainErrors.ChangeRequestCanOnlyBeRevokedByCreator()); - - change.Revoke(revokedBy, revokedByDevice, content); - Status = GetStatusAfterChange(change); - - return change; - } - - private static RelationshipStatus GetStatusAfterChange(RelationshipChange change) - { - switch (change.Type) - { - case RelationshipChangeType.Creation: - return change.Status switch - { - RelationshipChangeStatus.Accepted => RelationshipStatus.Active, - RelationshipChangeStatus.Rejected => RelationshipStatus.Rejected, - RelationshipChangeStatus.Revoked => RelationshipStatus.Revoked, - RelationshipChangeStatus.Pending => throw new NotSupportedException(), - _ => throw new NotSupportedException() - }; - - case RelationshipChangeType.Termination: - return change.Status switch - { - RelationshipChangeStatus.Accepted => RelationshipStatus.Terminated, - RelationshipChangeStatus.Rejected => RelationshipStatus.Active, - RelationshipChangeStatus.Revoked => RelationshipStatus.Active, - RelationshipChangeStatus.Pending => throw new NotSupportedException(), - _ => throw new NotSupportedException() - }; - case RelationshipChangeType.TerminationCancellation: - throw new NotImplementedException(); - default: - throw new NotSupportedException(); - } - } - - private RelationshipChange? GetPendingChangeOrNull() - { - return _changes.FirstOrDefault(c => c.Status == RelationshipChangeStatus.Pending); - } - - public RelationshipChange RequestTermination(IdentityAddress requestedBy, DeviceId requestedByDevice) - { - EnsureCanBeTerminated(); - - var terminationChange = new RelationshipTerminationChange(this, requestedBy, requestedByDevice); - _changes.Add(terminationChange); - - return terminationChange; - } - - private void EnsureCanBeTerminated() - { - if (Status != RelationshipStatus.Active) - throw new DomainException(DomainErrors.OnlyActiveRelationshipsCanBeTerminated()); - - var existingChange = GetPendingChangeOrNull(); - - if (existingChange != null) - throw new DomainException(DomainErrors.PendingChangeAlreadyExists(existingChange.Id)); - } - - #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 deleted file mode 100644 index aa4ce6bff3..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChange.cs +++ /dev/null @@ -1,163 +0,0 @@ -using Backbone.BuildingBlocks.Domain; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Ids; -using Backbone.Tooling; - -namespace Backbone.Modules.Relationships.Domain.Entities; - -public class RelationshipChange -{ - // ReSharper disable once UnusedMember.Local - protected RelationshipChange() - { - // This constructor is for EF Core only; initializing the properties with null is therefore not a problem - Id = null!; - RelationshipId = null!; - Relationship = null!; - Request = null!; - } - - protected RelationshipChange(Relationship relationship, IdentityAddress createdBy, DeviceId createdByDevice, RelationshipChangeType type, byte[]? requestContent) - { - Id = RelationshipChangeId.New(); - RelationshipId = relationship.Id; - Relationship = relationship; - Type = type; - Status = RelationshipChangeStatus.Pending; - Request = new RelationshipChangeRequest(Id, createdBy, createdByDevice, requestContent); - CreatedAt = SystemTime.UtcNow; - } - - public RelationshipChangeId Id { get; } - public RelationshipId RelationshipId { get; } - public Relationship Relationship { get; } - - public RelationshipChangeType Type { get; } - public RelationshipChangeStatus Status { get; private set; } - public DateTime CreatedAt { get; } - - public RelationshipChangeRequest Request { get; } - public RelationshipChangeResponse? Response { get; private set; } - - public bool IsCompleted => Status != RelationshipChangeStatus.Pending; - - internal void Accept(IdentityAddress by, DeviceId byDevice, byte[]? content = null) - { - EnsureCanBeAccepted(by, content); - Status = RelationshipChangeStatus.Accepted; - Response = new RelationshipChangeResponse(Id, by, byDevice, content); - } - - protected virtual void EnsureCanBeAccepted(IdentityAddress by, byte[]? content) - { - if (IsCompleted) - throw new DomainException(DomainErrors.ChangeRequestIsAlreadyCompleted(Status)); - - if (by == Request.CreatedBy) - throw new DomainException(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); - } - - internal virtual void Reject(IdentityAddress by, DeviceId byDevice, byte[]? content = null) - { - EnsureCanBeRejected(by, content); - Status = RelationshipChangeStatus.Rejected; - Response = new RelationshipChangeResponse(Id, by, byDevice, content); - } - - protected virtual void EnsureCanBeRejected(IdentityAddress by, byte[]? content) - { - if (IsCompleted) - throw new DomainException(DomainErrors.ChangeRequestIsAlreadyCompleted(Status)); - - if (by == Request.CreatedBy) - throw new DomainException(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); - } - - internal virtual void Revoke(IdentityAddress by, DeviceId byDevice, byte[]? content = null) - { - EnsureCanBeRevoked(by, content); - Status = RelationshipChangeStatus.Revoked; - Response = new RelationshipChangeResponse(Id, by, byDevice, content); - } - - protected virtual void EnsureCanBeRevoked(IdentityAddress by, byte[]? content) - { - if (IsCompleted) - throw new DomainException(DomainErrors.ChangeRequestIsAlreadyCompleted(Status)); - - if (by != Request.CreatedBy) - throw new DomainException(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); - } -} - -public class RelationshipChangeRequest -{ - // ReSharper disable once UnusedMember.Local - private RelationshipChangeRequest() - { - // This constructor is for EF Core only; initializing the properties with null is therefore not a problem - Id = null!; - CreatedBy = null!; - CreatedByDevice = null!; - } - - public RelationshipChangeRequest(RelationshipChangeId changeId, IdentityAddress createdBy, DeviceId createdByDevice, byte[]? content = null) - { - Id = changeId; - CreatedAt = SystemTime.UtcNow; - CreatedBy = createdBy; - CreatedByDevice = createdByDevice; - Content = content; - } - - public RelationshipChangeId Id { get; } - public DateTime CreatedAt { get; } - public IdentityAddress CreatedBy { get; } - public DeviceId CreatedByDevice { get; } - public byte[]? Content { get; private set; } - - public void LoadContent(byte[] content) - { - if (Content != null) - throw new Exception("Cannot change the content of a relationship template."); - - Content = content; - } -} - -public class RelationshipChangeResponse -{ - // ReSharper disable once UnusedMember.Local - private RelationshipChangeResponse() - { - // This constructor is for EF Core only; initializing the properties with null is therefore not a problem - Id = null!; - CreatedBy = null!; - CreatedByDevice = null!; - } - - public RelationshipChangeResponse(RelationshipChangeId changeId, IdentityAddress createdBy, DeviceId createdByDevice, byte[]? content = null) - { - Id = changeId; - CreatedAt = SystemTime.UtcNow; - CreatedBy = createdBy; - CreatedByDevice = createdByDevice; - Content = content; - } - - public RelationshipChangeId Id { get; } - public DateTime CreatedAt { get; } - public IdentityAddress CreatedBy { get; } - public DeviceId CreatedByDevice { get; } - - public byte[]? Content { get; private set; } - - public void LoadContent(byte[] content) - { - if (Content != null) - throw new Exception("Cannot change the content of a relationship template."); - - Content = content; - } -} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeLog.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeLog.cs deleted file mode 100644 index e03e78b23f..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeLog.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.Collections; -using Backbone.BuildingBlocks.Domain; -using Backbone.BuildingBlocks.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Ids; - -namespace Backbone.Modules.Relationships.Domain.Entities; - -public interface IRelationshipChangeLog : IEnumerable -{ - RelationshipChange GetLatestOfType(RelationshipChangeType type); - RelationshipChange? GetLatestOfTypeOrNull(RelationshipChangeType type, Predicate? condition = null); -} - -public class RelationshipChangeLog : IRelationshipChangeLog, ICollection -{ - private readonly SortedList _changes = new(); - - - public RelationshipChange GetLatestOfType(RelationshipChangeType type) - { - var change = _changes.Values.LastOrDefault(c => c.Type == type) ?? throw new DomainException(GenericDomainErrors.NotFound(nameof(RelationshipChange))); - return change; - } - - public RelationshipChange? GetLatestOfTypeOrNull(RelationshipChangeType type, Predicate? condition = null) - { - var change = _changes.Values.LastOrDefault(c => c.Type == type && (condition == null || condition(c))); - return change; - } - - - public RelationshipChange GetById(RelationshipChangeId id) - { - var change = _changes.Values.FirstOrDefault(c => c.Id == id) ?? throw new DomainException(GenericDomainErrors.NotFound(nameof(RelationshipChange))); - return change; - } - - #region IEnumerable implementation - - public IEnumerator GetEnumerator() - { - return _changes.Values.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - #endregion - - #region ICollection implementation - - public void Add(RelationshipChange change) - { - _changes.Add(change.CreatedAt, change); - } - - public void Clear() - { - _changes.Clear(); - } - - public bool Contains(RelationshipChange item) - { - return _changes.Values.Contains(item); - } - - public void CopyTo(RelationshipChange[] array, int arrayIndex) - { - _changes.Values.CopyTo(array, arrayIndex); - } - - public bool Remove(RelationshipChange item) - { - return _changes.Values.Remove(item); - } - - public int Count => _changes.Count; - public bool IsReadOnly => false; - - #endregion -} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeStatus.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeStatus.cs deleted file mode 100644 index 6989c6ee21..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeStatus.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Backbone.Modules.Relationships.Domain.Entities; - -public enum RelationshipChangeStatus -{ - Pending = 10, - Accepted = 20, - Rejected = 30, - Revoked = 40 -} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeType.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeType.cs deleted file mode 100644 index 80bad189c5..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipChangeType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Backbone.Modules.Relationships.Domain.Entities; - -public enum RelationshipChangeType -{ - Creation = 10, - Termination = 20, - TerminationCancellation = 30 -} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipCreationChange.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipCreationChange.cs deleted file mode 100644 index 27a1865eac..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipCreationChange.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Backbone.BuildingBlocks.Domain; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Errors; - -namespace Backbone.Modules.Relationships.Domain.Entities; - -public class RelationshipCreationChange : RelationshipChange -{ - // ReSharper disable once UnusedMember.Local - private RelationshipCreationChange() - { - } - - internal RelationshipCreationChange(Relationship relationship, IdentityAddress createdBy, DeviceId createdByDevice, byte[]? requestContent) : base(relationship, createdBy, createdByDevice, RelationshipChangeType.Creation, requestContent) { } - - protected override void EnsureCanBeAccepted(IdentityAddress by, byte[]? content) - { - if (content == null) - throw new DomainException(DomainErrors.ContentIsRequiredForCompletingRelationships()); - - base.EnsureCanBeAccepted(by, content); - } - - protected override void EnsureCanBeRejected(IdentityAddress by, byte[]? content) - { - if (content == null) - throw new DomainException(DomainErrors.ContentIsRequiredForCompletingRelationships()); - - base.EnsureCanBeRejected(by, content); - } - - protected override void EnsureCanBeRevoked(IdentityAddress by, byte[]? content) - { - if (content == null) - throw new DomainException(DomainErrors.ContentIsRequiredForCompletingRelationships()); - - base.EnsureCanBeRevoked(by, content); - } -} diff --git a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTerminationChange.cs b/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTerminationChange.cs deleted file mode 100644 index 30052808aa..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Entities/RelationshipTerminationChange.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Backbone.DevelopmentKit.Identity.ValueObjects; - -namespace Backbone.Modules.Relationships.Domain.Entities; - -public class RelationshipTerminationChange : RelationshipChange -{ - private RelationshipTerminationChange() { } - - internal RelationshipTerminationChange(Relationship relationship, IdentityAddress createdBy, DeviceId createdByDevice) : base(relationship, createdBy, createdByDevice, RelationshipChangeType.Termination, null) { } -} diff --git a/Modules/Relationships/src/Relationships.Domain/Errors/DomainErrors.cs b/Modules/Relationships/src/Relationships.Domain/Errors/DomainErrors.cs deleted file mode 100644 index ffb8e80616..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Errors/DomainErrors.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Backbone.BuildingBlocks.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; - -namespace Backbone.Modules.Relationships.Domain.Errors; - -public static class DomainErrors -{ - public static DomainError ChangeRequestCannotBeAcceptedByCreator() - { - return new DomainError("error.platform.relationships.changeRequestCannotBeAcceptedByCreator", "A change request cannot be accepted by its creator."); - } - - public static DomainError ChangeRequestCannotBeRejectedByCreator() - { - return new DomainError("error.platform.relationships.changeRequestCannotBeRejectedByCreator", "A change request cannot be rejected by its creator."); - } - - public static DomainError ChangeRequestCanOnlyBeRevokedByCreator() - { - return new DomainError("error.platform.relationships.changeRequestCanOnlyBeRevokedByCreator", "A change request can only be revoked by its creator."); - } - - public static DomainError ChangeRequestIsAlreadyCompleted(RelationshipChangeStatus? changeStatus = null) - { - return new DomainError("error.platform.relationships.changeRequestIsAlreadyCompleted", - $"This change is already completed. (current status: '{changeStatus}')."); - } - - public static DomainError OnlyActiveRelationshipsCanBeTerminated() - { - return new DomainError("error.platform.relationships.onlyActiveRelationshipsCanBeTerminated", "Only active relationships can be terminated."); - } - - public static DomainError PendingChangeAlreadyExists(RelationshipChangeId? changeId = null) - { - return new DomainError("error.platform.relationships.pendingChangeAlreadyExists", $"There is already a pending change for this relationship. Change ID: {changeId}"); - } - - public static DomainError ContentIsRequiredForCompletingRelationships() - { - return new DomainError("error.platform.relationships.contentIsRequiredForCompletingRelationships", "The content property is required for accepting a relationship."); - } - - public static DomainError MaxNumberOfAllocationsExhausted() - { - return new DomainError("error.platform.validation.relationshipTemplate.maxNumberOfAllocationsExhausted", "The maximum number of allocations (maxNumberOfAllocations) of the template you are trying to read is exhausted."); - } -} diff --git a/Modules/Relationships/src/Relationships.Domain/Extensions/ChangeHistoryExtensions.cs b/Modules/Relationships/src/Relationships.Domain/Extensions/ChangeHistoryExtensions.cs deleted file mode 100644 index 20b60de8c1..0000000000 --- a/Modules/Relationships/src/Relationships.Domain/Extensions/ChangeHistoryExtensions.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Entities; - -namespace Backbone.Modules.Relationships.Domain.Extensions; - -public static class ChangeHistoryExtensions -{ - public static RelationshipChange? GetOpenTerminationOrNull(this IRelationshipChangeLog changes) - { - return changes.GetLatestOfTypeOrNull(RelationshipChangeType.Termination, c => !c.IsCompleted); - } - - public static RelationshipChange? GetPendingChangeOrNull(this IRelationshipChangeLog changes) - { - return changes.GetLatestOfTypeOrNull(RelationshipChangeType.Termination, c => !c.IsCompleted); - } -} diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.Designer.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.Designer.cs new file mode 100644 index 0000000000..373fa438e2 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.Designer.cs @@ -0,0 +1,249 @@ +// +using System; +using Backbone.Modules.Relationships.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Backbone.Modules.Relationships.Infrastructure.Database.Postgres.Migrations +{ + [DbContext(typeof(RelationshipsDbContext))] + [Migration("20240412141126_RelationshipsRevamp")] + partial class RelationshipsRevamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("Content") + .HasColumnType("bytea"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); + + b.Property("CreatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("MaxNumberOfAllocations") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("RelationshipTemplates"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllocatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("AllocatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); + + b.Property("AllocatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("RelationshipTemplateId", "AllocatedBy"); + + b.ToTable("RelationshipTemplateAllocations", (string)null); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("AcceptanceContent") + .HasColumnType("bytea"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationContent") + .HasColumnType("bytea"); + + b.Property("From") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("To") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("From"); + + b.HasIndex("RelationshipTemplateId"); + + b.HasIndex("To"); + + b.ToTable("Relationships"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); + + b.Property("CreatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.Property("NewStatus") + .HasColumnType("integer"); + + b.Property("OldStatus") + .HasColumnType("integer"); + + b.Property("Reason") + .HasColumnType("integer"); + + b.Property("RelationshipId") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("RelationshipId"); + + b.ToTable("RelationshipAuditLog", (string)null); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", null) + .WithMany("Allocations") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", "RelationshipTemplate") + .WithMany("Relationships") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("RelationshipTemplate"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", null) + .WithMany("AuditLog") + .HasForeignKey("RelationshipId"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => + { + b.Navigation("Allocations"); + + b.Navigation("Relationships"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.Navigation("AuditLog"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.cs new file mode 100644 index 0000000000..93bfdc9b16 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/20240412141126_RelationshipsRevamp.cs @@ -0,0 +1,114 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Backbone.Modules.Relationships.Infrastructure.Database.Postgres.Migrations +{ + /// + public partial class RelationshipsRevamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RelationshipChanges"); + + migrationBuilder.AddColumn( + name: "AcceptanceContent", + table: "Relationships", + type: "bytea", + nullable: true); + + migrationBuilder.AddColumn( + name: "CreationContent", + table: "Relationships", + type: "bytea", + nullable: true); + + migrationBuilder.CreateTable( + name: "RelationshipAuditLog", + columns: table => new + { + Id = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + Reason = table.Column(type: "integer", nullable: false), + OldStatus = table.Column(type: "integer", nullable: true), + NewStatus = table.Column(type: "integer", nullable: false), + CreatedBy = table.Column(type: "character(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: false), + CreatedByDevice = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + RelationshipId = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RelationshipAuditLog", x => x.Id); + table.ForeignKey( + name: "FK_RelationshipAuditLog_Relationships_RelationshipId", + column: x => x.RelationshipId, + principalTable: "Relationships", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipAuditLog_RelationshipId", + table: "RelationshipAuditLog", + column: "RelationshipId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RelationshipAuditLog"); + + migrationBuilder.DropColumn( + name: "AcceptanceContent", + table: "Relationships"); + + migrationBuilder.DropColumn( + name: "CreationContent", + table: "Relationships"); + + migrationBuilder.CreateTable( + name: "RelationshipChanges", + columns: table => new + { + Id = table.Column(type: "character varying(20)", maxLength: 20, nullable: false), + RelationshipId = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + Discriminator = table.Column(type: "character varying(34)", maxLength: 34, nullable: false), + Status = table.Column(type: "integer", nullable: false), + Type = table.Column(type: "integer", nullable: false), + Req_Content = table.Column(type: "bytea", nullable: true), + Req_CreatedAt = table.Column(type: "timestamp with time zone", nullable: false), + Req_CreatedBy = table.Column(type: "character(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: false), + Req_CreatedByDevice = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + Res_Content = table.Column(type: "bytea", nullable: true), + Res_CreatedAt = table.Column(type: "timestamp with time zone", nullable: true), + Res_CreatedBy = table.Column(type: "character(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: true), + Res_CreatedByDevice = table.Column(type: "character(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RelationshipChanges", x => x.Id); + table.ForeignKey( + name: "FK_RelationshipChanges_Relationships_RelationshipId", + column: x => x.RelationshipId, + principalTable: "Relationships", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipChanges_RelationshipId", + table: "RelationshipChanges", + column: "RelationshipId"); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipChanges_Res_CreatedAt_Res_CreatedBy_Res_Created~", + table: "RelationshipChanges", + columns: new[] { "Res_CreatedAt", "Res_CreatedBy", "Res_CreatedByDevice" }) + .Annotation("Npgsql:IndexInclude", new[] { "Res_Content" }); + } + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/RelationshipsDbContextModelSnapshot.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/RelationshipsDbContextModelSnapshot.cs index 30f0327ca6..8770ba3111 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/RelationshipsDbContextModelSnapshot.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.Postgres/Migrations/RelationshipsDbContextModelSnapshot.cs @@ -22,7 +22,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => { b.Property("Id") .HasMaxLength(20) @@ -30,158 +30,132 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character(20)") .IsFixedLength(); + b.Property("Content") + .HasColumnType("bytea"); + b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); - b.Property("From") + b.Property("CreatedBy") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("character(36)") .IsFixedLength(); - b.Property("RelationshipTemplateId") + b.Property("CreatedByDevice") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("character(20)") .IsFixedLength(); - b.Property("Status") - .HasColumnType("integer"); - - b.Property("To") - .IsRequired() - .HasMaxLength(36) - .IsUnicode(false) - .HasColumnType("character(36)") - .IsFixedLength(); - - b.HasKey("Id"); + b.Property("DeletedAt") + .HasColumnType("timestamp with time zone"); - b.HasIndex("From"); + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); - b.HasIndex("RelationshipTemplateId"); + b.Property("MaxNumberOfAllocations") + .HasColumnType("integer"); - b.HasIndex("To"); + b.HasKey("Id"); - b.ToTable("Relationships"); + b.ToTable("RelationshipTemplates"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => { - b.Property("Id") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); - b.Property("CreatedAt") + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllocatedAt") .HasColumnType("timestamp with time zone"); - b.Property("Discriminator") + b.Property("AllocatedBy") .IsRequired() - .HasMaxLength(34) - .HasColumnType("character varying(34)"); + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("character(36)") + .IsFixedLength(); - b.Property("RelationshipId") + b.Property("AllocatedByDevice") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("character(20)") .IsFixedLength(); - b.Property("Status") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); b.HasKey("Id"); - b.HasIndex("RelationshipId"); - - b.ToTable("RelationshipChanges", (string)null); - - b.HasDiscriminator("Discriminator").HasValue("RelationshipChange"); + b.HasIndex("RelationshipTemplateId", "AllocatedBy"); - b.UseTphMappingStrategy(); + b.ToTable("RelationshipTemplateAllocations", (string)null); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { b.Property("Id") .HasMaxLength(20) - .HasColumnType("character varying(20)"); + .IsUnicode(false) + .HasColumnType("character(20)") + .IsFixedLength(); - b.Property("Content") - .HasColumnType("bytea") - .HasColumnName("Req_Content"); + b.Property("AcceptanceContent") + .HasColumnType("bytea"); b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("Req_CreatedAt"); + .HasColumnType("timestamp with time zone"); - b.Property("CreatedBy") + b.Property("CreationContent") + .HasColumnType("bytea"); + + b.Property("From") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("character(36)") - .HasColumnName("Req_CreatedBy") .IsFixedLength(); - b.Property("CreatedByDevice") + b.Property("RelationshipTemplateId") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("character(20)") - .HasColumnName("Req_CreatedByDevice") .IsFixedLength(); - b.HasKey("Id"); - - b.ToTable("RelationshipChanges", (string)null); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", b => - { - b.Property("Id") - .HasMaxLength(20) - .HasColumnType("character varying(20)"); - - b.Property("Content") - .HasColumnType("bytea") - .HasColumnName("Res_Content"); - - b.Property("CreatedAt") - .HasColumnType("timestamp with time zone") - .HasColumnName("Res_CreatedAt"); + b.Property("Status") + .HasColumnType("integer"); - b.Property("CreatedBy") + b.Property("To") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("character(36)") - .HasColumnName("Res_CreatedBy") - .IsFixedLength(); - - b.Property("CreatedByDevice") - .IsRequired() - .HasMaxLength(20) - .IsUnicode(false) - .HasColumnType("character(20)") - .HasColumnName("Res_CreatedByDevice") .IsFixedLength(); b.HasKey("Id"); - b.HasIndex("CreatedAt", "CreatedBy", "CreatedByDevice") - .HasAnnotation("SqlServer:Include", new[] { "Content" }); + b.HasIndex("From"); + + b.HasIndex("RelationshipTemplateId"); - NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt", "CreatedBy", "CreatedByDevice"), new[] { "Content" }); + b.HasIndex("To"); - b.ToTable("RelationshipChanges", (string)null); + b.ToTable("Relationships"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => { b.Property("Id") .HasMaxLength(20) @@ -189,9 +163,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character(20)") .IsFixedLength(); - b.Property("Content") - .HasColumnType("bytea"); - b.Property("CreatedAt") .HasColumnType("timestamp with time zone"); @@ -209,47 +180,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("character(20)") .IsFixedLength(); - b.Property("DeletedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("ExpiresAt") - .HasColumnType("timestamp with time zone"); - - b.Property("MaxNumberOfAllocations") + b.Property("NewStatus") .HasColumnType("integer"); - b.HasKey("Id"); - - b.ToTable("RelationshipTemplates"); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplateAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() + b.Property("OldStatus") .HasColumnType("integer"); - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("AllocatedAt") - .HasColumnType("timestamp with time zone"); - - b.Property("AllocatedBy") - .IsRequired() - .HasMaxLength(36) - .IsUnicode(false) - .HasColumnType("character(36)") - .IsFixedLength(); - - b.Property("AllocatedByDevice") - .IsRequired() - .HasMaxLength(20) - .IsUnicode(false) - .HasColumnType("character(20)") - .IsFixedLength(); + b.Property("Reason") + .HasColumnType("integer"); - b.Property("RelationshipTemplateId") - .IsRequired() + b.Property("RelationshipId") .HasMaxLength(20) .IsUnicode(false) .HasColumnType("character(20)") @@ -257,32 +197,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("RelationshipTemplateId", "AllocatedBy"); - - b.ToTable("RelationshipTemplateAllocations", (string)null); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipCreationChange", b => - { - b.HasBaseType("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange"); - - b.ToTable("RelationshipChanges", (string)null); + b.HasIndex("RelationshipId"); - b.HasDiscriminator().HasValue("RelationshipCreationChange"); + b.ToTable("RelationshipAuditLog", (string)null); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTerminationChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => { - b.HasBaseType("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange"); - - b.ToTable("RelationshipChanges", (string)null); - - b.HasDiscriminator().HasValue("RelationshipTerminationChange"); + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", null) + .WithMany("Allocations") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", "RelationshipTemplate") + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", "RelationshipTemplate") .WithMany("Relationships") .HasForeignKey("RelationshipTemplateId") .OnDelete(DeleteBehavior.Restrict) @@ -291,62 +222,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("RelationshipTemplate"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.Relationship", "Relationship") - .WithMany("Changes") - .HasForeignKey("RelationshipId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Relationship"); + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", null) + .WithMany("AuditLog") + .HasForeignKey("RelationshipId"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", null) - .WithOne("Request") - .HasForeignKey("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", b => - { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", null) - .WithOne("Response") - .HasForeignKey("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplateAllocation", b => - { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", null) - .WithMany("Allocations") - .HasForeignKey("RelationshipTemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => - { - b.Navigation("Changes"); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => - { - b.Navigation("Request") - .IsRequired(); + b.Navigation("Allocations"); - b.Navigation("Response"); + b.Navigation("Relationships"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { - b.Navigation("Allocations"); - - b.Navigation("Relationships"); + b.Navigation("AuditLog"); }); #pragma warning restore 612, 618 } diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.Designer.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.Designer.cs new file mode 100644 index 0000000000..06307ed514 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.Designer.cs @@ -0,0 +1,249 @@ +// +using System; +using Backbone.Modules.Relationships.Infrastructure.Persistence.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Backbone.Modules.Relationships.Infrastructure.Database.SqlServer.Migrations +{ + [DbContext(typeof(RelationshipsDbContext))] + [Migration("20240412141504_RelationshipsRevamp")] + partial class RelationshipsRevamp + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("Content") + .HasColumnType("varbinary(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); + + b.Property("CreatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("DeletedAt") + .HasColumnType("datetime2"); + + b.Property("ExpiresAt") + .HasColumnType("datetime2"); + + b.Property("MaxNumberOfAllocations") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("RelationshipTemplates"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllocatedAt") + .HasColumnType("datetime2"); + + b.Property("AllocatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); + + b.Property("AllocatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("RelationshipTemplateId", "AllocatedBy"); + + b.ToTable("RelationshipTemplateAllocations", (string)null); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("AcceptanceContent") + .HasColumnType("varbinary(max)"); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreationContent") + .HasColumnType("varbinary(max)"); + + b.Property("From") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); + + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("Status") + .HasColumnType("int"); + + b.Property("To") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("From"); + + b.HasIndex("RelationshipTemplateId"); + + b.HasIndex("To"); + + b.ToTable("Relationships"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => + { + b.Property("Id") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("CreatedAt") + .HasColumnType("datetime2"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); + + b.Property("CreatedByDevice") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.Property("NewStatus") + .HasColumnType("int"); + + b.Property("OldStatus") + .HasColumnType("int"); + + b.Property("Reason") + .HasColumnType("int"); + + b.Property("RelationshipId") + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); + + b.HasKey("Id"); + + b.HasIndex("RelationshipId"); + + b.ToTable("RelationshipAuditLog", (string)null); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", null) + .WithMany("Allocations") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", "RelationshipTemplate") + .WithMany("Relationships") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Restrict) + .IsRequired(); + + b.Navigation("RelationshipTemplate"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => + { + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", null) + .WithMany("AuditLog") + .HasForeignKey("RelationshipId"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => + { + b.Navigation("Allocations"); + + b.Navigation("Relationships"); + }); + + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => + { + b.Navigation("AuditLog"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.cs new file mode 100644 index 0000000000..6dc9a49bd3 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/20240412141504_RelationshipsRevamp.cs @@ -0,0 +1,114 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Backbone.Modules.Relationships.Infrastructure.Database.SqlServer.Migrations +{ + /// + public partial class RelationshipsRevamp : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RelationshipChanges"); + + migrationBuilder.AddColumn( + name: "AcceptanceContent", + table: "Relationships", + type: "varbinary(max)", + nullable: true); + + migrationBuilder.AddColumn( + name: "CreationContent", + table: "Relationships", + type: "varbinary(max)", + nullable: true); + + migrationBuilder.CreateTable( + name: "RelationshipAuditLog", + columns: table => new + { + Id = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + Reason = table.Column(type: "int", nullable: false), + OldStatus = table.Column(type: "int", nullable: true), + NewStatus = table.Column(type: "int", nullable: false), + CreatedBy = table.Column(type: "char(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: false), + CreatedByDevice = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + RelationshipId = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RelationshipAuditLog", x => x.Id); + table.ForeignKey( + name: "FK_RelationshipAuditLog_Relationships_RelationshipId", + column: x => x.RelationshipId, + principalTable: "Relationships", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipAuditLog_RelationshipId", + table: "RelationshipAuditLog", + column: "RelationshipId"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RelationshipAuditLog"); + + migrationBuilder.DropColumn( + name: "AcceptanceContent", + table: "Relationships"); + + migrationBuilder.DropColumn( + name: "CreationContent", + table: "Relationships"); + + migrationBuilder.CreateTable( + name: "RelationshipChanges", + columns: table => new + { + Id = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: false), + RelationshipId = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + CreatedAt = table.Column(type: "datetime2", nullable: false), + Discriminator = table.Column(type: "nvarchar(34)", maxLength: 34, nullable: false), + Status = table.Column(type: "int", nullable: false), + Type = table.Column(type: "int", nullable: false), + Req_Content = table.Column(type: "varbinary(max)", nullable: true), + Req_CreatedAt = table.Column(type: "datetime2", nullable: false), + Req_CreatedBy = table.Column(type: "char(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: false), + Req_CreatedByDevice = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: false), + Res_Content = table.Column(type: "varbinary(max)", nullable: true), + Res_CreatedAt = table.Column(type: "datetime2", nullable: true), + Res_CreatedBy = table.Column(type: "char(36)", unicode: false, fixedLength: true, maxLength: 36, nullable: true), + Res_CreatedByDevice = table.Column(type: "char(20)", unicode: false, fixedLength: true, maxLength: 20, nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RelationshipChanges", x => x.Id); + table.ForeignKey( + name: "FK_RelationshipChanges_Relationships_RelationshipId", + column: x => x.RelationshipId, + principalTable: "Relationships", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipChanges_RelationshipId", + table: "RelationshipChanges", + column: "RelationshipId"); + + migrationBuilder.CreateIndex( + name: "IX_RelationshipChanges_Res_CreatedAt_Res_CreatedBy_Res_CreatedByDevice", + table: "RelationshipChanges", + columns: new[] { "Res_CreatedAt", "Res_CreatedBy", "Res_CreatedByDevice" }) + .Annotation("SqlServer:Include", new[] { "Res_Content" }); + } + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/ApplicationDbContextModelSnapshot.cs b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/RelationshipsDbContextModelSnapshot.cs similarity index 57% rename from Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/ApplicationDbContextModelSnapshot.cs rename to Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/RelationshipsDbContextModelSnapshot.cs index d5d5fca1a1..5ed03c1a51 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure.Database.SqlServer/Migrations/RelationshipsDbContextModelSnapshot.cs @@ -22,7 +22,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => { b.Property("Id") .HasMaxLength(20) @@ -30,158 +30,132 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("char(20)") .IsFixedLength(); + b.Property("Content") + .HasColumnType("varbinary(max)"); + b.Property("CreatedAt") .HasColumnType("datetime2"); - b.Property("From") + b.Property("CreatedBy") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("char(36)") .IsFixedLength(); - b.Property("RelationshipTemplateId") + b.Property("CreatedByDevice") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("char(20)") .IsFixedLength(); - b.Property("Status") - .HasColumnType("int"); - - b.Property("To") - .IsRequired() - .HasMaxLength(36) - .IsUnicode(false) - .HasColumnType("char(36)") - .IsFixedLength(); - - b.HasKey("Id"); + b.Property("DeletedAt") + .HasColumnType("datetime2"); - b.HasIndex("From"); + b.Property("ExpiresAt") + .HasColumnType("datetime2"); - b.HasIndex("RelationshipTemplateId"); + b.Property("MaxNumberOfAllocations") + .HasColumnType("int"); - b.HasIndex("To"); + b.HasKey("Id"); - b.ToTable("Relationships"); + b.ToTable("RelationshipTemplates"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => { - b.Property("Id") - .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); - b.Property("CreatedAt") + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AllocatedAt") .HasColumnType("datetime2"); - b.Property("Discriminator") + b.Property("AllocatedBy") .IsRequired() - .HasMaxLength(34) - .HasColumnType("nvarchar(34)"); + .HasMaxLength(36) + .IsUnicode(false) + .HasColumnType("char(36)") + .IsFixedLength(); - b.Property("RelationshipId") + b.Property("AllocatedByDevice") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("char(20)") .IsFixedLength(); - b.Property("Status") - .HasColumnType("int"); - - b.Property("Type") - .HasColumnType("int"); + b.Property("RelationshipTemplateId") + .IsRequired() + .HasMaxLength(20) + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); b.HasKey("Id"); - b.HasIndex("RelationshipId"); - - b.ToTable("RelationshipChanges", (string)null); - - b.HasDiscriminator("Discriminator").HasValue("RelationshipChange"); + b.HasIndex("RelationshipTemplateId", "AllocatedBy"); - b.UseTphMappingStrategy(); + b.ToTable("RelationshipTemplateAllocations", (string)null); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { b.Property("Id") .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); + .IsUnicode(false) + .HasColumnType("char(20)") + .IsFixedLength(); - b.Property("Content") - .HasColumnType("varbinary(max)") - .HasColumnName("Req_Content"); + b.Property("AcceptanceContent") + .HasColumnType("varbinary(max)"); b.Property("CreatedAt") - .HasColumnType("datetime2") - .HasColumnName("Req_CreatedAt"); + .HasColumnType("datetime2"); - b.Property("CreatedBy") + b.Property("CreationContent") + .HasColumnType("varbinary(max)"); + + b.Property("From") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("char(36)") - .HasColumnName("Req_CreatedBy") .IsFixedLength(); - b.Property("CreatedByDevice") + b.Property("RelationshipTemplateId") .IsRequired() .HasMaxLength(20) .IsUnicode(false) .HasColumnType("char(20)") - .HasColumnName("Req_CreatedByDevice") .IsFixedLength(); - b.HasKey("Id"); - - b.ToTable("RelationshipChanges", (string)null); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", b => - { - b.Property("Id") - .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); - - b.Property("Content") - .HasColumnType("varbinary(max)") - .HasColumnName("Res_Content"); - - b.Property("CreatedAt") - .HasColumnType("datetime2") - .HasColumnName("Res_CreatedAt"); + b.Property("Status") + .HasColumnType("int"); - b.Property("CreatedBy") + b.Property("To") .IsRequired() .HasMaxLength(36) .IsUnicode(false) .HasColumnType("char(36)") - .HasColumnName("Res_CreatedBy") - .IsFixedLength(); - - b.Property("CreatedByDevice") - .IsRequired() - .HasMaxLength(20) - .IsUnicode(false) - .HasColumnType("char(20)") - .HasColumnName("Res_CreatedByDevice") .IsFixedLength(); b.HasKey("Id"); - b.HasIndex("CreatedAt", "CreatedBy", "CreatedByDevice") - .HasAnnotation("Npgsql:IndexInclude", new[] { "Content" }); + b.HasIndex("From"); + + b.HasIndex("RelationshipTemplateId"); - SqlServerIndexBuilderExtensions.IncludeProperties(b.HasIndex("CreatedAt", "CreatedBy", "CreatedByDevice"), new[] { "Content" }); + b.HasIndex("To"); - b.ToTable("RelationshipChanges", (string)null); + b.ToTable("Relationships"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => { b.Property("Id") .HasMaxLength(20) @@ -189,9 +163,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("char(20)") .IsFixedLength(); - b.Property("Content") - .HasColumnType("varbinary(max)"); - b.Property("CreatedAt") .HasColumnType("datetime2"); @@ -209,47 +180,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("char(20)") .IsFixedLength(); - b.Property("DeletedAt") - .HasColumnType("datetime2"); - - b.Property("ExpiresAt") - .HasColumnType("datetime2"); - - b.Property("MaxNumberOfAllocations") + b.Property("NewStatus") .HasColumnType("int"); - b.HasKey("Id"); - - b.ToTable("RelationshipTemplates"); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplateAllocation", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() + b.Property("OldStatus") .HasColumnType("int"); - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AllocatedAt") - .HasColumnType("datetime2"); - - b.Property("AllocatedBy") - .IsRequired() - .HasMaxLength(36) - .IsUnicode(false) - .HasColumnType("char(36)") - .IsFixedLength(); - - b.Property("AllocatedByDevice") - .IsRequired() - .HasMaxLength(20) - .IsUnicode(false) - .HasColumnType("char(20)") - .IsFixedLength(); + b.Property("Reason") + .HasColumnType("int"); - b.Property("RelationshipTemplateId") - .IsRequired() + b.Property("RelationshipId") .HasMaxLength(20) .IsUnicode(false) .HasColumnType("char(20)") @@ -257,32 +197,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("RelationshipTemplateId", "AllocatedBy"); - - b.ToTable("RelationshipTemplateAllocations", (string)null); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipCreationChange", b => - { - b.HasBaseType("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange"); - - b.ToTable("RelationshipChanges", (string)null); + b.HasIndex("RelationshipId"); - b.HasDiscriminator().HasValue("RelationshipCreationChange"); + b.ToTable("RelationshipAuditLog", (string)null); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTerminationChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplateAllocation", b => { - b.HasBaseType("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange"); - - b.ToTable("RelationshipChanges", (string)null); - - b.HasDiscriminator().HasValue("RelationshipTerminationChange"); + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", null) + .WithMany("Allocations") + .HasForeignKey("RelationshipTemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", "RelationshipTemplate") + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", "RelationshipTemplate") .WithMany("Relationships") .HasForeignKey("RelationshipTemplateId") .OnDelete(DeleteBehavior.Restrict) @@ -291,62 +222,23 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("RelationshipTemplate"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.RelationshipAuditLogEntry", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.Relationship", "Relationship") - .WithMany("Changes") - .HasForeignKey("RelationshipId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Relationship"); + b.HasOne("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", null) + .WithMany("AuditLog") + .HasForeignKey("RelationshipId"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates.RelationshipTemplate", b => { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", null) - .WithOne("Request") - .HasForeignKey("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeRequest", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", b => - { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", null) - .WithOne("Response") - .HasForeignKey("Backbone.Modules.Relationships.Domain.Entities.RelationshipChangeResponse", "Id") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplateAllocation", b => - { - b.HasOne("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", null) - .WithMany("Allocations") - .HasForeignKey("RelationshipTemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.Relationship", b => - { - b.Navigation("Changes"); - }); - - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipChange", b => - { - b.Navigation("Request") - .IsRequired(); + b.Navigation("Allocations"); - b.Navigation("Response"); + b.Navigation("Relationships"); }); - modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Entities.RelationshipTemplate", b => + modelBuilder.Entity("Backbone.Modules.Relationships.Domain.Aggregates.Relationships.Relationship", b => { - b.Navigation("Allocations"); - - b.Navigation("Relationships"); + b.Navigation("AuditLog"); }); #pragma warning restore 612, 618 } diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipChangeQueryableExtensions.cs b/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipChangeQueryableExtensions.cs deleted file mode 100644 index b5c14c3ee7..0000000000 --- a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipChangeQueryableExtensions.cs +++ /dev/null @@ -1,98 +0,0 @@ -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; - -namespace Backbone.Modules.Relationships.Infrastructure.Extensions; - -public static class RelationshipChangeQueryableExtensions -{ - public static IQueryable CompletedAt(this IQueryable query, OptionalDateRange? completedAt) - { - var newQuery = query; - - if (completedAt == null) - return newQuery; - - if (completedAt.From.HasValue) - newQuery = newQuery.Where(r => r.Response != null && r.Response.CreatedAt >= completedAt.From); - - if (completedAt.To.HasValue) - newQuery = newQuery.Where(r => r.Response != null && r.Response.CreatedAt <= completedAt.To); - - return newQuery; - } - - public static IQueryable OnlyPeerChanges(this IQueryable query, IdentityAddress activeIdentity) - { - return query.Where(c => c.Request.CreatedBy != activeIdentity && c.Response == null || c.Response != null && c.Response.CreatedBy != activeIdentity); - } - - public static IQueryable WithIdIn(this IQueryable query, IEnumerable ids) - { - return query.Where(c => ids.Contains(c.Id)); - } - - public static IQueryable CreatedAt(this IQueryable query, OptionalDateRange createdAt) - { - var newQuery = query; - - if (createdAt.From != default) - newQuery = newQuery.Where(r => r.Request.CreatedAt >= createdAt.From); - - if (createdAt.To != default) - newQuery = newQuery.Where(r => r.Request.CreatedAt <= createdAt.To); - - return newQuery; - } - - public static IQueryable ModifiedAt(this IQueryable query, OptionalDateRange modifiedAt) - { - var newQuery = query; - - if (modifiedAt.From != default) - newQuery = newQuery.Where(c => c.Request.CreatedAt >= modifiedAt.From || - c.Response != null && c.Response.CreatedAt >= modifiedAt.From); - - if (modifiedAt.To != default) - newQuery = newQuery.Where(c => c.Request.CreatedAt <= modifiedAt.To || - c.Response != null && c.Response.CreatedAt <= modifiedAt.To); - - return newQuery; - } - - public static IQueryable Pending(this IQueryable query) - { - return query.Where(r => r.Status == RelationshipChangeStatus.Pending); - } - - public static IQueryable WithType(this IQueryable query, RelationshipChangeType type) - { - return query.Where(r => r.Type == type); - } - - public static IQueryable WithStatus(this IQueryable query, RelationshipChangeStatus status) - { - return query.Where(r => r.Status == status); - } - - public static IQueryable WithRelationshipParticipant(this IQueryable query, IdentityAddress identityAddress) - { - return query.Where(r => r.Relationship.From == identityAddress || r.Relationship.To == identityAddress); - } - - public static IQueryable CreatedBy(this IQueryable query, IdentityAddress identityId) - { - return query.Where(r => r.Request.CreatedBy == identityId); - } - - public static IQueryable CompletedBy(this IQueryable query, IdentityAddress identityId) - { - return query.Where(r => r.Response != null && r.Response.CreatedBy == identityId); - } - - public static IQueryable WithId(this IQueryable query, RelationshipChangeId id) - { - return query.Where(r => r.Id == id); - } -} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipQueryableExtensions.cs b/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipQueryableExtensions.cs index c088b4a786..9bf0ae3a2e 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipQueryableExtensions.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipQueryableExtensions.cs @@ -1,7 +1,6 @@ using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Microsoft.EntityFrameworkCore; namespace Backbone.Modules.Relationships.Infrastructure.Extensions; @@ -13,9 +12,9 @@ public static IQueryable BetweenParticipants(this IQueryable WithParticipant(this IQueryable query, IdentityAddress identityId) + public static IQueryable WithParticipant(this IQueryable query, IdentityAddress participantAddress) { - return query.Where(r => r.To == identityId || r.From == identityId); + return query.Where(Relationship.HasParticipant(participantAddress)); } public static IQueryable WithIdIn(this IQueryable query, IEnumerable ids) diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipTemplateQueryableExtensions.cs b/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipTemplateQueryableExtensions.cs index 0fe4e88888..e46b302c21 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipTemplateQueryableExtensions.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Extensions/RelationshipTemplateQueryableExtensions.cs @@ -1,7 +1,5 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Backbone.Tooling; using Microsoft.EntityFrameworkCore; @@ -9,9 +7,9 @@ namespace Backbone.Modules.Relationships.Infrastructure.Extensions; public static class RelationshipTemplateQueryableExtensions { - public static async Task FirstWithId(this IQueryable query, RelationshipTemplateId templateId, CancellationToken cancellationToken) + public static async Task FirstWithIdOrDefault(this IQueryable query, RelationshipTemplateId templateId, CancellationToken cancellationToken) { - var template = await query.FirstOrDefaultAsync(r => r.Id == templateId, cancellationToken) ?? throw new NotFoundException(nameof(RelationshipTemplate)); + var template = await query.FirstOrDefaultAsync(r => r.Id == templateId, cancellationToken); return template; } diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipAuditLogEntryEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipAuditLogEntryEntityTypeConfiguration.cs new file mode 100644 index 0000000000..9058a44e79 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipAuditLogEntryEntityTypeConfiguration.cs @@ -0,0 +1,21 @@ +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; + +public class RelationshipAuditLogEntryEntityTypeConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable("RelationshipAuditLog"); + builder.HasKey(x => x.Id); + + builder.Property(x => x.CreatedAt); + builder.Property(x => x.Reason); + builder.Property(x => x.OldStatus); + builder.Property(x => x.NewStatus); + builder.Property(x => x.CreatedBy); + builder.Property(x => x.CreatedByDevice); + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs deleted file mode 100644 index 824cd81d2c..0000000000 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeEntityTypeConfiguration.cs +++ /dev/null @@ -1,49 +0,0 @@ -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 void Configure(EntityTypeBuilder builder) - { - builder.ToTable("RelationshipChanges"); - - builder.Ignore(x => x.IsCompleted); - builder.Ignore(x => x.Request); - builder.Ignore(x => x.Response); - - builder.HasKey(x => x.Id); - - builder.Property(x => x.RelationshipId); - builder.Property(x => x.CreatedAt); - builder.Property(x => x.Type); - - builder.HasOne(x => x.Relationship).WithMany(x => x.Changes); - - builder - .HasOne(x => x.Request).WithOne() - .HasForeignKey(b => b.Id); - - builder - .HasOne(x => x.Response).WithOne() - .HasForeignKey(b => b.Id); - } -} - -public class RelationshipCreationChangeEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("RelationshipChanges"); - } -} - -public class RelationshipTerminationChangeEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("RelationshipChanges"); - } -} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeRequestEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeRequestEntityTypeConfiguration.cs deleted file mode 100644 index e724db53c2..0000000000 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeRequestEntityTypeConfiguration.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; - -public class RelationshipChangeRequestEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("RelationshipChanges"); - - builder.Property(x => x.CreatedBy) - .HasColumnName("Req_CreatedBy"); - - builder.Property(x => x.CreatedByDevice) - .HasColumnName("Req_CreatedByDevice"); - - builder.Property(x => x.CreatedAt) - .HasColumnName("Req_CreatedAt"); - - builder.Property(x => x.Content) - .HasColumnName("Req_Content"); - } -} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeResponseEntityTypeConfiguration.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeResponseEntityTypeConfiguration.cs deleted file mode 100644 index 33b1461edd..0000000000 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipChangeResponseEntityTypeConfiguration.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Entities; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.EntityTypeConfigurations; - -public class RelationshipChangeResponseEntityTypeConfiguration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.ToTable("RelationshipChanges"); - - var indexBuilder = builder.HasIndex(x => new { x.CreatedAt, x.CreatedBy, x.CreatedByDevice }); - NpgsqlIndexBuilderExtensions.IncludeProperties(indexBuilder, x => x.Content!); - SqlServerIndexBuilderExtensions.IncludeProperties(indexBuilder, x => x.Content); - - builder.Property(x => x.CreatedBy) - .HasColumnName("Res_CreatedBy"); - - builder.Property(x => x.CreatedByDevice) - .HasColumnName("Res_CreatedByDevice"); - - builder.Property(x => x.CreatedAt) - .HasColumnName("Res_CreatedAt"); - - builder.Property(x => x.Content) - .HasColumnName("Res_Content"); - } -} 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..7d3812d0aa 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipEntityTypeConfiguration.cs @@ -1,4 +1,4 @@ -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; @@ -16,6 +16,7 @@ public void Configure(EntityTypeBuilder builder) builder.Property(x => x.RelationshipTemplateId); builder.Property(x => x.CreatedAt); - builder.Metadata.FindNavigation(nameof(Relationship.Changes))!.SetPropertyAccessMode(PropertyAccessMode.Field); + builder.Property(x => x.CreationContent); + builder.Property(x => x.AcceptanceContent); } } 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..457e10c3b1 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateAllocationEntityTypeConfiguration.cs @@ -1,4 +1,4 @@ -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; 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..8e508d6884 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/EntityTypeConfigurations/RelationshipTemplateEntityTypeConfiguration.cs @@ -1,4 +1,4 @@ -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/RelationshipsDbContext.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/RelationshipsDbContext.cs index 84aad891e5..e35911e87a 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/RelationshipsDbContext.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/RelationshipsDbContext.cs @@ -1,6 +1,6 @@ using Backbone.BuildingBlocks.Infrastructure.Persistence.Database; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Backbone.Modules.Relationships.Infrastructure.Persistence.Database.ValueConverters; using Microsoft.EntityFrameworkCore; @@ -8,14 +8,19 @@ namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database; public class RelationshipsDbContext : AbstractDbContextBase { - public RelationshipsDbContext() { } + public RelationshipsDbContext() + { + } - public RelationshipsDbContext(DbContextOptions options) : base(options) { } + public RelationshipsDbContext(DbContextOptions options) : base(options) + { + } - public RelationshipsDbContext(DbContextOptions options, IServiceProvider serviceProvider) : base(options, serviceProvider) { } + public RelationshipsDbContext(DbContextOptions options, IServiceProvider serviceProvider) : base(options, serviceProvider) + { + } public DbSet Relationships { get; set; } = null!; - public DbSet RelationshipChanges { get; set; } = null!; public DbSet RelationshipTemplates { get; set; } = null!; public DbSet RelationshipTemplateAllocations { get; set; } = null!; @@ -30,10 +35,10 @@ protected override void ConfigureConventions(ModelConfigurationBuilder configura base.ConfigureConventions(configurationBuilder); configurationBuilder.Properties().AreUnicode(false).AreFixedLength().HaveMaxLength(RelationshipId.MAX_LENGTH).HaveConversion(); - configurationBuilder.Properties().AreUnicode(false).AreFixedLength().HaveMaxLength(RelationshipTemplateId.MAX_LENGTH).HaveConversion(); - - // Uncommenting the following means that we would have to recreate the table on the database, which is why we decided to leave RelationshipChangeIds in nvarchar(20) for now. - configurationBuilder.Properties().HaveMaxLength(RelationshipChangeId.MAX_LENGTH).HaveConversion(); //.AreFixedLength().AreUnicode(false) + configurationBuilder.Properties().AreUnicode(false).AreFixedLength().HaveMaxLength(RelationshipTemplateId.MAX_LENGTH) + .HaveConversion(); + configurationBuilder.Properties().AreUnicode(false).AreFixedLength().HaveMaxLength(RelationshipAuditLogEntryId.MAX_LENGTH) + .HaveConversion(); } protected override void OnModelCreating(ModelBuilder builder) diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipTemplatesRepository.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipTemplatesRepository.cs index 86baee66b5..af361efa67 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipTemplatesRepository.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipTemplatesRepository.cs @@ -4,12 +4,12 @@ using Backbone.BuildingBlocks.Application.Pagination; using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Backbone.Modules.Relationships.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.Repository; + public class RelationshipTemplatesRepository : IRelationshipTemplatesRepository { private readonly DbSet _templates; @@ -36,24 +36,25 @@ public async Task Delete(Expression> filter, Ca await _templates.Where(filter).ExecuteDeleteAsync(cancellationToken); } - public async Task Find(RelationshipTemplateId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false, bool fillContent = true) + public async Task Find(RelationshipTemplateId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false) { var template = await (track ? _templates : _readOnlyTemplates) - .Include(r => r.Allocations) - .NotExpiredFor(identityAddress) - .NotDeleted() - .FirstWithId(id, cancellationToken); + .Include(r => r.Allocations) + .NotExpiredFor(identityAddress) + .NotDeleted() + .FirstWithIdOrDefault(id, cancellationToken); return template; } - public async Task> FindTemplatesWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, CancellationToken cancellationToken, bool track = false) + public async Task> FindTemplatesWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, + CancellationToken cancellationToken, bool track = false) { var query = (track ? _templates : _readOnlyTemplates) - .AsQueryable() - .NotExpiredFor(identityAddress) - .NotDeleted() - .WithIdIn(ids); + .AsQueryable() + .NotExpiredFor(identityAddress) + .NotDeleted() + .WithIdIn(ids); var templates = await query.OrderAndPaginate(d => d.CreatedAt, paginationFilter, cancellationToken); diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipsRepository.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipsRepository.cs index 22565afdc3..e28f6a1cf7 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipsRepository.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/Repository/RelationshipsRepository.cs @@ -1,15 +1,13 @@ using System.Linq.Expressions; -using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.Persistence.Database; using Backbone.BuildingBlocks.Application.Extensions; using Backbone.BuildingBlocks.Application.Pagination; +using Backbone.BuildingBlocks.Domain; using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Application; using Backbone.Modules.Relationships.Application.Infrastructure; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; -using Backbone.Modules.Relationships.Common; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Backbone.Modules.Relationships.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; @@ -18,55 +16,16 @@ namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.Rep public class RelationshipsRepository : IRelationshipsRepository { private readonly DbSet _relationships; - private readonly DbSet _changes; private readonly IQueryable _readOnlyRelationships; - private readonly IQueryable _readOnlyChanges; private readonly RelationshipsDbContext _dbContext; public RelationshipsRepository(RelationshipsDbContext dbContext) { _relationships = dbContext.Relationships; _readOnlyRelationships = dbContext.Relationships.AsNoTracking(); - _changes = dbContext.RelationshipChanges; - _readOnlyChanges = dbContext.RelationshipChanges.AsNoTracking(); _dbContext = dbContext; } - public async Task> FindChangesWithIds(IEnumerable ids, - RelationshipChangeType? relationshipChangeType, RelationshipChangeStatus? relationshipChangeStatus, - OptionalDateRange? modifiedAt, OptionalDateRange? createdAt, OptionalDateRange? completedAt, - IdentityAddress? createdBy, IdentityAddress? completedBy, IdentityAddress activeIdentity, - PaginationFilter paginationFilter, CancellationToken cancellationToken, bool onlyPeerChanges = false, bool track = false) - { - var query = (track ? _changes : _readOnlyChanges) - .AsQueryable() - .IncludeAll(_dbContext) - .WithRelationshipParticipant(activeIdentity); - - if (relationshipChangeType.HasValue) - query = query.WithType(relationshipChangeType.Value); - if (relationshipChangeStatus.HasValue) - query = query.WithStatus(relationshipChangeStatus.Value); - if (modifiedAt != null) - query = query.ModifiedAt(modifiedAt); - if (createdAt != null) - query = query.CreatedAt(createdAt); - if (completedAt != null) - query = query.CompletedAt(completedAt); - if (createdBy != null) - query = query.CreatedBy(createdBy); - if (completedBy != null) - query = query.CompletedBy(completedBy); - if (ids.Any()) - query = query.WithIdIn(ids); - if (onlyPeerChanges) - query = query.OnlyPeerChanges(activeIdentity); - - var changes = await query.OrderAndPaginate(d => d.CreatedAt, paginationFilter, cancellationToken); - - return changes; - } - public async Task FindRelationship(RelationshipId id, IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false) { @@ -78,18 +37,6 @@ public async Task FindRelationship(RelationshipId id, IdentityAddr return relationship; } - public async Task FindRelationshipChange(RelationshipChangeId id, - IdentityAddress identityAddress, CancellationToken cancellationToken, bool track = false) - { - var change = await (track ? _changes : _readOnlyChanges) - .IncludeAll(_dbContext) - .WithId(id) - .WithRelationshipParticipant(identityAddress) - .FirstOrDefaultAsync(cancellationToken); - - return change; - } - public async Task> FindRelationshipsWithIds(IEnumerable ids, IdentityAddress identityAddress, PaginationFilter paginationFilter, CancellationToken cancellationToken, bool track = false) { @@ -121,7 +68,7 @@ public async Task Add(Relationship relationship, CancellationToken cancellationT catch (DbUpdateException ex) { if (ex.InnerException != null && ex.InnerException.Message.Contains(ConstraintNames.ONLY_ONE_ACTIVE_RELATIONSHIP_BETWEEN_TWO_IDENTITIES)) - throw new OperationFailedException(ApplicationErrors.Relationship.RelationshipToTargetAlreadyExists(relationship.To)); + throw new DomainException(DomainErrors.RelationshipToTargetAlreadyExists(relationship.To)); throw; } @@ -132,8 +79,7 @@ public async Task RelationshipBetweenTwoIdentitiesExists(IdentityAddress i { return await _readOnlyRelationships .BetweenParticipants(identityAddressA, identityAddressB) - .Where(r => r.Status != RelationshipStatus.Terminated && r.Status != RelationshipStatus.Rejected && - r.Status != RelationshipStatus.Revoked) + .Where(Relationship.CountsAsActive()) .AnyAsync(cancellationToken); } diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipAuditLogEntryIdEntityFrameworkValueConverter.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipAuditLogEntryIdEntityFrameworkValueConverter.cs new file mode 100644 index 0000000000..a3318c4321 --- /dev/null +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipAuditLogEntryIdEntityFrameworkValueConverter.cs @@ -0,0 +1,20 @@ +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.ValueConverters; + +public class RelationshipAuditLogEntryIdEntityFrameworkValueConverter : ValueConverter +{ + public RelationshipAuditLogEntryIdEntityFrameworkValueConverter() : this(null) + { + } + + public RelationshipAuditLogEntryIdEntityFrameworkValueConverter(ConverterMappingHints? mappingHints) + : base( + id => id.StringValue, + value => RelationshipAuditLogEntryId.Parse(value), + mappingHints + ) + { + } +} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipChangeIdEntityFrameworkValueConverter.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipChangeIdEntityFrameworkValueConverter.cs deleted file mode 100644 index 3a8c0eb413..0000000000 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipChangeIdEntityFrameworkValueConverter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Ids; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; - -namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.ValueConverters; - -public class RelationshipChangeIdEntityFrameworkValueConverter : ValueConverter -{ - public RelationshipChangeIdEntityFrameworkValueConverter() : this(null) { } - - public RelationshipChangeIdEntityFrameworkValueConverter(ConverterMappingHints? mappingHints) - : base( - id => id.StringValue, - value => RelationshipChangeId.Parse(value), - mappingHints - ) - { } -} diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipIdEntityFrameworkValueConverter.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipIdEntityFrameworkValueConverter.cs index c2969bc9d8..4e869b2ec7 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipIdEntityFrameworkValueConverter.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipIdEntityFrameworkValueConverter.cs @@ -1,11 +1,13 @@ -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.ValueConverters; public class RelationshipIdEntityFrameworkValueConverter : ValueConverter { - public RelationshipIdEntityFrameworkValueConverter() : this(null) { } + public RelationshipIdEntityFrameworkValueConverter() : this(null) + { + } public RelationshipIdEntityFrameworkValueConverter(ConverterMappingHints? mappingHints) : base( @@ -13,5 +15,6 @@ public RelationshipIdEntityFrameworkValueConverter(ConverterMappingHints? mappin value => RelationshipId.Parse(value), mappingHints ) - { } + { + } } diff --git a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipTemplateIdEntityFrameworkValueConverter.cs b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipTemplateIdEntityFrameworkValueConverter.cs index 0ee749095f..645647a24a 100644 --- a/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipTemplateIdEntityFrameworkValueConverter.cs +++ b/Modules/Relationships/src/Relationships.Infrastructure/Persistence/Database/ValueConverters/RelationshipTemplateIdEntityFrameworkValueConverter.cs @@ -1,11 +1,13 @@ -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Backbone.Modules.Relationships.Infrastructure.Persistence.Database.ValueConverters; public class RelationshipTemplateIdEntityFrameworkValueConverter : ValueConverter { - public RelationshipTemplateIdEntityFrameworkValueConverter() : this(null) { } + public RelationshipTemplateIdEntityFrameworkValueConverter() : this(null) + { + } public RelationshipTemplateIdEntityFrameworkValueConverter(ConverterMappingHints? mappingHints) : base( @@ -13,5 +15,6 @@ public RelationshipTemplateIdEntityFrameworkValueConverter(ConverterMappingHints value => RelationshipTemplateId.Parse(value), mappingHints ) - { } + { + } } diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Extensions/RelationshipTemplateQueryableExtensionsTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Extensions/RelationshipTemplateQueryableExtensionsTests.cs index 7a3cd4d690..1403be10fc 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Extensions/RelationshipTemplateQueryableExtensionsTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Extensions/RelationshipTemplateQueryableExtensionsTests.cs @@ -1,7 +1,9 @@ using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Backbone.Modules.Relationships.Infrastructure.Extensions; using Backbone.Modules.Relationships.Infrastructure.Persistence.Database; +using Backbone.UnitTestTools.Data; using Backbone.UnitTestTools.TestDoubles.Fakes; using FluentAssertions; using Xunit; @@ -29,14 +31,12 @@ public void NotExpiredFor_DoesNotFilterOutTemplatesForParticipants() var requestCreator = IdentityAddress.Create(new byte[5], "id0"); var template = new RelationshipTemplate(templateCreator, DeviceId.New(), 1, YESTERDAY, new byte[2]); - var relationship = new Relationship(template, requestCreator, DeviceId.New(), new byte[2]); - + var relationship = new Relationship(template, requestCreator, DeviceId.New(), new byte[2], []); _arrangeContext.RelationshipTemplates.Add(template); _arrangeContext.Relationships.Add(relationship); _arrangeContext.SaveChanges(); - // Act var result = _actContext .RelationshipTemplates @@ -44,7 +44,6 @@ public void NotExpiredFor_DoesNotFilterOutTemplatesForParticipants() .NotExpiredFor(templateCreator) .ToList(); - // Assert result.Should().HaveCount(1); } @@ -56,9 +55,8 @@ public void NotExpiredFor_DoesNotFilterOutTemplatesWithoutExpiryDate() var templateCreator = CreateRandomIdentityAddress(); var requestCreator = CreateRandomIdentityAddress(); - var template = new RelationshipTemplate(templateCreator, DeviceId.New(), 1, null, CreateRandomBytes()); - var relationship = new Relationship(template, requestCreator, DeviceId.New(), CreateRandomBytes()); - + var template = new RelationshipTemplate(templateCreator, DeviceId.New(), 1, null, TestDataGenerator.CreateRandomBytes()); + var relationship = new Relationship(template, requestCreator, DeviceId.New(), TestDataGenerator.CreateRandomBytes(), []); _arrangeContext.RelationshipTemplates.Add(template); _arrangeContext.Relationships.Add(relationship); @@ -86,8 +84,8 @@ public void NotExpiredFor_FiltersOutExpiredTemplatesForNonParticipants() var templateCreator = CreateRandomIdentityAddress(); var requestCreator = CreateRandomIdentityAddress(); - var template = new RelationshipTemplate(templateCreator, DeviceId.New(), 1, YESTERDAY, CreateRandomBytes()); - var relationship = new Relationship(template, requestCreator, DeviceId.New(), CreateRandomBytes()); + var template = new RelationshipTemplate(templateCreator, DeviceId.New(), 1, YESTERDAY, TestDataGenerator.CreateRandomBytes()); + var relationship = new Relationship(template, requestCreator, DeviceId.New(), TestDataGenerator.CreateRandomBytes(), []); _arrangeContext.RelationshipTemplates.Add(template); diff --git a/Modules/Relationships/test/Relationships.Application.Tests/TestHelpers/TestData.cs b/Modules/Relationships/test/Relationships.Application.Tests/TestHelpers/TestData.cs new file mode 100644 index 0000000000..b37e479be0 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Application.Tests/TestHelpers/TestData.cs @@ -0,0 +1,28 @@ +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; +using Backbone.UnitTestTools.Data; + +namespace Backbone.Modules.Relationships.Application.Tests.TestHelpers; + +public static class TestData +{ + public static Relationship CreatePendingRelationship(IdentityAddress? from = null, IdentityAddress? to = null) + { + from ??= TestDataGenerator.CreateRandomIdentityAddress(); + return new Relationship(CreateRelationshipTemplate(createdBy: to), from, TestDataGenerator.CreateRandomDeviceId(), null, []); + } + + public static RelationshipTemplate CreateRelationshipTemplate(IdentityAddress? createdBy = null) + { + createdBy ??= TestDataGenerator.CreateRandomIdentityAddress(); + return new RelationshipTemplate(createdBy, TestDataGenerator.CreateRandomDeviceId(), 1, null, []); + } + + public static Relationship CreateActiveRelationship() + { + var relationship = new Relationship(CreateRelationshipTemplate(), TestDataGenerator.CreateRandomIdentityAddress(), TestDataGenerator.CreateRandomDeviceId(), null, []); + relationship.Accept(TestDataGenerator.CreateRandomIdentityAddress(), TestDataGenerator.CreateRandomDeviceId(), []); + return relationship; + } +} 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 index 6c57fa41f4..7b0b03f1f7 100644 --- 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 @@ -5,12 +5,13 @@ using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.IntegrationEvents.Outgoing; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.CreateRelationshipTemplate; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using FakeItEasy; using FluentAssertions.Execution; using Xunit; namespace Backbone.Modules.Relationships.Application.Tests.Tests.RelationshipTemplates.Commands.CreateRelationshipTemplate; + public class HandlerTests { private readonly IUserContext _userContext; diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesValidatorTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesValidatorTests.cs index d892f9ff89..650bdfe366 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesValidatorTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/RelationshipTemplates/Queries/ListRelationshipTemplates/ListRelationshipTemplatesValidatorTests.cs @@ -1,6 +1,6 @@ using Backbone.BuildingBlocks.Application.Pagination; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Queries.ListRelationshipTemplates; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using FluentAssertions; using FluentValidation.TestHelper; using Xunit; diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AcceptRelationship/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AcceptRelationship/HandlerTests.cs new file mode 100644 index 0000000000..1743860f0c --- /dev/null +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AcceptRelationship/HandlerTests.cs @@ -0,0 +1,119 @@ +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.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Application.Relationships.Commands.AcceptRelationship; +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Application.Tests.TestHelpers; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.UnitTestTools.Data; +using FakeItEasy; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Relationships.Application.Tests.Tests.Relationships.Commands.AcceptRelationship; + +public class HandlerTests +{ + [Fact] + public async Task Returns_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository); + + // Act + var response = await handler.Handle(new AcceptRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + response.Id.Should().NotBeNull(); + response.Status.Should().Be(RelationshipStatus.Active); + response.AuditLog.Should().HaveCount(2); + } + + [Fact] + public async Task Saves_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var mockRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => mockRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, mockRelationshipsRepository); + + // Act + await handler.Handle(new AcceptRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockRelationshipsRepository.Update( + A.That.Matches(r => r.Id == relationship.Id && r.Status == RelationshipStatus.Active)) + ) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Publishes_RelationshipStatusChangedIntegrationEvent() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var mockEventBus = A.Fake(); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository, mockEventBus); + + // Act + await handler.Handle(new AcceptRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockEventBus.Publish(A.That.Matches(e => + e.RelationshipId == relationship.Id && + e.Status == RelationshipStatus.Active.ToDtoString() && + e.Initiator == activeIdentity && + e.Peer == relationship.From) + )) + .MustHaveHappenedOnceExactly(); + } + + private static Handler CreateHandler(IUserContext userContext, IRelationshipsRepository relationshipsRepository, IEventBus? eventBus = null) + { + eventBus ??= A.Fake(); + return new Handler(relationshipsRepository, userContext, eventBus); + } +} diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/HandlerTests.cs index 56a7e245b2..fe2247bc6f 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/HandlerTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity/HandlerTests.cs @@ -2,8 +2,7 @@ using Backbone.DevelopmentKit.Identity.ValueObjects; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.AnonymizeRelationshipTemplateAllocationsAllocatedByIdentity; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using Backbone.UnitTestTools.Data; using FakeItEasy; using Xunit; diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/CreateRelationship/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/CreateRelationship/HandlerTests.cs new file mode 100644 index 0000000000..d7a4aa1d1e --- /dev/null +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/CreateRelationship/HandlerTests.cs @@ -0,0 +1,189 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Exceptions; +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.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Application.Relationships.Commands.CreateRelationship; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; +using Backbone.Tooling; +using Backbone.UnitTestTools.Data; +using Backbone.UnitTestTools.Extensions; +using FakeItEasy; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Relationships.Application.Tests.Tests.Relationships.Commands.CreateRelationship; + +public class HandlerTests +{ + [Fact] + public async Task Saves_the_created_relationship() + { + // Arrange + SystemTime.Set("2020-01-01"); + var activeIdentity = IdentityAddress.Create([0], "id1"); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipTemplatesRepository = A.Fake(); + var relationshipTemplate = new RelationshipTemplate( + TestDataGenerator.CreateRandomIdentityAddress(), + TestDataGenerator.CreateRandomDeviceId(), + 1, + DateTime.Parse("2021-01-01"), + [] + ); + A.CallTo(() => fakeRelationshipTemplatesRepository.Find(relationshipTemplate.Id, activeIdentity, A._, A._)) + .Returns(relationshipTemplate); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var mockRelationshipsRepository = A.Fake(); + + var handler = CreateHandler(fakeRelationshipTemplatesRepository, fakeUserContext, mockRelationshipsRepository); + + // Act + await handler.Handle(new CreateRelationshipCommand + { + RelationshipTemplateId = relationshipTemplate.Id + }, CancellationToken.None); + + // Assert + A.CallTo(() => mockRelationshipsRepository.Add(A._, A._)).MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Returns_data_of_created_relationship() + { + // Arrange + SystemTime.Set("2020-01-01"); + var activeIdentity = IdentityAddress.Create([0], "id1"); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipTemplatesRepository = A.Fake(); + var relationshipTemplate = new RelationshipTemplate( + TestDataGenerator.CreateRandomIdentityAddress(), + TestDataGenerator.CreateRandomDeviceId(), + 1, + DateTime.Parse("2021-01-01"), + [] + ); + A.CallTo(() => fakeRelationshipTemplatesRepository.Find(relationshipTemplate.Id, activeIdentity, A._, A._)) + .Returns(relationshipTemplate); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeRelationshipTemplatesRepository, fakeUserContext); + + // Act + var response = await handler.Handle(new CreateRelationshipCommand + { + RelationshipTemplateId = relationshipTemplate.Id + }, CancellationToken.None); + + // Assert + response.Id.Should().NotBeNull(); + response.RelationshipTemplateId.Should().Be(relationshipTemplate.Id); + response.From.Should().Be(activeIdentity); + response.To.Should().Be(relationshipTemplate.CreatedBy); + response.CreatedAt.Should().Be(SystemTime.UtcNow); + response.Status.Should().Be(RelationshipStatus.Pending); + response.AuditLog.Should().HaveCount(1); + } + + [Fact] + public void Throws_when_no_template_with_given_id_exists() + { + // Arrange + var relationshipTemplateId = RelationshipTemplateId.Parse("RLTNonExistingReltId"); + var address = IdentityAddress.Create([0], "id1"); + + var relationshipTemplatesRepository = A.Fake(); + A.CallTo(() => relationshipTemplatesRepository.Find(relationshipTemplateId, address, A._, A._)) + .Returns(null); + + var handler = CreateHandler(relationshipTemplatesRepository); + + // Act + var acting = () => handler.Handle(new CreateRelationshipCommand + { + RelationshipTemplateId = relationshipTemplateId + }, CancellationToken.None); + + // Assert + acting.Should().AwaitThrowAsync().Which.Message.Should().Contain("RelationshipTemplate"); + } + + [Fact] + public async Task Publishes_RelationshipCreatedIntegrationEvent() + { + // Arrange + SystemTime.Set("2020-01-01"); + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipTemplatesRepository = A.Fake(); + var relationshipTemplate = new RelationshipTemplate( + TestDataGenerator.CreateRandomIdentityAddress(), + TestDataGenerator.CreateRandomDeviceId(), + 1, + DateTime.Parse("2021-01-01"), + [] + ); + A.CallTo(() => fakeRelationshipTemplatesRepository.Find(relationshipTemplate.Id, activeIdentity, A._, A._)) + .Returns(relationshipTemplate); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var mockEventBus = A.Fake(); + + var handler = CreateHandler(fakeRelationshipTemplatesRepository, fakeUserContext, mockEventBus); + + // Act + await handler.Handle(new CreateRelationshipCommand + { + RelationshipTemplateId = relationshipTemplate.Id + }, CancellationToken.None); + + // Assert + A.CallTo(() => mockEventBus.Publish(A.That.Matches(e => e.From == activeIdentity, relationshipTemplate.CreatedBy))).MustHaveHappenedOnceExactly(); + } + + private static Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository) + { + return CreateHandler(relationshipTemplatesRepository, null, null, null); + } + + private static Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository, IUserContext userContext, IEventBus eventBus) + { + return CreateHandler(relationshipTemplatesRepository, userContext, eventBus, null); + } + + private static Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository, IUserContext userContext) + { + return CreateHandler(relationshipTemplatesRepository, userContext, null, null); + } + + private static Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository, IUserContext userContext, IRelationshipsRepository relationshipsRepository) + { + return CreateHandler(relationshipTemplatesRepository, userContext, null, relationshipsRepository); + } + + private static Handler CreateHandler(IRelationshipTemplatesRepository relationshipTemplatesRepository, IUserContext? userContext, IEventBus? eventBus, + IRelationshipsRepository? relationshipsRepository) + { + userContext ??= A.Dummy(); + eventBus ??= A.Dummy(); + relationshipsRepository ??= A.Dummy(); + + var handler = new Handler(userContext, eventBus, relationshipsRepository, relationshipTemplatesRepository); + return handler; + } +} diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipTemplatesByIdentity/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipTemplatesByIdentity/HandlerTests.cs index fd39436dac..45dd1af926 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipTemplatesByIdentity/HandlerTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipTemplatesByIdentity/HandlerTests.cs @@ -1,7 +1,7 @@ using System.Linq.Expressions; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.RelationshipTemplates.Commands.DeleteRelationshipTemplatesOfIdentity; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; using FakeItEasy; using Xunit; diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipsByIdentity/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipsByIdentity/HandlerTests.cs index 59c13180cd..7f0286d473 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipsByIdentity/HandlerTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/DeleteRelationshipsByIdentity/HandlerTests.cs @@ -1,7 +1,7 @@ using System.Linq.Expressions; using Backbone.Modules.Relationships.Application.Infrastructure.Persistence.Repository; using Backbone.Modules.Relationships.Application.Relationships.Commands.DeleteRelationshipsOfIdentity; -using Backbone.Modules.Relationships.Domain.Entities; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using FakeItEasy; using Xunit; diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RejectRelationship/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RejectRelationship/HandlerTests.cs new file mode 100644 index 0000000000..3e3e7dfc59 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RejectRelationship/HandlerTests.cs @@ -0,0 +1,119 @@ +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.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Application.Relationships.Commands.RejectRelationship; +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Application.Tests.TestHelpers; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.UnitTestTools.Data; +using FakeItEasy; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Relationships.Application.Tests.Tests.Relationships.Commands.RejectRelationship; + +public class HandlerTests +{ + [Fact] + public async Task Returns_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository); + + // Act + var response = await handler.Handle(new RejectRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + response.Id.Should().NotBeNull(); + response.Status.Should().Be(RelationshipStatus.Rejected); + response.AuditLog.Should().HaveCount(2); + } + + [Fact] + public async Task Saves_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var mockRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => mockRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, mockRelationshipsRepository); + + // Act + await handler.Handle(new RejectRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockRelationshipsRepository.Update( + A.That.Matches(r => r.Id == relationship.Id && r.Status == RelationshipStatus.Rejected)) + ) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Publishes_RelationshipStatusChangedIntegrationEvent() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(to: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var mockEventBus = A.Fake(); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository, mockEventBus); + + // Act + await handler.Handle(new RejectRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockEventBus.Publish(A.That.Matches(e => + e.RelationshipId == relationship.Id && + e.Status == RelationshipStatus.Rejected.ToDtoString() && + e.Initiator == activeIdentity && + e.Peer == relationship.From) + )) + .MustHaveHappenedOnceExactly(); + } + + private static Handler CreateHandler(IUserContext userContext, IRelationshipsRepository relationshipsRepository, IEventBus? eventBus = null) + { + eventBus ??= A.Fake(); + return new Handler(relationshipsRepository, userContext, eventBus); + } +} diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RevokeRelationship/HandlerTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RevokeRelationship/HandlerTests.cs new file mode 100644 index 0000000000..635332d226 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Commands/RevokeRelationship/HandlerTests.cs @@ -0,0 +1,119 @@ +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.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Relationships.Application.Relationships.Commands.RevokeRelationship; +using Backbone.Modules.Relationships.Application.Relationships.DTOs; +using Backbone.Modules.Relationships.Application.Tests.TestHelpers; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.UnitTestTools.Data; +using FakeItEasy; +using FluentAssertions; +using Xunit; + +namespace Backbone.Modules.Relationships.Application.Tests.Tests.Relationships.Commands.RevokeRelationship; + +public class HandlerTests +{ + [Fact] + public async Task Returns_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(from: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository); + + // Act + var response = await handler.Handle(new RevokeRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + response.Id.Should().NotBeNull(); + response.Status.Should().Be(RelationshipStatus.Revoked); + response.AuditLog.Should().HaveCount(2); + } + + [Fact] + public async Task Saves_the_updated_relationship() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var mockRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(from: activeIdentity); + A.CallTo(() => mockRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var handler = CreateHandler(fakeUserContext, mockRelationshipsRepository); + + // Act + await handler.Handle(new RevokeRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockRelationshipsRepository.Update( + A.That.Matches(r => r.Id == relationship.Id && r.Status == RelationshipStatus.Revoked)) + ) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Publishes_RelationshipStatusChangedIntegrationEvent() + { + // Arrange + var activeIdentity = TestDataGenerator.CreateRandomIdentityAddress(); + var activeDevice = TestDataGenerator.CreateRandomDeviceId(); + + var fakeRelationshipsRepository = A.Fake(); + var relationship = TestData.CreatePendingRelationship(from: activeIdentity); + A.CallTo(() => fakeRelationshipsRepository.FindRelationship(relationship.Id, activeIdentity, A._, true)).Returns(relationship); + + var fakeUserContext = A.Fake(); + A.CallTo(() => fakeUserContext.GetAddress()).Returns(activeIdentity); + A.CallTo(() => fakeUserContext.GetDeviceId()).Returns(activeDevice); + + var mockEventBus = A.Fake(); + + var handler = CreateHandler(fakeUserContext, fakeRelationshipsRepository, mockEventBus); + + // Act + await handler.Handle(new RevokeRelationshipCommand + { + RelationshipId = relationship.Id + }, CancellationToken.None); + + // Assert + A.CallTo( + () => mockEventBus.Publish(A.That.Matches(e => + e.RelationshipId == relationship.Id && + e.Status == RelationshipStatus.Revoked.ToDtoString() && + e.Initiator == activeIdentity && + e.Peer == relationship.To) + )) + .MustHaveHappenedOnceExactly(); + } + + private static Handler CreateHandler(IUserContext userContext, IRelationshipsRepository relationshipsRepository, IEventBus? eventBus = null) + { + eventBus ??= A.Fake(); + return new Handler(relationshipsRepository, userContext, eventBus); + } +} diff --git a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Queries/ListRelationshipsValidatorTests.cs b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Queries/ListRelationshipsValidatorTests.cs index 4d9c7e6b1b..ca90d8b9b8 100644 --- a/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Queries/ListRelationshipsValidatorTests.cs +++ b/Modules/Relationships/test/Relationships.Application.Tests/Tests/Relationships/Queries/ListRelationshipsValidatorTests.cs @@ -1,6 +1,6 @@ using Backbone.BuildingBlocks.Application.Pagination; using Backbone.Modules.Relationships.Application.Relationships.Queries.ListRelationships; -using Backbone.Modules.Relationships.Domain.Ids; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; using FluentAssertions; using FluentValidation.TestHelper; using Xunit; diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/ExceptionAssertionsExtensions.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/ExceptionAssertionsExtensions.cs index 262e6d0083..2abac723c3 100644 --- a/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/ExceptionAssertionsExtensions.cs +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/ExceptionAssertionsExtensions.cs @@ -1,5 +1,4 @@ using Backbone.BuildingBlocks.Domain; -using Backbone.BuildingBlocks.Domain.Errors; using FluentAssertions; using FluentAssertions.Specialized; @@ -7,8 +6,13 @@ namespace Backbone.Modules.Relationships.Domain.Tests.Extensions; public static class ExceptionAssertionsExtensions { - public static void WithError(this ExceptionAssertions exceptionAssertions, DomainError error) where T : DomainException + public static void WithError(this ExceptionAssertions exceptionAssertions, string code, string? messagePart = null) where T : DomainException { - exceptionAssertions.Which.Code.Should().Be(error.Code); + var exception = exceptionAssertions.Which; + + exception.Code.Should().Be(code); + + if (messagePart != null) + exception.Message.Should().Contain(messagePart); } } diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/IChangeLogExtensions.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/IChangeLogExtensions.cs deleted file mode 100644 index dc0d86c587..0000000000 --- a/Modules/Relationships/test/Relationships.Domain.Tests/Extensions/IChangeLogExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Backbone.Modules.Relationships.Domain.Entities; - -namespace Backbone.Modules.Relationships.Domain.Tests.Extensions; - -public static class IChangeLogExtensions -{ - public static RelationshipChange? GetOpenCreation(this IRelationshipChangeLog changes) - { - return changes.GetLatestOfTypeOrNull(RelationshipChangeType.Creation, c => !c.IsCompleted); - } - - public static RelationshipChange? GetOpenTermination(this IRelationshipChangeLog changes) - { - return changes.GetLatestOfTypeOrNull(RelationshipChangeType.Termination, c => !c.IsCompleted); - } - - public static RelationshipChange? GetOpenTerminationCancellation(this IRelationshipChangeLog changes) - { - return changes.GetLatestOfTypeOrNull(RelationshipChangeType.TerminationCancellation, c => !c.IsCompleted); - } -} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/TestHelpers/TestData.cs b/Modules/Relationships/test/Relationships.Domain.Tests/TestHelpers/TestData.cs new file mode 100644 index 0000000000..84a971143d --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/TestHelpers/TestData.cs @@ -0,0 +1,45 @@ +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Aggregates.RelationshipTemplates; + +namespace Backbone.Modules.Relationships.Domain.Tests.TestHelpers; + +public static class TestData +{ + public static readonly IdentityAddress IDENTITY_1 = IdentityAddress.Create([1, 1, 1], "id1"); + public static readonly DeviceId DEVICE_1 = DeviceId.New(); + + public static readonly IdentityAddress IDENTITY_2 = IdentityAddress.Create([2, 2, 2], "id1"); + public static readonly DeviceId DEVICE_2 = DeviceId.New(); + + public static readonly RelationshipTemplate RELATIONSHIP_TEMPLATE_OF_1 = new(IDENTITY_1, DEVICE_1, 1, null, []); + public static readonly RelationshipTemplate RELATIONSHIP_TEMPLATE_OF_2 = new(IDENTITY_2, DEVICE_2, 1, null, []); + + public static Relationship CreatePendingRelationship() + { + return new Relationship(RELATIONSHIP_TEMPLATE_OF_2, IDENTITY_1, DEVICE_1, null, []); + } + + public static Relationship CreateActiveRelationship(IdentityAddress? from = null, IdentityAddress? to = null) + { + to ??= IDENTITY_2; + var template = new RelationshipTemplate(to, DEVICE_2, 999, null, []); + var relationship = new Relationship(template, from ?? IDENTITY_1, DEVICE_1, null, []); + relationship.Accept(to, DEVICE_2, []); + return relationship; + } + + public static Relationship CreateRejectedRelationship() + { + var relationship = new Relationship(RELATIONSHIP_TEMPLATE_OF_2, IDENTITY_1, DEVICE_1, null, []); + relationship.Reject(IDENTITY_2, DEVICE_2); + return relationship; + } + + public static Relationship CreateRevokedRelationship() + { + var relationship = new Relationship(RELATIONSHIP_TEMPLATE_OF_2, IDENTITY_1, DEVICE_1, null, []); + relationship.Revoke(IDENTITY_1, DEVICE_1); + return relationship; + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/AcceptRelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/AcceptRelationshipTests.cs new file mode 100644 index 0000000000..ab8dbca875 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/AcceptRelationshipTests.cs @@ -0,0 +1,95 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Tests.Extensions; +using Backbone.Tooling; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class AcceptRelationshipTests +{ + [Fact] + public void Accepting_creation_transitions_relationship_to_status_active() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + relationship.Accept(IDENTITY_2, DEVICE_2, [0]); + + // Assert + relationship.Status.Should().Be(RelationshipStatus.Active); + relationship.AcceptanceContent.Should().BeEquivalentTo([0]); + } + + [Fact] + public void Accepting_creation_creates_an_audit_log_entry() + { + // Arrange + SystemTime.Set("2000-01-01"); + + var relationship = CreatePendingRelationship(); + + // Act + relationship.Accept(IDENTITY_2, DEVICE_2, []); + + // Assert + relationship.AuditLog.Should().HaveCount(2); + + var auditLogEntry = relationship.AuditLog.Last(); + + auditLogEntry.Id.Should().NotBeNull(); + auditLogEntry.Reason.Should().Be(RelationshipAuditLogEntryReason.AcceptanceOfCreation); + auditLogEntry.OldStatus.Should().Be(RelationshipStatus.Pending); + auditLogEntry.NewStatus.Should().Be(RelationshipStatus.Active); + auditLogEntry.CreatedBy.Should().Be(IDENTITY_2); + auditLogEntry.CreatedByDevice.Should().Be(DEVICE_2); + auditLogEntry.CreatedAt.Should().Be(DateTime.Parse("2000-01-01")); + } + + [Fact] + public void Can_only_accept_creation_when_relationship_is_in_status_pending() + { + // Arrange + var relationship = CreateActiveRelationship(); + + // Act + var acting = () => relationship.Accept(IDENTITY_2, DEVICE_2, []); + + // Assert + acting.Should().Throw().WithError( + "error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus", + nameof(RelationshipStatus.Pending) + ); + } + + [Fact] + public void Cannot_accept_own_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + var acting = () => relationship.Accept(IDENTITY_1, DEVICE_1, []); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse"); + } + + [Fact] + public void Cannot_accept_foreign_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + var foreignAddress = IdentityAddress.ParseUnsafe("some-other-identity"); + + // Act + var acting = () => relationship.Accept(foreignAddress, DeviceId.New(), []); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse"); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/CreateRelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/CreateRelationshipTests.cs new file mode 100644 index 0000000000..8fe3ae1ec0 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/CreateRelationshipTests.cs @@ -0,0 +1,98 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Tests.Extensions; +using Backbone.Tooling; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class CreateRelationshipTests +{ + [Fact] + public void New_Relationship_Has_Correct_Data() + { + // Arrange + SystemTime.Set("2000-01-01"); + + // Act + var relationship = new Relationship(RELATIONSHIP_TEMPLATE_OF_2, IDENTITY_1, DEVICE_1, [0, 1, 2], []); + + // Assert + relationship.Id.Should().NotBeNull(); + relationship.From.Should().Be(IDENTITY_1); + relationship.To.Should().Be(IDENTITY_2); + relationship.Status.Should().Be(RelationshipStatus.Pending); + relationship.RelationshipTemplateId.Should().Be(RELATIONSHIP_TEMPLATE_OF_2.Id); + relationship.RelationshipTemplate.Should().Be(RELATIONSHIP_TEMPLATE_OF_2); + relationship.CreatedAt.Should().Be(DateTime.Parse("2000-01-01")); + relationship.CreationContent.Should().Equal([0, 1, 2]); + } + + [Fact] + public void New_relationship_has_AuditLogEntry() + { + // Arrange + SystemTime.Set("2000-01-01"); + + // Act + var relationship = new Relationship(RELATIONSHIP_TEMPLATE_OF_2, IDENTITY_1, DEVICE_1, null, []); + + // Assert + relationship.AuditLog.Should().HaveCount(1); + + var auditLogEntry = relationship.AuditLog.First(); + + auditLogEntry.Id.Should().NotBeNull(); + auditLogEntry.Reason.Should().Be(RelationshipAuditLogEntryReason.Creation); + auditLogEntry.OldStatus.Should().Be(null); + auditLogEntry.NewStatus.Should().Be(RelationshipStatus.Pending); + auditLogEntry.CreatedBy.Should().Be(IDENTITY_1); + auditLogEntry.CreatedByDevice.Should().Be(DEVICE_1); + auditLogEntry.CreatedAt.Should().Be(DateTime.Parse("2000-01-01")); + } + + [Fact] + public void Cannot_create_Relationship_to_self() + { + // Act + var acting = () => new Relationship(RELATIONSHIP_TEMPLATE_OF_1, IDENTITY_1, DEVICE_1, null, []); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotSendRelationshipRequestToYourself"); + } + + [Fact] + public void There_can_only_be_one_active_relationship_between_two_identities() + { + // Arrange + var existingRelationships = new List + { + CreateActiveRelationship() + }; + + // Act + var acting = () => new Relationship(RELATIONSHIP_TEMPLATE_OF_1, IDENTITY_2, DEVICE_2, null, existingRelationships); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.relationshipToTargetAlreadyExists"); + } + + [Fact] + public void Creating_a_new_relationship_is_possible_if_existing_ones_are_rejected_or_revoked() + { + // Arrange + var existingRelationships = new List + { + // CreateRejectedRelationship(), + CreateRevokedRelationship() + }; + + // Act + var acting = () => new Relationship(RELATIONSHIP_TEMPLATE_OF_1, IDENTITY_2, DEVICE_2, null, existingRelationships); + + // Assert + acting.Should().NotThrow(); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/ExpressionTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/ExpressionTests.cs new file mode 100644 index 0000000000..b4487758d9 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/ExpressionTests.cs @@ -0,0 +1,101 @@ +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Tests.TestHelpers; +using Xunit; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class ExpressionTests +{ + #region CountsAsActive + + [Fact] + public void CountsAsActive_with_status_Pending() + { + var pendingRelationship = TestData.CreatePendingRelationship(); + + var result = pendingRelationship.EvaluateCountsAsActiveExpression(); + + Assert.True(result); + } + + [Fact] + public void CountsAsActive_with_status_Active() + { + var activeRelationship = TestData.CreateActiveRelationship(); + + var result = activeRelationship.EvaluateCountsAsActiveExpression(); + + Assert.True(result); + } + + [Fact] + public void CountsAsActive_with_status_Rejected() + { + var rejectedRelationship = TestData.CreateRejectedRelationship(); + + var result = rejectedRelationship.EvaluateCountsAsActiveExpression(); + + Assert.False(result); + } + + [Fact] + public void CountsAsActive_with_status_Revoked() + { + var revokedRelationship = TestData.CreateRevokedRelationship(); + + var result = revokedRelationship.EvaluateCountsAsActiveExpression(); + + Assert.False(result); + } + + #endregion + + #region HasParticipant + + [Fact] + public void HasParticipant_recognizes_from_address() + { + var relationship = TestData.CreateActiveRelationship(); + + var result = relationship.EvaluateHasParticipantExpression(relationship.From); + + Assert.True(result); + } + + [Fact] + public void HasParticipant_recognizes_to_address() + { + var relationship = TestData.CreateActiveRelationship(); + + var result = relationship.EvaluateHasParticipantExpression(relationship.To); + + Assert.True(result); + } + + [Fact] + public void HasParticipant_recognizes_foreign_addresses() + { + var relationship = TestData.CreateActiveRelationship(); + + var result = relationship.EvaluateHasParticipantExpression("id1"); + + Assert.False(result); + } + + #endregion +} + +file static class RelationshipExtensions +{ + public static bool EvaluateHasParticipantExpression(this Relationship relationship, string identity) + { + var expression = Relationship.HasParticipant(identity); + return expression.Compile()(relationship); + } + + public static bool EvaluateCountsAsActiveExpression(this Relationship relationship) + { + var expression = Relationship.CountsAsActive(); + return expression.Compile()(relationship); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RejectRelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RejectRelationshipTests.cs new file mode 100644 index 0000000000..51b5a70bc2 --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RejectRelationshipTests.cs @@ -0,0 +1,94 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Tests.Extensions; +using Backbone.Tooling; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class RejectRelationshipTests +{ + [Fact] + public void Reject_creation_transitions_relationship_to_status_rejected() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + relationship.Reject(IDENTITY_2, DEVICE_2); + + // Assert + relationship.Status.Should().Be(RelationshipStatus.Rejected); + } + + [Fact] + public void Rejecting_creation_creates_an_audit_log_entry() + { + // Arrange + SystemTime.Set("2000-01-01"); + + var relationship = CreatePendingRelationship(); + + // Act + relationship.Reject(IDENTITY_2, DEVICE_2); + + // Assert + relationship.AuditLog.Should().HaveCount(2); + + var auditLogEntry = relationship.AuditLog.Last(); + + auditLogEntry.Id.Should().NotBeNull(); + auditLogEntry.Reason.Should().Be(RelationshipAuditLogEntryReason.RejectionOfCreation); + auditLogEntry.OldStatus.Should().Be(RelationshipStatus.Pending); + auditLogEntry.NewStatus.Should().Be(RelationshipStatus.Rejected); + auditLogEntry.CreatedBy.Should().Be(IDENTITY_2); + auditLogEntry.CreatedByDevice.Should().Be(DEVICE_2); + auditLogEntry.CreatedAt.Should().Be(DateTime.Parse("2000-01-01")); + } + + [Fact] + public void Can_only_reject_creation_when_relationship_is_in_status_pending() + { + // Arrange + var relationship = CreateActiveRelationship(); + + // Act + var acting = () => relationship.Reject(IDENTITY_2, DEVICE_2); + + // Assert + acting.Should().Throw().WithError( + "error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus", + nameof(RelationshipStatus.Pending) + ); + } + + [Fact] + public void Cannot_reject_own_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + var acting = () => relationship.Reject(IDENTITY_1, DEVICE_1); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse"); + } + + [Fact] + public void Cannot_reject_foreign_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + var foreignAddress = IdentityAddress.ParseUnsafe("some-other-identity"); + + // Act + var acting = () => relationship.Reject(foreignAddress, DeviceId.New()); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse"); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RevokeRelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RevokeRelationshipTests.cs new file mode 100644 index 0000000000..511d5024cb --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/RevokeRelationshipTests.cs @@ -0,0 +1,94 @@ +using Backbone.BuildingBlocks.Domain; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.Modules.Relationships.Domain.Tests.Extensions; +using Backbone.Tooling; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class RevokeRelationshipTests +{ + [Fact] + public void Revoke_creation_transitions_relationship_to_status_revoked() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + relationship.Revoke(IDENTITY_1, DEVICE_1); + + // Assert + relationship.Status.Should().Be(RelationshipStatus.Revoked); + } + + [Fact] + public void Revoking_creation_creates_an_audit_log_entry() + { + // Arrange + SystemTime.Set("2000-01-01"); + + var relationship = CreatePendingRelationship(); + + // Act + relationship.Revoke(IDENTITY_1, DEVICE_1); + + // Assert + relationship.AuditLog.Should().HaveCount(2); + + var auditLogEntry = relationship.AuditLog.Last(); + + auditLogEntry.Id.Should().NotBeNull(); + auditLogEntry.Reason.Should().Be(RelationshipAuditLogEntryReason.RevocationOfCreation); + auditLogEntry.OldStatus.Should().Be(RelationshipStatus.Pending); + auditLogEntry.NewStatus.Should().Be(RelationshipStatus.Revoked); + auditLogEntry.CreatedBy.Should().Be(IDENTITY_1); + auditLogEntry.CreatedByDevice.Should().Be(DEVICE_1); + auditLogEntry.CreatedAt.Should().Be(DateTime.Parse("2000-01-01")); + } + + [Fact] + public void Can_only_revoke_creation_when_relationship_is_in_status_pending() + { + // Arrange + var relationship = CreateActiveRelationship(); + + // Act + var acting = () => relationship.Revoke(IDENTITY_2, DEVICE_2); + + // Assert + acting.Should().Throw().WithError( + "error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus", + nameof(RelationshipStatus.Pending) + ); + } + + [Fact] + public void Cannot_revoke_own_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + + // Act + var acting = () => relationship.Revoke(IDENTITY_2, DEVICE_2); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotRevokeRelationshipRequestNotCreatedByYourself"); + } + + [Fact] + public void Cannot_revoke_foreign_relationship_request() + { + // Arrange + var relationship = CreatePendingRelationship(); + var foreignAddress = IdentityAddress.ParseUnsafe("some-other-identity"); + + // Act + var acting = () => relationship.Revoke(foreignAddress, DeviceId.New()); + + // Assert + acting.Should().Throw().WithError("error.platform.validation.relationshipRequest.cannotRevokeRelationshipRequestNotCreatedByYourself"); + } +} diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/SelectorTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/SelectorTests.cs new file mode 100644 index 0000000000..8e249fbacb --- /dev/null +++ b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/Aggregates/Relationships/SelectorTests.cs @@ -0,0 +1,70 @@ +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Relationships.Domain.Aggregates.Relationships; +using Backbone.UnitTestTools.Data; +using FluentAssertions; +using Xunit; +using static Backbone.Modules.Relationships.Domain.Tests.TestHelpers.TestData; + +namespace Backbone.Modules.Relationships.Domain.Tests.Tests.Aggregates.Relationships; + +public class SelectorTests +{ + [Fact] + public void WithParticipant_From() + { + // Arrange + var identityAddress = TestDataGenerator.CreateRandomIdentityAddress(); + var relationship = CreateActiveRelationship(from: identityAddress); + + // Act + var result = relationship.HasParticipant(identityAddress); + + // Assert + result.Should().BeTrue(); + } + + [Fact] + public void WithParticipant_To() + { + // Arrange + var identityAddress = TestDataGenerator.CreateRandomIdentityAddress(); + var relationship = CreateActiveRelationship(to: identityAddress); + + // Act + var result = relationship.HasParticipant(identityAddress); + + // Assert + result.Should().BeTrue(); + relationship.To.Should().Be(identityAddress); + } + + [Fact] + public void WithParticipant_Mixed() + { + // Arrange + var identityAddressFrom = TestDataGenerator.CreateRandomIdentityAddress(); + var identityAddressTo = TestDataGenerator.CreateRandomIdentityAddress(); + var relationship = CreateActiveRelationship(from: identityAddressFrom, to: identityAddressTo); + + // Act + var hasIdentityAddressFrom = relationship.HasParticipant(identityAddressFrom); + var hasIdentityAddressTo = relationship.HasParticipant(identityAddressTo); + + // Assert + hasIdentityAddressFrom.Should().BeTrue(); + hasIdentityAddressTo.Should().BeTrue(); + relationship.From.Should().Be(identityAddressFrom); + } +} + +#region Extensions + +file static class RelationshipExtensions +{ + public static bool HasParticipant(this Relationship relationship, IdentityAddress identity) + { + return Relationship.HasParticipant(identity).Compile()(relationship); + } +} + +#endregion diff --git a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs b/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs deleted file mode 100644 index 45c11948cc..0000000000 --- a/Modules/Relationships/test/Relationships.Domain.Tests/Tests/RelationshipTests.cs +++ /dev/null @@ -1,611 +0,0 @@ -using Backbone.BuildingBlocks.Domain; -using Backbone.BuildingBlocks.Domain.Errors; -using Backbone.DevelopmentKit.Identity.ValueObjects; -using Backbone.Modules.Relationships.Domain.Entities; -using Backbone.Modules.Relationships.Domain.Errors; -using Backbone.Modules.Relationships.Domain.Ids; -using Backbone.Modules.Relationships.Domain.Tests.Extensions; -using Backbone.Tooling; -using Backbone.UnitTestTools.Data; -using FluentAssertions; -using Xunit; - -namespace Backbone.Modules.Relationships.Domain.Tests.Tests; - -public class RelationshipTests -{ - private static readonly IdentityAddress FROM_IDENTITY = IdentityAddress.Create([1, 1, 1], "id1"); - private static readonly DeviceId FROM_DEVICE = DeviceId.New(); - - private static readonly IdentityAddress TO_IDENTITY = IdentityAddress.Create([2, 2, 2], "id1"); - private static readonly DeviceId TO_DEVICE = DeviceId.New(); - - private static readonly byte[] REQUEST_CONTENT = [1, 1, 1]; - private static readonly byte[] RESPONSE_CONTENT = [2, 2, 2]; - - private static readonly RelationshipTemplate TEMPLATE = new(TO_IDENTITY, TO_DEVICE, 1, SystemTime.UtcNow.AddDays(1), [0]); - - #region Creation - - [Fact] - public void New_Relationship_Has_Correct_Data() - { - // Act - var relationship = CreatePendingRelationship(); - - // Assert - relationship.From.Should().Be(FROM_IDENTITY); - relationship.To.Should().Be(TO_IDENTITY); - relationship.Status.Should().Be(RelationshipStatus.Pending); - - relationship.Changes.Should().HaveCount(1); - var change = relationship.Changes.GetLatestOfType(RelationshipChangeType.Creation); - change.Request.CreatedBy.Should().Be(FROM_IDENTITY); - change.Request.CreatedByDevice.Should().Be(FROM_DEVICE); - - change.Type.Should().Be(RelationshipChangeType.Creation); - change.Status.Should().Be(RelationshipChangeStatus.Pending); - - change.Response.Should().BeNull(); - } - - #region Accept Creation - - [Fact] - public void Accepting_CreationRequest_Changes_Relevant_Data() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Active); - - change.Status.Should().Be(RelationshipChangeStatus.Accepted); - - change.Response.Should().NotBeNull(); - change.Response!.Content.Should().Equal(RESPONSE_CONTENT); - change.Response!.CreatedBy.Should().Be(TO_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(TO_DEVICE); - } - - [Fact] - public void Cannot_Accept_CreationRequests_Without_Content() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ContentIsRequiredForCompletingRelationships()); - } - - [Fact] - public void Cannot_Accept_Already_Completed_CreationRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Act - Action acting = () => relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void Relationship_Cannot_Be_Accepted_By_Creator() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.AcceptChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); - } - - #endregion - - #region Reject Creation - - [Fact] - public void Rejecting_CreationRequest_Sets_Relevant_Data() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Rejected); - - change.Status.Should().Be(RelationshipChangeStatus.Rejected); - - change.Response.Should().NotBeNull(); - change.Response!.Content.Should().Equal(RESPONSE_CONTENT); - change.Response!.CreatedBy.Should().Be(TO_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(TO_DEVICE); - } - - [Fact] - public void Cannot_Reject_CreationRequests_Without_Content() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ContentIsRequiredForCompletingRelationships()); - } - - [Fact] - public void Cannot_Reject_Already_Completed_CreationRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Act - Action acting = () => relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void CreationRequest_Cannot_Be_Rejected_By_Creator() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.RejectChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeRejectedByCreator()); - } - - #endregion - - #region Revoke Creation - - [Fact] - public void Revoking_CreationRequest_Sets_Relevant_Data() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Revoked); - - change.Status.Should().Be(RelationshipChangeStatus.Revoked); - - change.Response.Should().NotBeNull(); - change.Response!.Content.Should().Equal(RESPONSE_CONTENT); - change.Response!.CreatedBy.Should().Be(FROM_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(FROM_DEVICE); - } - - [Fact] - public void Cannot_Revoke_CreationRequests_Without_Content() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ContentIsRequiredForCompletingRelationships()); - } - - [Fact] - public void Cannot_Revoke_Already_Completed_CreationRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Act - Action acting = () => relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void CreationRequest_Cannot_Be_Revoked_By_Recipient() - { - // Arrange - var relationship = CreatePendingRelationship(); - var change = relationship.Changes.GetOpenCreation()!; - - // Act - Action acting = () => relationship.RevokeChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCanOnlyBeRevokedByCreator()); - } - - #endregion - - #endregion - - #region Common - - [Fact] - public void Cannot_Accept_Non_Existent_ChangeRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - - // Act - Action acting = () => relationship.AcceptChange(RelationshipChangeId.New(), TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(GenericDomainErrors.NotFound()); - } - - [Fact] - public void Cannot_Reject_Non_Existent_ChangeRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - - // Act - Action acting = () => relationship.RejectChange(RelationshipChangeId.New(), TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(GenericDomainErrors.NotFound()); - } - - [Fact] - public void Cannot_Revoke_Non_Existent_ChangeRequests() - { - // Arrange - var relationship = CreatePendingRelationship(); - - // Act - Action acting = () => relationship.RevokeChange(RelationshipChangeId.New(), TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(GenericDomainErrors.NotFound()); - } - - #endregion - - #region Termination - - [Fact] - public void Requesting_Termination_Sets_Relevant_Data() - { - // Arrange - var relationship = CreateActiveRelationship(); - - // Act - relationship.RequestTermination(FROM_IDENTITY, FROM_DEVICE); - - // Assert - relationship.Changes.Should().HaveCount(2); - - var termination = relationship.Changes.GetOpenTermination()!; - termination.Should().NotBeNull(); - termination.Status.Should().Be(RelationshipChangeStatus.Pending); - termination.Request.Should().NotBeNull(); - termination.Request.CreatedBy.Should().Be(FROM_IDENTITY); - termination.Request.CreatedByDevice.Should().Be(FROM_DEVICE); - - termination.Response.Should().BeNull(); - } - - [Fact] - public void Cannot_Request_Termination_For_Pending_Relationships() - { - // Arrange - var relationship = CreatePendingRelationship(); - - // Act - Action acting = () => relationship.RequestTermination(FROM_IDENTITY, FROM_DEVICE); - - // Assert - acting.Should().Throw().WithError(DomainErrors.OnlyActiveRelationshipsCanBeTerminated()); - } - - #region Accept Termination - - [Fact] - public void Accepting_TerminationRequest_Changes_Relevant_Data() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, null); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Terminated); - - change.Status.Should().Be(RelationshipChangeStatus.Accepted); - - change.Response.Should().NotBeNull(); - change.Response!.CreatedBy.Should().Be(TO_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(TO_DEVICE); - } - - [Fact] - public void Cannot_Accept_Already_Completed_TerminationRequests() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - Action acting = () => relationship.AcceptChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void TerminationRequest_Cannot_Be_Accepted_By_Creator() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - Action acting = () => relationship.AcceptChange(change.Id, FROM_IDENTITY, FROM_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeAcceptedByCreator()); - } - - #endregion - - #region Reject Termination - - [Fact] - public void Rejecting_TerminationRequest_Changes_Relevant_Data() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, null); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Active); - - change.Status.Should().Be(RelationshipChangeStatus.Rejected); - - change.Response.Should().NotBeNull(); - change.Response!.CreatedBy.Should().Be(TO_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(TO_DEVICE); - } - - [Fact] - public void Cannot_Reject_Already_Completed_TerminationRequests() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - Action acting = () => relationship.RejectChange(change.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void TerminationRequest_Cannot_Be_Rejected_By_Creator() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - Action acting = () => relationship.RejectChange(change.Id, FROM_IDENTITY, FROM_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCannotBeRejectedByCreator()); - } - - #endregion - - #region Revoke Termination - - [Fact] - public void Revoking_TerminationRequest_Sets_Relevant_Data() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, null); - - // Assert - relationship.Status.Should().Be(RelationshipStatus.Active); - - change.Status.Should().Be(RelationshipChangeStatus.Revoked); - - change.Response.Should().NotBeNull(); - change.Response!.CreatedBy.Should().Be(FROM_IDENTITY); - change.Response!.CreatedByDevice.Should().Be(FROM_DEVICE); - } - - [Fact] - public void Cannot_Revoke_Already_Completed_TerminationRequests() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Act - Action acting = () => relationship.RevokeChange(change.Id, FROM_IDENTITY, FROM_DEVICE, RESPONSE_CONTENT); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestIsAlreadyCompleted()); - } - - [Fact] - public void TerminationRequest_Cannot_Be_Revoked_By_Recipient() - { - // Arrange - var relationship = CreateRelationshipWithOpenTermination(); - var change = relationship.Changes.GetOpenTermination()!; - - // Act - Action acting = () => relationship.RevokeChange(change.Id, TO_IDENTITY, TO_DEVICE, null); - - // Assert - acting.Should().Throw().WithError(DomainErrors.ChangeRequestCanOnlyBeRevokedByCreator()); - } - - #endregion - - #endregion - - #region Selectors - - [Fact] - public void WithParticipant_From() - { - // Arrange - var identityAddress = TestDataGenerator.CreateRandomIdentityAddress(); - var relationship = CreateActiveRelationship(identityAddress); - - // Act - var result = relationship.HasParticipant(identityAddress); - - // Assert - result.Should().BeTrue(); - } - - [Fact] - public void WithParticipant_To() - { - // Arrange - var identityAddress = TestDataGenerator.CreateRandomIdentityAddress(); - var relationship = CreateActiveRelationship((null, identityAddress)); - - // Act - var result = relationship.HasParticipant(identityAddress); - - // Assert - result.Should().BeTrue(); - relationship.To.Should().Be(identityAddress); - } - - [Fact] - public void WithParticipant_Mixed() - { - // Arrange - var identityAddressFrom = TestDataGenerator.CreateRandomIdentityAddress(); - var identityAddressTo = TestDataGenerator.CreateRandomIdentityAddress(); - var relationship = CreateActiveRelationship((identityAddressFrom, identityAddressTo)); - - // Act - var hasIdentityAddressFrom = relationship.HasParticipant(identityAddressFrom); - var hasIdentityAddressTo = relationship.HasParticipant(identityAddressTo); - - // Assert - hasIdentityAddressFrom.Should().BeTrue(); - hasIdentityAddressTo.Should().BeTrue(); - relationship.From.Should().Be(identityAddressFrom); - } - - #endregion - - #region Constructor Functions - - private static Relationship CreatePendingRelationship() - { - var relationship = new Relationship(TEMPLATE, FROM_IDENTITY, FROM_DEVICE, REQUEST_CONTENT); - return relationship; - } - - private static Relationship CreateActiveRelationship() - { - var relationship = new Relationship(TEMPLATE, FROM_IDENTITY, FROM_DEVICE, REQUEST_CONTENT); - var change = relationship.Changes.GetOpenCreation(); - relationship.AcceptChange(change!.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - return relationship; - } - - private static Relationship CreateActiveRelationship(IdentityAddress from) - { - return CreateActiveRelationship((from, null)); - } - - private static Relationship CreateActiveRelationship((IdentityAddress? from, IdentityAddress? to) parameters) - { - RelationshipTemplate? template = null; - if (parameters.to is not null) - { - template = new RelationshipTemplate(parameters.to, TO_DEVICE, 1, SystemTime.UtcNow.AddDays(1), [0]); - } - - var relationship = new Relationship(template ?? TEMPLATE, parameters.from ?? FROM_IDENTITY, FROM_DEVICE, REQUEST_CONTENT); - var change = relationship.Changes.GetOpenCreation()!; - relationship.AcceptChange(change.Id, parameters.to ?? TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - return relationship; - } - - private static Relationship CreateRelationshipWithOpenTermination() - { - var relationship = new Relationship(TEMPLATE, FROM_IDENTITY, FROM_DEVICE, REQUEST_CONTENT); - var change = relationship.Changes.GetOpenCreation(); - relationship.AcceptChange(change!.Id, TO_IDENTITY, TO_DEVICE, RESPONSE_CONTENT); - - relationship.RequestTermination(FROM_IDENTITY, FROM_DEVICE); - return relationship; - } - - #endregion -} - -#region Extensions - -file static class RelationshipExtensions -{ - public static bool HasParticipant(this Relationship relationship, IdentityAddress identity) - { - return Relationship.HasParticipant(identity).Compile()(relationship); - } -} - -#endregion diff --git a/Modules/Synchronization/src/Synchronization.Application/Extensions/IEventBusExtensions.cs b/Modules/Synchronization/src/Synchronization.Application/Extensions/IEventBusExtensions.cs index 49402b48db..955756ab47 100644 --- a/Modules/Synchronization/src/Synchronization.Application/Extensions/IEventBusExtensions.cs +++ b/Modules/Synchronization/src/Synchronization.Application/Extensions/IEventBusExtensions.cs @@ -2,8 +2,8 @@ using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.IdentityDeletionProcessStarted; using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.IdentityDeletionProcessStatusChanged; using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.MessageCreated; -using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; -using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipCreated; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; namespace Backbone.Modules.Synchronization.Application.Extensions; @@ -27,7 +27,7 @@ private static void SubscribeToMessagesEvents(IEventBus eventBus) private static void SubscribeToRelationshipsEvents(IEventBus eventBus) { - eventBus.Subscribe(); - eventBus.Subscribe(); + eventBus.Subscribe(); + eventBus.Subscribe(); } } diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs deleted file mode 100644 index f60e9ae70e..0000000000 --- a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEvent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; - -namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; - -public class RelationshipChangeCompletedIntegrationEvent : IntegrationEvent -{ - public required string ChangeId { get; set; } - public required string RelationshipId { get; set; } - public required string ChangeCreatedBy { get; set; } - public required string ChangeRecipient { get; set; } - public required string ChangeResult { get; set; } -} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs deleted file mode 100644 index 155dfcd02c..0000000000 --- a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCompleted/RelationshipChangeCompletedIntegrationEventHandler.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; -using Backbone.Modules.Synchronization.Application.Infrastructure; -using Backbone.Modules.Synchronization.Application.IntegrationEvents.Outgoing; -using Backbone.Modules.Synchronization.Domain.Entities.Sync; -using Microsoft.Extensions.Logging; - -namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCompleted; - -public class RelationshipChangeCompletedIntegrationEventHandler : IIntegrationEventHandler -{ - private readonly ISynchronizationDbContext _dbContext; - private readonly IEventBus _eventBus; - private readonly ILogger _logger; - - public RelationshipChangeCompletedIntegrationEventHandler(ISynchronizationDbContext dbContext, IEventBus eventBus, ILogger logger) - { - _dbContext = dbContext; - _eventBus = eventBus; - _logger = logger; - } - - public async Task Handle(RelationshipChangeCompletedIntegrationEvent integrationEvent) - { - await CreateExternalEvent(integrationEvent); - } - - private async Task CreateExternalEvent(RelationshipChangeCompletedIntegrationEvent integrationEvent) - { -#pragma warning disable IDE0037 - var payload = new { RelationshipId = integrationEvent.RelationshipId, ChangeId = integrationEvent.ChangeId }; -#pragma warning restore IDE0037 - try - { - var owner = integrationEvent.ChangeResult switch - { - "Accepted" => integrationEvent.ChangeCreatedBy, - "Rejected" => integrationEvent.ChangeCreatedBy, - "Revoked" => integrationEvent.ChangeRecipient, - _ => throw new ArgumentOutOfRangeException(nameof(integrationEvent.ChangeResult), integrationEvent, null) - }; - - var externalEvent = await _dbContext.CreateExternalEvent(owner, ExternalEventType.RelationshipChangeCompleted, payload); - _eventBus.Publish(new ExternalEventCreatedIntegrationEvent(externalEvent)); - } - catch (Exception ex) - { - _logger.LogError(ex, "An error occured while processing an integration event."); - throw; - } - } -} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs deleted file mode 100644 index 3b8b802667..0000000000 --- a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEvent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; - -namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; - -public class RelationshipChangeCreatedIntegrationEvent : IntegrationEvent -{ - public required string ChangeId { get; set; } - public required string RelationshipId { get; set; } - public required string ChangeCreatedBy { get; set; } - public required string ChangeRecipient { get; set; } -} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs new file mode 100644 index 0000000000..8b5b55a4cf --- /dev/null +++ b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEvent.cs @@ -0,0 +1,10 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; + +namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipCreated; + +public class RelationshipCreatedIntegrationEvent : IntegrationEvent +{ + public required string RelationshipId { get; set; } + public required string From { get; set; } + public required string To { get; set; } +} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs new file mode 100644 index 0000000000..52b2279017 --- /dev/null +++ b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipCreated/RelationshipCreatedIntegrationEventHandler.cs @@ -0,0 +1,38 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.Modules.Synchronization.Application.Infrastructure; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Synchronization.Domain.Entities.Sync; +using Microsoft.Extensions.Logging; + +namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipCreated; + +public class RelationshipCreatedIntegrationEventHandler : IIntegrationEventHandler +{ + private readonly ISynchronizationDbContext _dbContext; + private readonly IEventBus _eventBus; + private readonly ILogger _logger; + + public RelationshipCreatedIntegrationEventHandler(ISynchronizationDbContext dbContext, IEventBus eventBus, ILogger logger) + { + _dbContext = dbContext; + _eventBus = eventBus; + _logger = logger; + } + + public async Task Handle(RelationshipCreatedIntegrationEvent @event) + { +#pragma warning disable IDE0037 + var payload = new { RelationshipId = @event.RelationshipId }; +#pragma warning restore IDE0037 + try + { + var externalEvent = await _dbContext.CreateExternalEvent(@event.To, ExternalEventType.RelationshipCreated, payload); + _eventBus.Publish(new ExternalEventCreatedIntegrationEvent(externalEvent)); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occured while processing an integration event."); + throw; + } + } +} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs new file mode 100644 index 0000000000..919cdf7a83 --- /dev/null +++ b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEvent.cs @@ -0,0 +1,9 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus.Events; + +namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; + +public class RelationshipStatusChangedIntegrationEvent : IntegrationEvent +{ + public required string RelationshipId { get; set; } + public required string Peer { get; set; } +} diff --git a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs similarity index 53% rename from Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs rename to Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs index 85323b7821..9e75817465 100644 --- a/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipChangeCreated/RelationshipChangeCreatedIntegrationEventHandler.cs +++ b/Modules/Synchronization/src/Synchronization.Application/IntegrationEvents/Incoming/RelationshipStatusChanged/RelationshipStatusChangedIntegrationEventHandler.cs @@ -1,37 +1,32 @@ -using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; using Backbone.Modules.Synchronization.Application.Infrastructure; using Backbone.Modules.Synchronization.Application.IntegrationEvents.Outgoing; using Backbone.Modules.Synchronization.Domain.Entities.Sync; using Microsoft.Extensions.Logging; -namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipChangeCreated; +namespace Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; -public class RelationshipChangeCreatedIntegrationEventHandler : IIntegrationEventHandler +public class RelationshipStatusChangedIntegrationEventHandler : IIntegrationEventHandler { private readonly ISynchronizationDbContext _dbContext; private readonly IEventBus _eventBus; - private readonly ILogger _logger; + private readonly ILogger _logger; - public RelationshipChangeCreatedIntegrationEventHandler(ISynchronizationDbContext dbContext, IEventBus eventBus, ILogger logger) + public RelationshipStatusChangedIntegrationEventHandler(ISynchronizationDbContext dbContext, IEventBus eventBus, ILogger logger) { _dbContext = dbContext; _eventBus = eventBus; _logger = logger; } - public async Task Handle(RelationshipChangeCreatedIntegrationEvent integrationEvent) - { - await CreateExternalEvent(integrationEvent); - } - - private async Task CreateExternalEvent(RelationshipChangeCreatedIntegrationEvent integrationEvent) + public async Task Handle(RelationshipStatusChangedIntegrationEvent @event) { #pragma warning disable IDE0037 - var payload = new { RelationshipId = integrationEvent.RelationshipId, ChangeId = integrationEvent.ChangeId }; + var payload = new { RelationshipId = @event.RelationshipId }; #pragma warning restore IDE0037 try { - var externalEvent = await _dbContext.CreateExternalEvent(integrationEvent.ChangeRecipient, ExternalEventType.RelationshipChangeCreated, payload); + var externalEvent = await _dbContext.CreateExternalEvent(@event.Peer, ExternalEventType.RelationshipStatusChanged, payload); _eventBus.Publish(new ExternalEventCreatedIntegrationEvent(externalEvent)); } catch (Exception ex) diff --git a/Modules/Synchronization/src/Synchronization.Application/SyncRuns/DTOs/ExternalEventDTO.cs b/Modules/Synchronization/src/Synchronization.Application/SyncRuns/DTOs/ExternalEventDTO.cs index b7a4f88126..bbbedb5f29 100644 --- a/Modules/Synchronization/src/Synchronization.Application/SyncRuns/DTOs/ExternalEventDTO.cs +++ b/Modules/Synchronization/src/Synchronization.Application/SyncRuns/DTOs/ExternalEventDTO.cs @@ -16,13 +16,15 @@ public class ExternalEventDTO : IHaveCustomMapping public void CreateMappings(Profile configuration) { configuration.CreateMap().ConvertUsing((externalEventType, _) => externalEventType switch - { - ExternalEventType.MessageDelivered => "MessageDelivered", - ExternalEventType.MessageReceived => "MessageReceived", - ExternalEventType.RelationshipChangeCreated => "RelationshipChangeCreated", - ExternalEventType.RelationshipChangeCompleted => "RelationshipChangeCompleted", - _ => throw new ArgumentOutOfRangeException(nameof(externalEventType), externalEventType, null) - }); + { + ExternalEventType.MessageDelivered => "MessageDelivered", + ExternalEventType.MessageReceived => "MessageReceived", + ExternalEventType.RelationshipCreated => "RelationshipCreated", + ExternalEventType.RelationshipStatusChanged => "RelationshipStatusChanged", + ExternalEventType.IdentityDeletionProcessStatusChanged => "IdentityDeletionProcessStatusChanged", + ExternalEventType.IdentityDeletionProcessStarted => "IdentityDeletionProcessStarted", + _ => throw new ArgumentOutOfRangeException(nameof(externalEventType), externalEventType, null) + }); configuration.CreateMap(); } } diff --git a/Modules/Synchronization/src/Synchronization.Domain/Entities/Sync/ExternalEvent.cs b/Modules/Synchronization/src/Synchronization.Domain/Entities/Sync/ExternalEvent.cs index 0d8283b945..a3c7e2b98c 100644 --- a/Modules/Synchronization/src/Synchronization.Domain/Entities/Sync/ExternalEvent.cs +++ b/Modules/Synchronization/src/Synchronization.Domain/Entities/Sync/ExternalEvent.cs @@ -58,8 +58,8 @@ public enum ExternalEventType { MessageReceived = 0, MessageDelivered = 1, - RelationshipChangeCreated = 2, - RelationshipChangeCompleted = 3, + RelationshipCreated = 2, + RelationshipStatusChanged = 3, IdentityDeletionProcessStarted = 4, IdentityDeletionProcessStatusChanged = 5 } diff --git a/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/IdentityDeletionProcessStatusChangedIntegrationEventHandlerTests.cs b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/IdentityDeletionProcessStatusChangedIntegrationEventHandlerTests.cs index 60a75d967b..df78ee92ad 100644 --- a/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/IdentityDeletionProcessStatusChangedIntegrationEventHandlerTests.cs +++ b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/IdentityDeletionProcessStatusChangedIntegrationEventHandlerTests.cs @@ -37,7 +37,7 @@ public async Task Creates_an_external_event() // Act await handler.Handle(identityDeletionProcessStatusChangedIntegrationEvent); - // Handle + // Assert A.CallTo(() => mockDbContext.CreateExternalEvent(identityAddress, ExternalEventType.IdentityDeletionProcessStatusChanged, A._)) .MustHaveHappenedOnceExactly(); } @@ -68,7 +68,7 @@ public async Task Publishes_an_external_event() // Act await handler.Handle(identityDeletionProcessStatusChangedIntegrationEvent); - // Handle + // Assert A.CallTo(() => mockEventBus.Publish( A.That.Matches(e => e.Owner == externalEvent.Owner && e.EventId == externalEvent.Id)) ).MustHaveHappenedOnceExactly(); diff --git a/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipCreatedIntegrationEventHandlerTests.cs b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipCreatedIntegrationEventHandlerTests.cs new file mode 100644 index 0000000000..9e81254bb7 --- /dev/null +++ b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipCreatedIntegrationEventHandlerTests.cs @@ -0,0 +1,90 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Synchronization.Application.Infrastructure; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipCreated; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Synchronization.Domain.Entities.Sync; +using FakeItEasy; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Backbone.Modules.Synchronization.Application.Tests.Tests.IntegrationEvents; + +public class RelationshipCreatedIntegrationEventHandlerTests +{ + [Fact] + public async Task Creates_an_external_event() + { + // Arrange + var relationshipFrom = TestDataGenerator.CreateRandomIdentityAddress(); + var relationshipTo = TestDataGenerator.CreateRandomIdentityAddress(); + var @event = new RelationshipCreatedIntegrationEvent + { + RelationshipId = "REL1", + From = relationshipFrom, + To = relationshipTo + }; + + var mockDbContext = A.Fake(); + + var externalEvent = new ExternalEvent(ExternalEventType.RelationshipCreated, relationshipTo, 1, + new { @event.RelationshipId }); + + A.CallTo(() => mockDbContext.CreateExternalEvent( + relationshipTo, + ExternalEventType.RelationshipCreated, + A._) + ).Returns(externalEvent); + + var handler = CreateHandler(mockDbContext); + + // Act + await handler.Handle(@event); + + // Assert + A.CallTo(() => mockDbContext.CreateExternalEvent(relationshipTo, ExternalEventType.RelationshipCreated, A._)) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Publishes_an_ExternalEventCreatedIntegrationEvent() + { + // Arrange + var relationshipFrom = TestDataGenerator.CreateRandomIdentityAddress(); + var relationshipTo = TestDataGenerator.CreateRandomIdentityAddress(); + var @event = new RelationshipCreatedIntegrationEvent + { + RelationshipId = "REL1", + From = relationshipFrom, + To = relationshipTo + }; + + var fakeDbContext = A.Fake(); + var mockEventBus = A.Fake(); + + var externalEvent = new ExternalEvent(ExternalEventType.IdentityDeletionProcessStarted, IdentityAddress.Parse(relationshipTo), 1, + new { @event.RelationshipId }); + + A.CallTo(() => fakeDbContext.CreateExternalEvent( + relationshipTo, + ExternalEventType.RelationshipCreated, + A._) + ).Returns(externalEvent); + + var handler = CreateHandler(fakeDbContext, mockEventBus); + + // Act + await handler.Handle(@event); + + // Assert + A.CallTo(() => mockEventBus.Publish( + A.That.Matches(e => e.Owner == relationshipTo)) + ).MustHaveHappenedOnceExactly(); + } + + private RelationshipCreatedIntegrationEventHandler CreateHandler(ISynchronizationDbContext dbContext, IEventBus? eventBus = null) + { + eventBus ??= A.Fake(); + return new RelationshipCreatedIntegrationEventHandler(dbContext, eventBus, A.Fake>()); + } +} diff --git a/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipStatusChangedIntegrationEventHandlerTests.cs b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipStatusChangedIntegrationEventHandlerTests.cs new file mode 100644 index 0000000000..9ff6d68823 --- /dev/null +++ b/Modules/Synchronization/test/Synchronization.Application.Tests/Tests/IntegrationEvents/RelationshipStatusChangedIntegrationEventHandlerTests.cs @@ -0,0 +1,86 @@ +using Backbone.BuildingBlocks.Application.Abstractions.Infrastructure.EventBus; +using Backbone.DevelopmentKit.Identity.ValueObjects; +using Backbone.Modules.Synchronization.Application.Infrastructure; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Incoming.RelationshipStatusChanged; +using Backbone.Modules.Synchronization.Application.IntegrationEvents.Outgoing; +using Backbone.Modules.Synchronization.Domain.Entities.Sync; +using FakeItEasy; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Backbone.Modules.Synchronization.Application.Tests.Tests.IntegrationEvents; + +public class RelationshipStatusChangedIntegrationEventHandlerTests +{ + [Fact] + public async Task Creates_an_external_event() + { + // Arrange + var relationshipTo = TestDataGenerator.CreateRandomIdentityAddress(); + var @event = new RelationshipStatusChangedIntegrationEvent + { + RelationshipId = "REL1", + Peer = relationshipTo + }; + + var mockDbContext = A.Fake(); + + var externalEvent = new ExternalEvent(ExternalEventType.RelationshipStatusChanged, relationshipTo, 1, + new { @event.RelationshipId }); + + A.CallTo(() => mockDbContext.CreateExternalEvent( + relationshipTo, + ExternalEventType.RelationshipStatusChanged, + A._) + ).Returns(externalEvent); + + var handler = CreateHandler(mockDbContext); + + // Act + await handler.Handle(@event); + + // Assert + A.CallTo(() => mockDbContext.CreateExternalEvent(relationshipTo, ExternalEventType.RelationshipStatusChanged, A._)) + .MustHaveHappenedOnceExactly(); + } + + [Fact] + public async Task Publishes_an_ExternalEventCreatedIntegrationEvent() + { + // Arrange + var relationshipTo = TestDataGenerator.CreateRandomIdentityAddress(); + var @event = new RelationshipStatusChangedIntegrationEvent + { + RelationshipId = "REL1", + Peer = relationshipTo + }; + + var fakeDbContext = A.Fake(); + var mockEventBus = A.Fake(); + + var externalEvent = new ExternalEvent(ExternalEventType.IdentityDeletionProcessStarted, IdentityAddress.Parse(relationshipTo), 1, + new { @event.RelationshipId }); + + A.CallTo(() => fakeDbContext.CreateExternalEvent( + relationshipTo, + ExternalEventType.RelationshipStatusChanged, + A._) + ).Returns(externalEvent); + + var handler = CreateHandler(fakeDbContext, mockEventBus); + + // Act + await handler.Handle(@event); + + // Assert + A.CallTo(() => mockEventBus.Publish( + A.That.Matches(e => e.Owner == relationshipTo)) + ).MustHaveHappenedOnceExactly(); + } + + private RelationshipStatusChangedIntegrationEventHandler CreateHandler(ISynchronizationDbContext dbContext, IEventBus? eventBus = null) + { + eventBus ??= A.Fake(); + return new RelationshipStatusChangedIntegrationEventHandler(dbContext, eventBus, A.Fake>()); + } +} diff --git a/openapi.yml b/openapi.yml new file mode 100644 index 0000000000..40344f475d --- /dev/null +++ b/openapi.yml @@ -0,0 +1,349 @@ +openapi: 3.1.0 +info: + version: "2" + title: Relationships API v2 + +paths: + "/api/v1/Relationships/{id}": + get: + tags: + - Relationships + parameters: + - name: id + in: path + required: true + style: simple + schema: + type: string + example: "REL_________________" + nullable: false + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeRelationship" + "404": + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "/api/v1/Relationships": + get: + tags: + - Relationships + parameters: + - name: PageNumber + in: query + style: form + required: false + schema: + type: integer + - name: PageSize + in: query + style: form + required: false + schema: + type: integer + format: int32 + - name: ids + in: query + style: form + required: true + schema: + type: array + items: + type: string + example: "REL_________________" + nullable: false + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/PagedHttpResponseEnvelopeListRelationshipsResponse" + post: + tags: + - Relationships + requestBody: + content: + application/json: + schema: + type: object + properties: + relationshipTemplateId: + type: string + example: "RLT_________________" + nullable: false + creationContent: + type: string + format: byte + nullable: false + additionalProperties: false + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeRelationshipMetadata" + "400": + description: > + Bad Request

+ Can contain one of the following error codes: + - `error.platform.validation.relationshipRequest.cannotSendRelationshipRequestToYourself` + - `error.platform.validation.relationshipRequest.relationshipToTargetAlreadyExists` + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + + "404": + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "/api/v1/Relationships/{id}/Accept": + put: + tags: + - Relationships + parameters: + - name: id + in: path + required: true + style: simple + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeRelationshipMetadata" + "400": + description: > + Bad Request

+ Can contain one of the following error codes: + - `error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse` + - `error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus` + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "404": + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "/api/v1/Relationships/{id}/Reject": + put: + tags: + - Relationships + parameters: + - name: id + in: path + required: true + style: simple + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeRelationshipMetadata" + "400": + description: > + Bad Request

+ Can contain one of the following error codes: + - `error.platform.validation.relationshipRequest.cannotAcceptOrRejectRelationshipRequestAddressedToSomeoneElse` + - `error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus` + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "404": + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "/api/v1/Relationships/{id}/Revoke": + put: + tags: + - Relationships + parameters: + - name: id + in: path + required: true + style: simple + schema: + type: string + responses: + "200": + description: Success + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeRelationshipMetadata" + "400": + description: > + Bad Request

+ Can contain one of the following error codes: + - `error.platform.validation.relationshipRequest.cannotRevokeRelationshipRequestNotCreatedByYourself` + - `error.platform.validation.relationshipRequest.relationshipIsNotInCorrectStatus` + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + "404": + description: Not Found + content: + application/json: + schema: + "$ref": "#/components/schemas/HttpResponseEnvelopeError" + +components: + securitySchemes: + oauth: + type: "oauth2" + flows: + password: + tokenUrl: "http://localhost:8081/connect/token" + scopes: {} + schemas: + HttpResponseEnvelopeRelationship: + type: object + properties: + result: + $ref: "#/components/schemas/Relationship" + + HttpResponseEnvelopeRelationshipMetadata: + type: object + properties: + result: + $ref: "#/components/schemas/RelationshipMetadata" + + Relationship: + type: object + properties: + id: + type: string + example: "REL_________________" + relationshipTemplateId: + type: string + example: "RLT_________________" + from: + type: string + example: "id1_________________________________" + to: + type: string + example: "id1_________________________________" + createdAt: + type: string + format: date-time + status: + $ref: "#/components/schemas/RelationshipStatus" + auditLog: + type: array + items: + $ref: "#/components/schemas/RelationshipAuditLogEntry" + additionalProperties: false + + RelationshipMetadata: + type: object + properties: + id: + type: string + example: "REL_________________" + relationshipTemplateId: + type: string + example: "RLT_________________" + from: + type: string + example: "id1_________________________________" + to: + type: string + example: "id1_________________________________" + createdAt: + type: string + format: date-time + status: + $ref: "#/components/schemas/RelationshipStatus" + creationContent: + type: string + format: byte + auditLog: + type: array + items: + $ref: "#/components/schemas/RelationshipAuditLogEntry" + additionalProperties: false + + RelationshipAuditLogEntry: + type: object + properties: + createdAt: + type: string + format: date-time + createdBy: + type: string + example: "id1_________________________________" + createdByDevice: + type: string + example: "DVC_________________" + reason: + type: string + example: "Creation|AcceptanceOfCreation|RejectionOfCreation|RevocationOfCreation" + enum: + - Creation + - AcceptanceOfCreation + - RejectionOfCreation + - RevocationOfCreation + oldStatus: + allOf: + - $ref: "#/components/schemas/RelationshipStatus" + nullable: true + newStatus: + allOf: + - $ref: "#/components/schemas/RelationshipStatus" + additionalProperties: false + + RelationshipStatus: + type: string + enum: + - Pending + - Active + - Rejected + - Revoked + example: "Pending|Accepted|Rejected|Revoked" + + HttpResponseEnvelopeError: + type: object + properties: + error: + $ref: "#/components/schemas/HttpError" + additionalProperties: false + + HttpError: + type: object + properties: + id: + type: string + example: "ERR_________________" + code: + type: string + message: + type: string + docs: + type: string + time: + type: string + format: date-time + additionalProperties: false