From 4473bf6ea7a4edf58af8c4981054ceefdd60f98a Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Mon, 27 Jan 2025 09:35:33 +0100 Subject: [PATCH 01/21] feat: revoke relationship in status pending when the neded attribute is deleted --- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 10 +- .../test/consumption/attributes.test.ts | 98 +++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 0454747b3..971df50fe 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -2,7 +2,7 @@ import { Result } from "@js-soft/ts-utils"; import { AttributesController, ConsumptionIds, LocalAttribute } from "@nmshd/consumption"; import { Notification, OwnSharedAttributeDeletedByOwnerNotificationItem } from "@nmshd/content"; import { CoreId } from "@nmshd/core-types"; -import { AccountController, MessageController } from "@nmshd/transport"; +import { AccountController, MessageController, RelationshipsController, RelationshipStatus } from "@nmshd/transport"; import { Inject } from "@nmshd/typescript-ioc"; import { AttributeIdString, NotificationIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; @@ -25,6 +25,7 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { expect(updatedPredecessor.deletionInfo?.deletionStatus).toStrictEqual(LocalAttributeDeletionStatus.DeletedByOwner); expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); + + test.only("should revoke a relationship when a repository attribute is deleted that was required in an pending relationship", async () => { + const [services1, services2] = await runtimeServiceProvider.launch(2, { + enableRequestModule: true, + enableDeciderModule: true, + enableNotificationModule: true + }); + + const item: ReadAttributeRequestItemJSON = { + "@type": "ReadAttributeRequestItem", + mustBeAccepted: true, + query: { + "@type": "IdentityAttributeQuery", + valueType: "GivenName" + } + }; + + const content: CreateOwnRelationshipTemplateRequest["content"] = { + "@type": "RelationshipTemplateContent", + title: "Connect to HCM", + onNewRelationship: { + title: "Connect to HCM2", + items: [item], + "@type": "Request" + } + }; + + const relationshipTemplateResult = await services1.transport.relationshipTemplates.createOwnRelationshipTemplate({ + content, + expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() + }); + + const loadedPeerTemplateResult = await services2.transport.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: relationshipTemplateResult.value.truncatedReference + }); + + await services2.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { + return event.data.template.id === loadedPeerTemplateResult.value.id; + }); + + const repositoryAttribute = await services2.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "123qwe" + } + } + }); + + expect(repositoryAttribute).toBeSuccessful(); + + const requestsForRelationship = await services2.consumption.incomingRequests.getRequests({ + query: { + "source.reference": loadedPeerTemplateResult.value.id + } + }); + + const acceptRequest = await services2.consumption.incomingRequests.accept({ + requestId: requestsForRelationship.value[0].id, + items: [ + { + accept: true, + existingAttributeId: repositoryAttribute.value.id + } as AcceptReadAttributeRequestItemParametersWithExistingAttributeJSON + ] + }); + + expect(acceptRequest).toBeSuccessful(); + + const relationships = await syncUntilHasRelationships(services1.transport); + expect(relationships).toHaveLength(1); + + const sharedAttribute = await services2.consumption.attributes.getAttributes({ + query: { + "shareInfo.sourceAttribute": repositoryAttribute.value.id + } + }); + + const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: sharedAttribute.value[0].id }); + + expect(attributeDeletion).toBeSuccessful(); + + // const acceptResponse = await services1.transport.relationships.acceptRelationship({ + // relationshipId: relationships[0].id + // }); + // expect(acceptResponse).toBeSuccessful(); + + // const relationships2 = await syncUntilHasRelationships(services2.transport); + // expect(relationships2).toHaveLength(1); + + // const attributes = await services1.consumption.attributes.getAttributes({}); + // const attributes2 = await services2.consumption.attributes.getAttributes({}); + }); }); describe(DeletePeerSharedAttributeAndNotifyOwnerUseCase.name, () => { From 4f8d26e395f584aa27eda43e22fc907ff7822495 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Mon, 27 Jan 2025 09:42:27 +0100 Subject: [PATCH 02/21] chore: remove focused test --- packages/runtime/test/consumption/attributes.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index 130cb2049..26a1d4fff 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -2311,7 +2311,7 @@ describe("DeleteAttributeUseCases", () => { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test.only("should revoke a relationship when a repository attribute is deleted that was required in an pending relationship", async () => { + test("should revoke a relationship when a repository attribute is deleted that was required in an pending relationship", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, From 5e2237af2f651cd1338f41fbd5720cc7fc7377b6 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Fri, 31 Jan 2025 11:38:26 +0100 Subject: [PATCH 03/21] feat: add error message when deleting an attribute while a relationship is still in Pending state --- .../src/useCases/common/RuntimeErrors.ts | 7 + .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 16 +- ...DeletePeerSharedAttributeAndNotifyOwner.ts | 9 +- ...PartyRelationshipAttributeAndNotifyPeer.ts | 10 +- .../test/consumption/attributes.test.ts | 190 ++++++++++++++++-- .../src/modules/messages/MessageController.ts | 5 +- 6 files changed, 210 insertions(+), 27 deletions(-) diff --git a/packages/runtime/src/useCases/common/RuntimeErrors.ts b/packages/runtime/src/useCases/common/RuntimeErrors.ts index cdb8d716a..7d83a87e1 100644 --- a/packages/runtime/src/useCases/common/RuntimeErrors.ts +++ b/packages/runtime/src/useCases/common/RuntimeErrors.ts @@ -253,6 +253,13 @@ class Attributes { public setDefaultRepositoryAttributesIsDisabled(): ApplicationError { return new ApplicationError("error.runtime.attributes.setDefaultRepositoryAttributesIsDisabled", "Setting default RepositoryAttributes is disabled for this Account."); } + + public cannotDeleteSharedAttributeWhileRelationshipIsPending(): ApplicationError { + return new ApplicationError( + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending", + "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending." + ); + } } class IdentityDeletionProcess { diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 971df50fe..efca6d652 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -2,8 +2,9 @@ import { Result } from "@js-soft/ts-utils"; import { AttributesController, ConsumptionIds, LocalAttribute } from "@nmshd/consumption"; import { Notification, OwnSharedAttributeDeletedByOwnerNotificationItem } from "@nmshd/content"; import { CoreId } from "@nmshd/core-types"; -import { AccountController, MessageController, RelationshipsController, RelationshipStatus } from "@nmshd/transport"; +import { AccountController, MessageController, RelationshipsController } from "@nmshd/transport"; import { Inject } from "@nmshd/typescript-ioc"; +import { RelationshipStatus } from "../../../types"; import { AttributeIdString, NotificationIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; export interface DeleteOwnSharedAttributeAndNotifyPeerRequest { @@ -40,6 +41,12 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should revoke a relationship when a repository attribute is deleted that was required in an pending relationship", async () => { + test("should throw an error when deleting an OwnSharedAttribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, @@ -2742,26 +2743,18 @@ describe("DeleteAttributeUseCases", () => { const relationships = await syncUntilHasRelationships(services1.transport); expect(relationships).toHaveLength(1); - const sharedAttribute = await services2.consumption.attributes.getAttributes({ + const ownSharedAttribute = await services2.consumption.attributes.getAttributes({ query: { "shareInfo.sourceAttribute": repositoryAttribute.value.id } }); - const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: sharedAttribute.value[0].id }); + const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); - expect(attributeDeletion).toBeSuccessful(); - - // const acceptResponse = await services1.transport.relationships.acceptRelationship({ - // relationshipId: relationships[0].id - // }); - // expect(acceptResponse).toBeSuccessful(); - - // const relationships2 = await syncUntilHasRelationships(services2.transport); - // expect(relationships2).toHaveLength(1); - - // const attributes = await services1.consumption.attributes.getAttributes({}); - // const attributes2 = await services2.consumption.attributes.getAttributes({}); + expect(attributeDeletion).toBeAnError( + "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + ); }); }); @@ -2878,6 +2871,88 @@ describe("DeleteAttributeUseCases", () => { expect(updatedPredecessor.deletionInfo?.deletionStatus).toStrictEqual(LocalAttributeDeletionStatus.DeletedByPeer); expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); + + test("should throw an error when deleting an OwnSharedAttribute when the Relationship is in status Pending", async () => { + const [services1, services2] = await runtimeServiceProvider.launch(2, { + enableRequestModule: true, + enableDeciderModule: true, + enableNotificationModule: true + }); + + const repositoryAttribute = await services1.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "123qwe" + } + } + }); + + const item: ShareAttributeRequestItemJSON = { + "@type": "ShareAttributeRequestItem", + mustBeAccepted: true, + attribute: repositoryAttribute.value.content, + sourceAttributeId: repositoryAttribute.value.id + }; + + const content: CreateOwnRelationshipTemplateRequest["content"] = { + "@type": "RelationshipTemplateContent", + title: "Connect to HCM", + onNewRelationship: { + title: "Connect to HCM2", + items: [item], + "@type": "Request" + } + }; + + const relationshipTemplateResult = await services1.transport.relationshipTemplates.createOwnRelationshipTemplate({ + content, + expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() + }); + + const loadedPeerTemplateResult = await services2.transport.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: relationshipTemplateResult.value.truncatedReference + }); + + await services2.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { + return event.data.template.id === loadedPeerTemplateResult.value.id; + }); + + expect(repositoryAttribute).toBeSuccessful(); + + const requestsForRelationship = await services2.consumption.incomingRequests.getRequests({ + query: { + "source.reference": loadedPeerTemplateResult.value.id + } + }); + + const acceptRequest = await services2.consumption.incomingRequests.accept({ + requestId: requestsForRelationship.value[0].id, + items: [ + { + accept: true + } as AcceptRequestItemParametersJSON + ] + }); + + expect(acceptRequest).toBeSuccessful(); + + const relationships = await syncUntilHasRelationships(services1.transport); + expect(relationships).toHaveLength(1); + + const peerSharedAttribute = await services2.consumption.attributes.getAttributes({ + query: { + "shareInfo.requestReference": requestsForRelationship.value[0].id + } + }); + + const attributeDeletion = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); + + expect(attributeDeletion).toBeAnError( + "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + ); + }); }); describe(DeleteThirdPartyRelationshipAttributeAndNotifyPeerUseCase.name, () => { @@ -2994,6 +3069,89 @@ describe("DeleteAttributeUseCases", () => { const getDeletedAttributeResult = await services1.consumption.attributes.getAttribute({ id: emittedThirdPartyRelationshipAttribute.id }); expect(getDeletedAttributeResult).toBeAnError(/.*/, "error.runtime.recordNotFound"); }); + + test("should throw an error when deleting a ThirdPartyRelationshipAttribute when the Relationship is in status Pending", async () => { + const [services1, services2, services3] = await runtimeServiceProvider.launch(3, { + enableRequestModule: true, + enableDeciderModule: true, + enableNotificationModule: true + }); + await establishRelationship(services1.transport, services2.transport); + const peerSharedRelationshipAttribute = await executeFullCreateAndShareRelationshipAttributeFlow(services2, services1, { + content: { + value: { + "@type": "ProprietaryString", + value: "aString", + title: "aTitle" + }, + key: "aKey", + confidentiality: RelationshipAttributeConfidentiality.Public + } + }); + + const item: ShareAttributeRequestItemJSON = { + "@type": "ShareAttributeRequestItem", + mustBeAccepted: true, + attribute: peerSharedRelationshipAttribute.content, + sourceAttributeId: peerSharedRelationshipAttribute.id, + thirdPartyAddress: services1.address + }; + + const content: CreateOwnRelationshipTemplateRequest["content"] = { + "@type": "RelationshipTemplateContent", + title: "Connect to HCM", + onNewRelationship: { + title: "Connect to HCM2", + items: [item], + "@type": "Request" + } + }; + + const relationshipTemplateResult = await services2.transport.relationshipTemplates.createOwnRelationshipTemplate({ + content, + expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() + }); + + const loadedPeerTemplateResult = await services3.transport.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: relationshipTemplateResult.value.truncatedReference + }); + + await services3.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { + return event.data.template.id === loadedPeerTemplateResult.value.id; + }); + + const requestsForRelationship = await services3.consumption.incomingRequests.getRequests({ + query: { + "source.reference": loadedPeerTemplateResult.value.id + } + }); + + const acceptRequest = await services3.consumption.incomingRequests.accept({ + requestId: requestsForRelationship.value[0].id, + items: [ + { + accept: true + } as AcceptRequestItemParametersJSON + ] + }); + + expect(acceptRequest).toBeSuccessful(); + + const relationships = await syncUntilHasRelationships(services2.transport); + expect(relationships).toHaveLength(1); + + const thirdPartyRelationshipAttribute = await services3.consumption.attributes.getAttributes({ + query: { + "shareInfo.requestReference": requestsForRelationship.value[0].id + } + }); + const attributeDeletion = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: thirdPartyRelationshipAttribute.value[0].id }); + + expect(attributeDeletion).toBeAnError( + "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + ); + }); }); }); diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index 965a4d769..ab3bc67a9 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -427,7 +427,10 @@ export class MessageController extends TransportController { for (const recipient of recipients) { const relationship = await this.relationships.getRelationshipToIdentity(recipient); - if (!relationship || !(relationship.status === RelationshipStatus.Terminated || relationship.status === RelationshipStatus.Active)) { + if ( + !relationship || + !(relationship.status === RelationshipStatus.Terminated || relationship.status === RelationshipStatus.Active || relationship.status === RelationshipStatus.Pending) + ) { peersWithNeitherActiveNorTerminatedRelationship.push(recipient.address); continue; } From 77cb61f9f67f1303eec911efcc788aaf38d3a7a4 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Fri, 31 Jan 2025 11:49:19 +0100 Subject: [PATCH 04/21] revert: unwanted change --- packages/transport/src/modules/messages/MessageController.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index dee93bcec..88f819234 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -426,10 +426,7 @@ export class MessageController extends TransportController { for (const recipient of recipients) { const relationship = await this.relationships.getRelationshipToIdentity(recipient); - if ( - !relationship || - !(relationship.status === RelationshipStatus.Terminated || relationship.status === RelationshipStatus.Active || relationship.status === RelationshipStatus.Pending) - ) { + if (!relationship || !(relationship.status === RelationshipStatus.Terminated || relationship.status === RelationshipStatus.Active)) { peersWithNeitherActiveNorTerminatedRelationship.push(recipient.address); continue; } From 4e6814f5222eb1d637b3df8236f7bc04037613c0 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Fri, 31 Jan 2025 15:38:49 +0100 Subject: [PATCH 05/21] chore: pr comments --- .../src/useCases/common/RuntimeErrors.ts | 2 +- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 5 ++-- ...DeletePeerSharedAttributeAndNotifyOwner.ts | 7 ++--- ...PartyRelationshipAttributeAndNotifyPeer.ts | 5 ++-- .../test/consumption/attributes.test.ts | 27 +++++++++---------- .../relationships/RelationshipsController.ts | 9 +++++++ 6 files changed, 30 insertions(+), 25 deletions(-) diff --git a/packages/runtime/src/useCases/common/RuntimeErrors.ts b/packages/runtime/src/useCases/common/RuntimeErrors.ts index 7d83a87e1..8fffcdeb2 100644 --- a/packages/runtime/src/useCases/common/RuntimeErrors.ts +++ b/packages/runtime/src/useCases/common/RuntimeErrors.ts @@ -257,7 +257,7 @@ class Attributes { public cannotDeleteSharedAttributeWhileRelationshipIsPending(): ApplicationError { return new ApplicationError( "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending", - "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending." + "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'." ); } } diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index efca6d652..24bcc7e98 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -4,7 +4,6 @@ import { Notification, OwnSharedAttributeDeletedByOwnerNotificationItem } from " import { CoreId } from "@nmshd/core-types"; import { AccountController, MessageController, RelationshipsController } from "@nmshd/transport"; import { Inject } from "@nmshd/typescript-ioc"; -import { RelationshipStatus } from "../../../types"; import { AttributeIdString, NotificationIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; export interface DeleteOwnSharedAttributeAndNotifyPeerRequest { @@ -41,9 +40,9 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { const content: CreateOwnRelationshipTemplateRequest["content"] = { "@type": "RelationshipTemplateContent", - title: "Connect to HCM", + title: "aTitle", onNewRelationship: { - title: "Connect to HCM2", items: [item], "@type": "Request" } @@ -2715,7 +2714,7 @@ describe("DeleteAttributeUseCases", () => { content: { value: { "@type": "GivenName", - value: "123qwe" + value: "aGivenName" } } }); @@ -2728,7 +2727,7 @@ describe("DeleteAttributeUseCases", () => { } }); - const acceptRequest = await services2.consumption.incomingRequests.accept({ + const acceptedRequest = await services2.consumption.incomingRequests.accept({ requestId: requestsForRelationship.value[0].id, items: [ { @@ -2738,7 +2737,7 @@ describe("DeleteAttributeUseCases", () => { ] }); - expect(acceptRequest).toBeSuccessful(); + expect(acceptedRequest).toBeSuccessful(); const relationships = await syncUntilHasRelationships(services1.transport); expect(relationships).toHaveLength(1); @@ -2872,7 +2871,7 @@ describe("DeleteAttributeUseCases", () => { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should throw an error when deleting an OwnSharedAttribute when the Relationship is in status Pending", async () => { + test("should throw an error when deleting an PeerSharedAttribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, @@ -2883,7 +2882,7 @@ describe("DeleteAttributeUseCases", () => { content: { value: { "@type": "GivenName", - value: "123qwe" + value: "aGivenName" } } }); @@ -2897,9 +2896,8 @@ describe("DeleteAttributeUseCases", () => { const content: CreateOwnRelationshipTemplateRequest["content"] = { "@type": "RelationshipTemplateContent", - title: "Connect to HCM", + title: "aTitle", onNewRelationship: { - title: "Connect to HCM2", items: [item], "@type": "Request" } @@ -2926,7 +2924,7 @@ describe("DeleteAttributeUseCases", () => { } }); - const acceptRequest = await services2.consumption.incomingRequests.accept({ + const acceptedRequest = await services2.consumption.incomingRequests.accept({ requestId: requestsForRelationship.value[0].id, items: [ { @@ -2935,7 +2933,7 @@ describe("DeleteAttributeUseCases", () => { ] }); - expect(acceptRequest).toBeSuccessful(); + expect(acceptedRequest).toBeSuccessful(); const relationships = await syncUntilHasRelationships(services1.transport); expect(relationships).toHaveLength(1); @@ -3099,9 +3097,8 @@ describe("DeleteAttributeUseCases", () => { const content: CreateOwnRelationshipTemplateRequest["content"] = { "@type": "RelationshipTemplateContent", - title: "Connect to HCM", + title: "aTitle", onNewRelationship: { - title: "Connect to HCM2", items: [item], "@type": "Request" } @@ -3126,7 +3123,7 @@ describe("DeleteAttributeUseCases", () => { } }); - const acceptRequest = await services3.consumption.incomingRequests.accept({ + const acceptedRequest = await services3.consumption.incomingRequests.accept({ requestId: requestsForRelationship.value[0].id, items: [ { @@ -3135,7 +3132,7 @@ describe("DeleteAttributeUseCases", () => { ] }); - expect(acceptRequest).toBeSuccessful(); + expect(acceptedRequest).toBeSuccessful(); const relationships = await syncUntilHasRelationships(services2.transport); expect(relationships).toHaveLength(1); diff --git a/packages/transport/src/modules/relationships/RelationshipsController.ts b/packages/transport/src/modules/relationships/RelationshipsController.ts index 53cfeee79..5862d77d3 100644 --- a/packages/transport/src/modules/relationships/RelationshipsController.ts +++ b/packages/transport/src/modules/relationships/RelationshipsController.ts @@ -655,4 +655,13 @@ export class RelationshipsController extends TransportController { return relationship; } + + public async canSendMessage(recipient: CoreAddress): Promise> { + const relationship = await this.getRelationshipToIdentity(recipient, RelationshipStatus.Pending); + if (relationship) { + Result.fail(TransportCoreErrors.messages.hasNeitherActiveNorTerminatedRelationship([recipient.address])); + } + + return Result.ok(undefined); + } } From f670e7e6471d7e16cf1656a86b4b667f8e807dc0 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 08:35:48 +0100 Subject: [PATCH 06/21] chore: pr comments --- .../src/useCases/common/RuntimeErrors.ts | 6 +- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 6 +- ...DeletePeerSharedAttributeAndNotifyOwner.ts | 6 +- ...PartyRelationshipAttributeAndNotifyPeer.ts | 6 +- .../test/consumption/attributes.test.ts | 145 ++++-------------- packages/runtime/test/lib/testUtils.ts | 41 ++++- .../src/modules/messages/MessageController.ts | 4 +- .../relationships/RelationshipsController.ts | 9 -- 8 files changed, 83 insertions(+), 140 deletions(-) diff --git a/packages/runtime/src/useCases/common/RuntimeErrors.ts b/packages/runtime/src/useCases/common/RuntimeErrors.ts index d90f1155a..51f77836b 100644 --- a/packages/runtime/src/useCases/common/RuntimeErrors.ts +++ b/packages/runtime/src/useCases/common/RuntimeErrors.ts @@ -268,10 +268,10 @@ class Attributes { return new ApplicationError("error.runtime.attributes.setDefaultRepositoryAttributesIsDisabled", "Setting default RepositoryAttributes is disabled for this Account."); } - public cannotDeleteSharedAttributeWhileRelationshipIsPending(): ApplicationError { + public cannotDeleteSharedAttributeBecausePeerCannotBeNotified(): ApplicationError { return new ApplicationError( - "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending", - "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'." + "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified", + "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion." ); } } diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 24bcc7e98..b97270664 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -40,10 +40,10 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should throw an error when deleting an OwnSharedAttribute when the Relationship is in status Pending", async () => { + test("should throw an error trying to delete an own shared Attribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, @@ -2688,7 +2688,7 @@ describe("DeleteAttributeUseCases", () => { } }; - const content: CreateOwnRelationshipTemplateRequest["content"] = { + const content: RelationshipTemplateContentJSON = { "@type": "RelationshipTemplateContent", title: "aTitle", onNewRelationship: { @@ -2697,19 +2697,6 @@ describe("DeleteAttributeUseCases", () => { } }; - const relationshipTemplateResult = await services1.transport.relationshipTemplates.createOwnRelationshipTemplate({ - content, - expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() - }); - - const loadedPeerTemplateResult = await services2.transport.relationshipTemplates.loadPeerRelationshipTemplate({ - reference: relationshipTemplateResult.value.truncatedReference - }); - - await services2.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { - return event.data.template.id === loadedPeerTemplateResult.value.id; - }); - const repositoryAttribute = await services2.consumption.attributes.createRepositoryAttribute({ content: { value: { @@ -2719,28 +2706,12 @@ describe("DeleteAttributeUseCases", () => { } }); - expect(repositoryAttribute).toBeSuccessful(); - - const requestsForRelationship = await services2.consumption.incomingRequests.getRequests({ - query: { - "source.reference": loadedPeerTemplateResult.value.id - } - }); - - const acceptedRequest = await services2.consumption.incomingRequests.accept({ - requestId: requestsForRelationship.value[0].id, - items: [ - { - accept: true, - existingAttributeId: repositoryAttribute.value.id - } as AcceptReadAttributeRequestItemParametersWithExistingAttributeJSON - ] - }); - - expect(acceptedRequest).toBeSuccessful(); - - const relationships = await syncUntilHasRelationships(services1.transport); - expect(relationships).toHaveLength(1); + await createRelationshipInPendingState(services1, services2, content, [ + { + accept: true, + existingAttributeId: repositoryAttribute.value.id + } as AcceptReadAttributeRequestItemParametersWithExistingAttributeJSON + ]); const ownSharedAttribute = await services2.consumption.attributes.getAttributes({ query: { @@ -2751,8 +2722,8 @@ describe("DeleteAttributeUseCases", () => { const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", - "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", + "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" ); }); }); @@ -2871,7 +2842,7 @@ describe("DeleteAttributeUseCases", () => { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should throw an error when deleting an PeerSharedAttribute when the Relationship is in status Pending", async () => { + test("should throw an error trying to delete an PeerSharedAttribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, @@ -2903,52 +2874,23 @@ describe("DeleteAttributeUseCases", () => { } }; - const relationshipTemplateResult = await services1.transport.relationshipTemplates.createOwnRelationshipTemplate({ - content, - expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() - }); - - const loadedPeerTemplateResult = await services2.transport.relationshipTemplates.loadPeerRelationshipTemplate({ - reference: relationshipTemplateResult.value.truncatedReference - }); - - await services2.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { - return event.data.template.id === loadedPeerTemplateResult.value.id; - }); - - expect(repositoryAttribute).toBeSuccessful(); - - const requestsForRelationship = await services2.consumption.incomingRequests.getRequests({ - query: { - "source.reference": loadedPeerTemplateResult.value.id - } - }); - - const acceptedRequest = await services2.consumption.incomingRequests.accept({ - requestId: requestsForRelationship.value[0].id, - items: [ - { - accept: true - } as AcceptRequestItemParametersJSON - ] - }); - - expect(acceptedRequest).toBeSuccessful(); - - const relationships = await syncUntilHasRelationships(services1.transport); - expect(relationships).toHaveLength(1); + await createRelationshipInPendingState(services1, services2, content, [ + { + accept: true + } as AcceptRequestItemParametersJSON + ]); const peerSharedAttribute = await services2.consumption.attributes.getAttributes({ query: { - "shareInfo.requestReference": requestsForRelationship.value[0].id + "shareInfo.peer": services1.address } }); const attributeDeletion = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", - "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", + "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" ); }); }); @@ -3068,7 +3010,7 @@ describe("DeleteAttributeUseCases", () => { expect(getDeletedAttributeResult).toBeAnError(/.*/, "error.runtime.recordNotFound"); }); - test("should throw an error when deleting a ThirdPartyRelationshipAttribute when the Relationship is in status Pending", async () => { + test("should throw an error trying to delete a ThirdPartyRelationshipAttribute when the Relationship is in status Pending", async () => { const [services1, services2, services3] = await runtimeServiceProvider.launch(3, { enableRequestModule: true, enableDeciderModule: true, @@ -3104,49 +3046,22 @@ describe("DeleteAttributeUseCases", () => { } }; - const relationshipTemplateResult = await services2.transport.relationshipTemplates.createOwnRelationshipTemplate({ - content, - expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() - }); - - const loadedPeerTemplateResult = await services3.transport.relationshipTemplates.loadPeerRelationshipTemplate({ - reference: relationshipTemplateResult.value.truncatedReference - }); - - await services3.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { - return event.data.template.id === loadedPeerTemplateResult.value.id; - }); - - const requestsForRelationship = await services3.consumption.incomingRequests.getRequests({ - query: { - "source.reference": loadedPeerTemplateResult.value.id - } - }); - - const acceptedRequest = await services3.consumption.incomingRequests.accept({ - requestId: requestsForRelationship.value[0].id, - items: [ - { - accept: true - } as AcceptRequestItemParametersJSON - ] - }); - - expect(acceptedRequest).toBeSuccessful(); - - const relationships = await syncUntilHasRelationships(services2.transport); - expect(relationships).toHaveLength(1); + await createRelationshipInPendingState(services2, services3, content, [ + { + accept: true + } as AcceptRequestItemParametersJSON + ]); const thirdPartyRelationshipAttribute = await services3.consumption.attributes.getAttributes({ query: { - "shareInfo.requestReference": requestsForRelationship.value[0].id + "shareInfo.peer": services2.address } }); const attributeDeletion = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: thirdPartyRelationshipAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted while the Relationship to the Peer is in status Pending.", - "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" + "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", + "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" ); }); }); diff --git a/packages/runtime/test/lib/testUtils.ts b/packages/runtime/test/lib/testUtils.ts index 2e991bc8a..63d4c7568 100644 --- a/packages/runtime/test/lib/testUtils.ts +++ b/packages/runtime/test/lib/testUtils.ts @@ -4,7 +4,8 @@ import { AcceptRequestItemParametersJSON, ConsumptionIds, DecideRequestItemGroupParametersJSON, - DecideRequestItemParametersJSON + DecideRequestItemParametersJSON, + DecideRequestParametersJSON } from "@nmshd/consumption"; import { ArbitraryRelationshipCreationContent, @@ -23,7 +24,7 @@ import { ShareAttributeAcceptResponseItemJSON, ShareAttributeRequestItem } from "@nmshd/content"; -import { CoreAddress, CoreId } from "@nmshd/core-types"; +import { CoreAddress, CoreDate, CoreId } from "@nmshd/core-types"; import { CoreBuffer } from "@nmshd/crypto"; import { IdentityUtil } from "@nmshd/transport"; import fs from "fs"; @@ -54,6 +55,7 @@ import { RelationshipDTO, RelationshipStatus, RelationshipTemplateDTO, + RelationshipTemplateProcessedEvent, ShareRepositoryAttributeRequest, SucceedRepositoryAttributeRequest, SucceedRepositoryAttributeResponse, @@ -915,3 +917,38 @@ export async function cleanupAttributes(...services: TestRuntimeServices[]): Pro }) ); } + +export async function createRelationshipInPendingState( + sender: TestRuntimeServices, + receiver: TestRuntimeServices, + templateContent: RelationshipTemplateContentJSON, + acceptItems: DecideRequestParametersJSON["items"] +): Promise { + const relationshipTemplateResult = await sender.transport.relationshipTemplates.createOwnRelationshipTemplate({ + content: templateContent, + expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() + }); + + const loadedPeerTemplateResult = await receiver.transport.relationshipTemplates.loadPeerRelationshipTemplate({ + reference: relationshipTemplateResult.value.truncatedReference + }); + + await receiver.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { + return event.data.template.id === loadedPeerTemplateResult.value.id; + }); + + const requestsForRelationship = await receiver.consumption.incomingRequests.getRequests({ + query: { + "source.reference": loadedPeerTemplateResult.value.id + } + }); + + await receiver.consumption.incomingRequests.accept({ + requestId: requestsForRelationship.value[0].id, + items: acceptItems + }); + + const relationships = await syncUntilHasRelationships(sender.transport); + expect(relationships).toHaveLength(1); + return relationships[0]; +} diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index 88f819234..f404d6e16 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -1,6 +1,6 @@ import { ISerializable } from "@js-soft/ts-serval"; import { log } from "@js-soft/ts-utils"; -import { CoreAddress, CoreDate, CoreId, ICoreAddress, ICoreId } from "@nmshd/core-types"; +import { CoreAddress, CoreDate, CoreError, CoreId, ICoreAddress, ICoreId } from "@nmshd/core-types"; import { CoreBuffer, CryptoCipher, CryptoSecretKey } from "@nmshd/crypto"; import { nameof } from "ts-simple-nameof"; import { CoreCrypto, TransportCoreErrors, TransportError } from "../../core"; @@ -419,7 +419,7 @@ export class MessageController extends TransportController { return message; } - private async validateMessageRecipients(recipients: CoreAddress[]) { + public async validateMessageRecipients(recipients: CoreAddress[]): Promise { const peersWithNeitherActiveNorTerminatedRelationship: string[] = []; const deletedPeers: string[] = []; diff --git a/packages/transport/src/modules/relationships/RelationshipsController.ts b/packages/transport/src/modules/relationships/RelationshipsController.ts index 5862d77d3..53cfeee79 100644 --- a/packages/transport/src/modules/relationships/RelationshipsController.ts +++ b/packages/transport/src/modules/relationships/RelationshipsController.ts @@ -655,13 +655,4 @@ export class RelationshipsController extends TransportController { return relationship; } - - public async canSendMessage(recipient: CoreAddress): Promise> { - const relationship = await this.getRelationshipToIdentity(recipient, RelationshipStatus.Pending); - if (relationship) { - Result.fail(TransportCoreErrors.messages.hasNeitherActiveNorTerminatedRelationship([recipient.address])); - } - - return Result.ok(undefined); - } } From cd7fcdcb2d9a35a7de53509b97fdfa019febeb6e Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 10:25:01 +0100 Subject: [PATCH 07/21] Update packages/runtime/test/consumption/attributes.test.ts Co-authored-by: Britta Stallknecht <146106656+britsta@users.noreply.github.com> --- packages/runtime/test/consumption/attributes.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index 7c047a217..a374801db 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -2842,7 +2842,7 @@ describe("DeleteAttributeUseCases", () => { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should throw an error trying to delete an PeerSharedAttribute when the Relationship is in status Pending", async () => { + test("should throw an error trying to delete a PeerSharedAttribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, From af5fc20e5780b7cba37d2733ab90cf3dc2662464 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 10:52:26 +0100 Subject: [PATCH 08/21] Update packages/runtime/test/lib/testUtils.ts Co-authored-by: Milena Czierlinski <146972016+Milena-Czierlinski@users.noreply.github.com> --- packages/runtime/test/lib/testUtils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime/test/lib/testUtils.ts b/packages/runtime/test/lib/testUtils.ts index 63d4c7568..5d1c92742 100644 --- a/packages/runtime/test/lib/testUtils.ts +++ b/packages/runtime/test/lib/testUtils.ts @@ -919,8 +919,8 @@ export async function cleanupAttributes(...services: TestRuntimeServices[]): Pro } export async function createRelationshipInPendingState( - sender: TestRuntimeServices, - receiver: TestRuntimeServices, + templator: TestRuntimeServices, + requestor: TestRuntimeServices, templateContent: RelationshipTemplateContentJSON, acceptItems: DecideRequestParametersJSON["items"] ): Promise { From 11f02708f82eb5df20cafe39b08a356b6158449a Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 10:52:32 +0100 Subject: [PATCH 09/21] Update packages/runtime/test/consumption/attributes.test.ts Co-authored-by: Milena Czierlinski <146972016+Milena-Czierlinski@users.noreply.github.com> --- packages/runtime/test/consumption/attributes.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index a374801db..27ffecb81 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -2842,7 +2842,7 @@ describe("DeleteAttributeUseCases", () => { expect(CoreDate.from(updatedPredecessor.deletionInfo!.deletionDate).isBetween(timeBeforeUpdate, timeAfterUpdate.add(1))).toBe(true); }); - test("should throw an error trying to delete a PeerSharedAttribute when the Relationship is in status Pending", async () => { + test("should throw an error trying to delete a peer shared Attribute when the Relationship is in status Pending", async () => { const [services1, services2] = await runtimeServiceProvider.launch(2, { enableRequestModule: true, enableDeciderModule: true, From 372447135bc485f47438986c54380fe210b692df Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 11:01:46 +0100 Subject: [PATCH 10/21] chore: fix renaming --- .../attributes/DeletePeerSharedAttributeAndNotifyOwner.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts index 7b54bf68d..21bc9ec17 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts @@ -2,7 +2,7 @@ import { Result } from "@js-soft/ts-utils"; import { AttributesController, ConsumptionIds, LocalAttribute } from "@nmshd/consumption"; import { Notification, PeerSharedAttributeDeletedByPeerNotificationItem } from "@nmshd/content"; import { CoreId } from "@nmshd/core-types"; -import { AccountController, MessageController, RelationshipsController } from "@nmshd/transport"; +import { AccountController, MessageController } from "@nmshd/transport"; import { Inject } from "@nmshd/typescript-ioc"; import { AttributeIdString, NotificationIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; @@ -25,7 +25,6 @@ export class DeletePeerSharedAttributeAndNotifyOwnerUseCase extends UseCase Date: Tue, 4 Feb 2025 11:05:36 +0100 Subject: [PATCH 11/21] chore: fix renaming --- packages/runtime/test/lib/testUtils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/runtime/test/lib/testUtils.ts b/packages/runtime/test/lib/testUtils.ts index 5d1c92742..3fedbba4b 100644 --- a/packages/runtime/test/lib/testUtils.ts +++ b/packages/runtime/test/lib/testUtils.ts @@ -924,31 +924,31 @@ export async function createRelationshipInPendingState( templateContent: RelationshipTemplateContentJSON, acceptItems: DecideRequestParametersJSON["items"] ): Promise { - const relationshipTemplateResult = await sender.transport.relationshipTemplates.createOwnRelationshipTemplate({ + const relationshipTemplateResult = await templator.transport.relationshipTemplates.createOwnRelationshipTemplate({ content: templateContent, expiresAt: CoreDate.utc().add({ day: 1 }).toISOString() }); - const loadedPeerTemplateResult = await receiver.transport.relationshipTemplates.loadPeerRelationshipTemplate({ + const loadedPeerTemplateResult = await requestor.transport.relationshipTemplates.loadPeerRelationshipTemplate({ reference: relationshipTemplateResult.value.truncatedReference }); - await receiver.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { + await requestor.eventBus.waitForEvent(RelationshipTemplateProcessedEvent, (event) => { return event.data.template.id === loadedPeerTemplateResult.value.id; }); - const requestsForRelationship = await receiver.consumption.incomingRequests.getRequests({ + const requestsForRelationship = await requestor.consumption.incomingRequests.getRequests({ query: { "source.reference": loadedPeerTemplateResult.value.id } }); - await receiver.consumption.incomingRequests.accept({ + await requestor.consumption.incomingRequests.accept({ requestId: requestsForRelationship.value[0].id, items: acceptItems }); - const relationships = await syncUntilHasRelationships(sender.transport); + const relationships = await syncUntilHasRelationships(templator.transport); expect(relationships).toHaveLength(1); return relationships[0]; } From e470075029968b880030894ed04db52df220b59a Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Tue, 4 Feb 2025 12:40:23 +0100 Subject: [PATCH 12/21] chore: fix sending messsage when relationsip is not activatable anymore --- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 12 +++++++++--- .../DeletePeerSharedAttributeAndNotifyOwner.ts | 14 +++++++++++--- ...ThirdPartyRelationshipAttributeAndNotifyPeer.ts | 12 +++++++++--- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index b97270664..f3c941bb0 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -2,7 +2,7 @@ import { Result } from "@js-soft/ts-utils"; import { AttributesController, ConsumptionIds, LocalAttribute } from "@nmshd/consumption"; import { Notification, OwnSharedAttributeDeletedByOwnerNotificationItem } from "@nmshd/content"; import { CoreId } from "@nmshd/core-types"; -import { AccountController, MessageController, RelationshipsController } from "@nmshd/transport"; +import { AccountController, MessageController, RelationshipsController, RelationshipStatus } from "@nmshd/transport"; import { Inject } from "@nmshd/typescript-ioc"; import { AttributeIdString, NotificationIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; @@ -40,9 +40,9 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase Date: Tue, 4 Feb 2025 14:31:30 +0100 Subject: [PATCH 13/21] chore: improve return type and variable naming --- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 4 ++-- .../DeletePeerSharedAttributeAndNotifyOwner.ts | 4 ++-- ...teThirdPartyRelationshipAttributeAndNotifyPeer.ts | 4 ++-- .../src/modules/messages/MessageController.ts | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index f3c941bb0..49a3e636b 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -53,9 +53,9 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { + public async validateMessageRecipients(recipients: CoreAddress[]): Promise> { const peersWithNeitherActiveNorTerminatedRelationship: string[] = []; const deletedPeers: string[] = []; @@ -437,12 +437,12 @@ export class MessageController extends TransportController { } if (peersWithNeitherActiveNorTerminatedRelationship.length > 0) { - return TransportCoreErrors.messages.hasNeitherActiveNorTerminatedRelationship(peersWithNeitherActiveNorTerminatedRelationship); + return Result.fail(TransportCoreErrors.messages.hasNeitherActiveNorTerminatedRelationship(peersWithNeitherActiveNorTerminatedRelationship)); } - if (deletedPeers.length > 0) return TransportCoreErrors.messages.peerIsDeleted(deletedPeers); + if (deletedPeers.length > 0) return Result.fail(TransportCoreErrors.messages.peerIsDeleted(deletedPeers)); - return; + return Result.ok(undefined); } private async decryptOwnEnvelope(envelope: MessageEnvelope, secretKey: CryptoSecretKey): Promise { From 054e1d25b9c9b1c5d6e0c21b54ef63c7c3d927cc Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Wed, 5 Feb 2025 08:17:31 +0100 Subject: [PATCH 14/21] chore: pr comments --- .../runtime/src/useCases/common/RuntimeErrors.ts | 6 +++--- .../DeleteOwnSharedAttributeAndNotifyPeer.ts | 2 +- .../DeletePeerSharedAttributeAndNotifyOwner.ts | 2 +- ...teThirdPartyRelationshipAttributeAndNotifyPeer.ts | 2 +- packages/runtime/test/consumption/attributes.test.ts | 12 ++++++------ .../src/modules/messages/MessageController.ts | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/runtime/src/useCases/common/RuntimeErrors.ts b/packages/runtime/src/useCases/common/RuntimeErrors.ts index 51f77836b..d90f1155a 100644 --- a/packages/runtime/src/useCases/common/RuntimeErrors.ts +++ b/packages/runtime/src/useCases/common/RuntimeErrors.ts @@ -268,10 +268,10 @@ class Attributes { return new ApplicationError("error.runtime.attributes.setDefaultRepositoryAttributesIsDisabled", "Setting default RepositoryAttributes is disabled for this Account."); } - public cannotDeleteSharedAttributeBecausePeerCannotBeNotified(): ApplicationError { + public cannotDeleteSharedAttributeWhileRelationshipIsPending(): ApplicationError { return new ApplicationError( - "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified", - "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion." + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending", + "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'." ); } } diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 49a3e636b..8450458b8 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -43,7 +43,7 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase { const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", - "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" + "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); }); }); @@ -2889,8 +2889,8 @@ describe("DeleteAttributeUseCases", () => { const attributeDeletion = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", - "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" + "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); }); }); @@ -3060,8 +3060,8 @@ describe("DeleteAttributeUseCases", () => { const attributeDeletion = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: thirdPartyRelationshipAttribute.value[0].id }); expect(attributeDeletion).toBeAnError( - "The shared Attribute cannot be deleted because the peer cannot be notified about the deletion.", - "error.runtime.attributes.cannotDeleteSharedAttributeBecausePeerCannotBeNotified" + "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", + "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); }); }); diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index fc6f63821..197efba6e 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -292,8 +292,8 @@ export class MessageController extends TransportController { const parsedParams = SendMessageParameters.from(parameters); if (!parsedParams.attachments) parsedParams.attachments = []; - const validationError = await this.validateMessageRecipients(parsedParams.recipients); - if (validationError.isError) throw validationError.error; + const validationResult = await this.validateMessageRecipients(parsedParams.recipients); + if (validationResult.isError) throw validationResult.error; const secret = await CoreCrypto.generateSecretKey(); const serializedSecret = secret.serialize(false); From d8dce26198bbc084d3239a0729a7ebd63861e7eb Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Thu, 6 Feb 2025 11:29:01 +0100 Subject: [PATCH 15/21] Update packages/transport/src/modules/messages/MessageController.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Julian König <33655937+jkoenig134@users.noreply.github.com> --- packages/transport/src/modules/messages/MessageController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index 197efba6e..327bd4b2a 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -419,7 +419,7 @@ export class MessageController extends TransportController { return message; } - public async validateMessageRecipients(recipients: CoreAddress[]): Promise> { + public async validateMessageRecipients(recipients: CoreAddress[]): Promise> { const peersWithNeitherActiveNorTerminatedRelationship: string[] = []; const deletedPeers: string[] = []; From 4eb668e8093af71e839b27f353126673bc59be22 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Fri, 7 Feb 2025 09:58:36 +0100 Subject: [PATCH 16/21] chore: make notificationId optional --- .../attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 8450458b8..6a30732cf 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -11,7 +11,7 @@ export interface DeleteOwnSharedAttributeAndNotifyPeerRequest { } export interface DeleteOwnSharedAttributeAndNotifyPeerResponse { - notificationId: NotificationIdString; + notificationId?: NotificationIdString; } class Validator extends SchemaValidator { @@ -56,7 +56,7 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase Date: Fri, 7 Feb 2025 10:01:09 +0100 Subject: [PATCH 17/21] chore: make notificationId optional --- .../attributes/DeletePeerSharedAttributeAndNotifyOwner.ts | 4 ++-- .../DeleteThirdPartyRelationshipAttributeAndNotifyPeer.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts index a6de0c69d..abdb47516 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts @@ -12,7 +12,7 @@ export interface DeletePeerSharedAttributeAndNotifyOwnerRequest { } export interface DeletePeerSharedAttributeAndNotifyOwnerResponse { - notificationId: NotificationIdString; + notificationId?: NotificationIdString; } class Validator extends SchemaValidator { @@ -58,7 +58,7 @@ export class DeletePeerSharedAttributeAndNotifyOwnerUseCase extends UseCase { @@ -59,7 +59,7 @@ export class DeleteThirdPartyRelationshipAttributeAndNotifyPeerUseCase extends U const messageRecipientsValidationResult = await this.messageController.validateMessageRecipients([thirdPartyRelationshipAttribute.shareInfo.peer]); if (messageRecipientsValidationResult.isError) { - return Result.ok({ notificationId: "" }); + return Result.ok({}); } const notificationId = await ConsumptionIds.notification.generate(); From 03aaebdd97bb31a5df8da2097e0f2332e24f7174 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Fri, 7 Feb 2025 10:18:37 +0100 Subject: [PATCH 18/21] chore: fix tests --- .../test/consumption/attributes.test.ts | 18 +++++++++--------- .../runtime/test/transport/messages.test.ts | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index 99cd0b981..5e9486e8f 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -1368,7 +1368,7 @@ describe(ShareRepositoryAttributeUseCase.name, () => { const rPeerSharedIdentityAttribute = (await services2.consumption.attributes.getAttribute({ id: sOwnSharedIdentityAttribute.id })).value; const deleteResult = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: rPeerSharedIdentityAttribute.id }); - const notificationId = deleteResult.value.notificationId; + const notificationId = deleteResult.value.notificationId!; await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(PeerSharedAttributeDeletedByPeerEvent, (e) => { @@ -1722,7 +1722,7 @@ describe(NotifyPeerAboutRepositoryAttributeSuccessionUseCase.name, () => { const rPeerSharedIdentityAttributeVersion1 = (await services2.consumption.attributes.getAttribute({ id: ownSharedIdentityAttributeVersion1.id })).value; const deleteResult = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: rPeerSharedIdentityAttributeVersion1.id }); - const notificationId = deleteResult.value.notificationId; + const notificationId = deleteResult.value.notificationId!; await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(PeerSharedAttributeDeletedByPeerEvent, (e) => { @@ -1914,7 +1914,7 @@ describe(SucceedRelationshipAttributeAndNotifyPeerUseCase.name, () => { const rPeerSharedRelationshipAttribute = (await services2.consumption.attributes.getAttribute({ id: sOwnSharedRelationshipAttribute.id })).value; const deleteResult = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: rPeerSharedRelationshipAttribute.id }); - const notificationId = deleteResult.value.notificationId; + const notificationId = deleteResult.value.notificationId!; await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(PeerSharedAttributeDeletedByPeerEvent, (e) => { @@ -2642,7 +2642,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about identity attribute deletion by owner", async () => { const notificationId = (await services1.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedIdentityAttributeVersion0.id })).value - .notificationId; + .notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services2.transport, notificationId); await services2.eventBus.waitForEvent(OwnSharedAttributeDeletedByOwnerEvent, (e) => { @@ -2659,7 +2659,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about identity attribute deletion of succeeded attribute by owner", async () => { const notificationId = (await services1.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedIdentityAttributeVersion1.id })).value - .notificationId; + .notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services2.transport, notificationId); await services2.eventBus.waitForEvent(OwnSharedAttributeDeletedByOwnerEvent, (e) => { @@ -2810,7 +2810,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about identity attribute deletion by peer", async () => { const notificationId = (await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: ownSharedIdentityAttributeVersion0.id })).value - .notificationId; + .notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(PeerSharedAttributeDeletedByPeerEvent, (e) => { @@ -2828,7 +2828,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about identity attribute deletion of succeeded attribute by peer", async () => { const notificationId = (await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: ownSharedIdentityAttributeVersion1.id })).value - .notificationId; + .notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(PeerSharedAttributeDeletedByPeerEvent, (e) => { @@ -2963,7 +2963,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about ThirdPartyRelationshipAttribute as the emitter of it", async () => { const notificationId = ( await services1.consumption.attributes.deleteThirdPartyRelationshipAttributeAndNotifyPeer({ attributeId: emittedThirdPartyRelationshipAttribute.id }) - ).value.notificationId; + ).value.notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services2.transport, notificationId); await services2.eventBus.waitForEvent(ThirdPartyRelationshipAttributeDeletedByPeerEvent, (e) => { @@ -2982,7 +2982,7 @@ describe("DeleteAttributeUseCases", () => { test("should notify about ThirdPartyRelationshipAttribute as the recipient of it", async () => { const notificationId = ( await services2.consumption.attributes.deleteThirdPartyRelationshipAttributeAndNotifyPeer({ attributeId: emittedThirdPartyRelationshipAttribute.id }) - ).value.notificationId; + ).value.notificationId!; const timeBeforeUpdate = CoreDate.utc(); await syncUntilHasMessageWithNotification(services1.transport, notificationId); await services1.eventBus.waitForEvent(ThirdPartyRelationshipAttributeDeletedByPeerEvent, (e) => { diff --git a/packages/runtime/test/transport/messages.test.ts b/packages/runtime/test/transport/messages.test.ts index 5832e8864..d94b4b38d 100644 --- a/packages/runtime/test/transport/messages.test.ts +++ b/packages/runtime/test/transport/messages.test.ts @@ -545,7 +545,7 @@ describe("Postponed Notifications via Messages", () => { const notifyAboutDeletionResult = (await client1.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedIdentityAttribute.id })).value; await client1.eventBus.waitForEvent(AttributeDeletedEvent); await client5.transport.account.syncEverything(); - const deletionNotificationNotYetReceived = await client5.consumption.notifications.getNotification({ id: notifyAboutDeletionResult.notificationId }); + const deletionNotificationNotYetReceived = await client5.consumption.notifications.getNotification({ id: notifyAboutDeletionResult.notificationId! }); expect(deletionNotificationNotYetReceived).toBeAnError(/.*/, "error.transport.recordNotFound"); await client1.transport.relationships.requestRelationshipReactivation({ relationshipId: relationshipId }); @@ -561,7 +561,7 @@ describe("Postponed Notifications via Messages", () => { await client5.eventBus.waitForRunningEventHandlers(); const postponedSuccessionNotification = await client5.consumption.notifications.getNotification({ id: notifyAboutSuccessionResult.notificationId }); expect(postponedSuccessionNotification).toBeSuccessful(); - const postponedDeletionNotification = await client5.consumption.notifications.getNotification({ id: notifyAboutDeletionResult.notificationId }); + const postponedDeletionNotification = await client5.consumption.notifications.getNotification({ id: notifyAboutDeletionResult.notificationId! }); expect(postponedDeletionNotification).toBeSuccessful(); const peerSharedIdentityAttribute = (await client5.consumption.attributes.getAttribute({ id: ownSharedIdentityAttribute.id })).value; From d96627860680be641ccf33a546c8539ecaa36131 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Mon, 10 Feb 2025 09:05:26 +0100 Subject: [PATCH 19/21] chore: beauty changes --- ...DeletePeerSharedAttributeAndNotifyOwner.ts | 7 +- .../test/consumption/attributes.test.ts | 73 ++++++++++--------- packages/runtime/test/lib/testUtils.ts | 2 +- .../src/modules/messages/MessageController.ts | 4 +- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts index abdb47516..6e62bac60 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeletePeerSharedAttributeAndNotifyOwner.ts @@ -41,14 +41,12 @@ export class DeletePeerSharedAttributeAndNotifyOwnerUseCase extends UseCase { enableNotificationModule: true }); + const repositoryAttribute = ( + await services2.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "aGivenName" + } + } + }) + ).value; + const item: ReadAttributeRequestItemJSON = { "@type": "ReadAttributeRequestItem", mustBeAccepted: true, @@ -2688,7 +2699,7 @@ describe("DeleteAttributeUseCases", () => { } }; - const content: RelationshipTemplateContentJSON = { + const relationshipTemplateContent: RelationshipTemplateContentJSON = { "@type": "RelationshipTemplateContent", title: "aTitle", onNewRelationship: { @@ -2696,32 +2707,22 @@ describe("DeleteAttributeUseCases", () => { "@type": "Request" } }; - - const repositoryAttribute = await services2.consumption.attributes.createRepositoryAttribute({ - content: { - value: { - "@type": "GivenName", - value: "aGivenName" - } - } - }); - - await createRelationshipInPendingState(services1, services2, content, [ + await createRelationshipWithStatusPending(services1, services2, relationshipTemplateContent, [ { accept: true, - existingAttributeId: repositoryAttribute.value.id + existingAttributeId: repositoryAttribute.id } as AcceptReadAttributeRequestItemParametersWithExistingAttributeJSON ]); const ownSharedAttribute = await services2.consumption.attributes.getAttributes({ query: { - "shareInfo.sourceAttribute": repositoryAttribute.value.id + "shareInfo.sourceAttribute": repositoryAttribute.id } }); - const attributeDeletion = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); + const attributeDeletionResult = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); - expect(attributeDeletion).toBeAnError( + expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); @@ -2849,23 +2850,25 @@ describe("DeleteAttributeUseCases", () => { enableNotificationModule: true }); - const repositoryAttribute = await services1.consumption.attributes.createRepositoryAttribute({ - content: { - value: { - "@type": "GivenName", - value: "aGivenName" + const repositoryAttribute = ( + await services1.consumption.attributes.createRepositoryAttribute({ + content: { + value: { + "@type": "GivenName", + value: "aGivenName" + } } - } - }); + }) + ).value; const item: ShareAttributeRequestItemJSON = { "@type": "ShareAttributeRequestItem", mustBeAccepted: true, - attribute: repositoryAttribute.value.content, - sourceAttributeId: repositoryAttribute.value.id + attribute: repositoryAttribute.content, + sourceAttributeId: repositoryAttribute.id }; - const content: CreateOwnRelationshipTemplateRequest["content"] = { + const relationshipTemplateContent: CreateOwnRelationshipTemplateRequest["content"] = { "@type": "RelationshipTemplateContent", title: "aTitle", onNewRelationship: { @@ -2874,7 +2877,7 @@ describe("DeleteAttributeUseCases", () => { } }; - await createRelationshipInPendingState(services1, services2, content, [ + await createRelationshipWithStatusPending(services1, services2, relationshipTemplateContent, [ { accept: true } as AcceptRequestItemParametersJSON @@ -2886,9 +2889,9 @@ describe("DeleteAttributeUseCases", () => { } }); - const attributeDeletion = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); + const attributeDeletionResult = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); - expect(attributeDeletion).toBeAnError( + expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); @@ -3037,7 +3040,7 @@ describe("DeleteAttributeUseCases", () => { thirdPartyAddress: services1.address }; - const content: CreateOwnRelationshipTemplateRequest["content"] = { + const relationshipTemplateContent: CreateOwnRelationshipTemplateRequest["content"] = { "@type": "RelationshipTemplateContent", title: "aTitle", onNewRelationship: { @@ -3046,7 +3049,7 @@ describe("DeleteAttributeUseCases", () => { } }; - await createRelationshipInPendingState(services2, services3, content, [ + await createRelationshipWithStatusPending(services2, services3, relationshipTemplateContent, [ { accept: true } as AcceptRequestItemParametersJSON @@ -3057,9 +3060,11 @@ describe("DeleteAttributeUseCases", () => { "shareInfo.peer": services2.address } }); - const attributeDeletion = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: thirdPartyRelationshipAttribute.value[0].id }); + const attributeDeletionResult = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ + attributeId: thirdPartyRelationshipAttribute.value[0].id + }); - expect(attributeDeletion).toBeAnError( + expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" ); diff --git a/packages/runtime/test/lib/testUtils.ts b/packages/runtime/test/lib/testUtils.ts index 3fedbba4b..88ff5e5ec 100644 --- a/packages/runtime/test/lib/testUtils.ts +++ b/packages/runtime/test/lib/testUtils.ts @@ -918,7 +918,7 @@ export async function cleanupAttributes(...services: TestRuntimeServices[]): Pro ); } -export async function createRelationshipInPendingState( +export async function createRelationshipWithStatusPending( templator: TestRuntimeServices, requestor: TestRuntimeServices, templateContent: RelationshipTemplateContentJSON, diff --git a/packages/transport/src/modules/messages/MessageController.ts b/packages/transport/src/modules/messages/MessageController.ts index 327bd4b2a..39e23b9f4 100644 --- a/packages/transport/src/modules/messages/MessageController.ts +++ b/packages/transport/src/modules/messages/MessageController.ts @@ -1,6 +1,6 @@ import { ISerializable } from "@js-soft/ts-serval"; import { log, Result } from "@js-soft/ts-utils"; -import { CoreAddress, CoreDate, CoreError, CoreId, ICoreAddress, ICoreId } from "@nmshd/core-types"; +import { CoreAddress, CoreDate, CoreId, ICoreAddress, ICoreId } from "@nmshd/core-types"; import { CoreBuffer, CryptoCipher, CryptoSecretKey } from "@nmshd/crypto"; import { nameof } from "ts-simple-nameof"; import { CoreCrypto, TransportCoreErrors, TransportError } from "../../core"; @@ -419,7 +419,7 @@ export class MessageController extends TransportController { return message; } - public async validateMessageRecipients(recipients: CoreAddress[]): Promise> { + public async validateMessageRecipients(recipients: CoreAddress[]): Promise> { const peersWithNeitherActiveNorTerminatedRelationship: string[] = []; const deletedPeers: string[] = []; From 3cbc4aa705703791de7553efc2a0feed676f688b Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Mon, 10 Feb 2025 09:09:15 +0100 Subject: [PATCH 20/21] chore: beauty changes --- packages/runtime/test/consumption/attributes.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/runtime/test/consumption/attributes.test.ts b/packages/runtime/test/consumption/attributes.test.ts index e3ae75ed7..0ba632530 100644 --- a/packages/runtime/test/consumption/attributes.test.ts +++ b/packages/runtime/test/consumption/attributes.test.ts @@ -2721,7 +2721,6 @@ describe("DeleteAttributeUseCases", () => { }); const attributeDeletionResult = await services2.consumption.attributes.deleteOwnSharedAttributeAndNotifyPeer({ attributeId: ownSharedAttribute.value[0].id }); - expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" @@ -2890,7 +2889,6 @@ describe("DeleteAttributeUseCases", () => { }); const attributeDeletionResult = await services2.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: peerSharedAttribute.value[0].id }); - expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" @@ -3063,7 +3061,6 @@ describe("DeleteAttributeUseCases", () => { const attributeDeletionResult = await services3.consumption.attributes.deletePeerSharedAttributeAndNotifyOwner({ attributeId: thirdPartyRelationshipAttribute.value[0].id }); - expect(attributeDeletionResult).toBeAnError( "The shared Attribute cannot be deleted while the Relationship to the peer is in status 'Pending'.", "error.runtime.attributes.cannotDeleteSharedAttributeWhileRelationshipIsPending" From e38baa0a903534aea3f881e15a7807ac9d52a2a6 Mon Sep 17 00:00:00 2001 From: Sebastian Mahr Date: Mon, 10 Feb 2025 11:43:43 +0100 Subject: [PATCH 21/21] chore: beauty changes --- .../attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts | 6 ++---- ...DeleteThirdPartyRelationshipAttributeAndNotifyPeer.ts | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts index 6a30732cf..3f2b75471 100644 --- a/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts +++ b/packages/runtime/src/useCases/consumption/attributes/DeleteOwnSharedAttributeAndNotifyPeer.ts @@ -40,9 +40,8 @@ export class DeleteOwnSharedAttributeAndNotifyPeerUseCase extends UseCase