From 929c99fd02cc6ba34868611553d3998fa51110f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20K=C3=B6nig?= <33655937+jkoenig134@users.noreply.github.com> Date: Thu, 19 Sep 2024 15:55:56 +0200 Subject: [PATCH] Make relationship setting usable (#274) * refactor: add reference and scope to GetSettingByKey * refactor: add reference and scope to UpsertSettingByKey * feat: add originalName to IdentityDVO and RelationshipDVO * refactor: query relationship setting correctly * feat: add originalName to IdentityDVO and RelationshipDVO * test: update tests for new settings utilities * fix: update schemas * fix: use correct value * test: add test for updated RelationshipDVO * fix: handle hardcoded settingsScope * fix: typo * chore: check more stuff --- .../runtime/src/dataViews/DataViewExpander.ts | 32 ++++++++---- .../src/dataViews/transport/IdentityDVO.ts | 1 + .../dataViews/transport/RelationshipDVO.ts | 1 + .../runtime/src/useCases/common/Schemas.ts | 28 +++++++++- .../consumption/settings/GetSettingByKey.ts | 12 ++++- .../settings/UpsertSettingByKey.ts | 20 ++++++-- .../runtime/test/consumption/settings.test.ts | 14 +++++ .../test/dataViews/RelationshipDVO.test.ts | 51 ++++++++++++------- 8 files changed, 126 insertions(+), 33 deletions(-) diff --git a/packages/runtime/src/dataViews/DataViewExpander.ts b/packages/runtime/src/dataViews/DataViewExpander.ts index 153a59d2d..cce26372b 100644 --- a/packages/runtime/src/dataViews/DataViewExpander.ts +++ b/packages/runtime/src/dataViews/DataViewExpander.ts @@ -1698,15 +1698,7 @@ export class DataViewExpander { } private async createRelationshipDVO(relationship: RelationshipDTO): Promise { - let relationshipSetting: RelationshipSettingDVO; - const settingResult = await this.consumption.settings.getSettings({ query: { reference: relationship.id } }); - if (settingResult.value.length > 0) { - relationshipSetting = settingResult.value[0].value; - } else { - relationshipSetting = { - isPinned: false - }; - } + const relationshipSetting = await this.getRelationshipSettingDVO(relationship); const stringByType: Record = {}; const relationshipAttributesResult = await this.consumption.attributes.getPeerSharedAttributes({ onlyValid: true, peer: relationship.peer }); @@ -1781,6 +1773,7 @@ export class DataViewExpander { return { id: relationship.id, name: relationshipSetting.userTitle ?? name, + originalName: relationshipSetting.userTitle ? name : undefined, description: relationshipSetting.userDescription ?? statusText, date: creationDate, image: "", @@ -1799,6 +1792,26 @@ export class DataViewExpander { }; } + private async getRelationshipSettingDVO(relationship: RelationshipDTO): Promise { + const settingResult = await this.consumption.settings.getSettings({ + query: { + scope: "Relationship", + reference: relationship.id + } + }); + + const defaultSetting = { isPinned: false }; + + if (settingResult.value.length === 0) return defaultSetting; + + const latestSetting = settingResult.value.reduce((prev, current) => (prev.createdAt > current.createdAt ? prev : current)); + const value = latestSetting.value; + + if (typeof value !== "object") return defaultSetting; + + return { ...defaultSetting, ...value }; + } + public async expandRelationshipDTO(relationship: RelationshipDTO): Promise { const relationshipDVO = await this.createRelationshipDVO(relationship); const initials = (relationshipDVO.name.match(/\b\w/g) ?? []).join(""); @@ -1807,6 +1820,7 @@ export class DataViewExpander { type: "IdentityDVO", id: relationship.peer, name: relationshipDVO.name, + originalName: relationshipDVO.originalName, date: relationshipDVO.date, description: relationshipDVO.description, publicKey: relationship.peerIdentity.publicKey, diff --git a/packages/runtime/src/dataViews/transport/IdentityDVO.ts b/packages/runtime/src/dataViews/transport/IdentityDVO.ts index a42f6c112..18a79d382 100644 --- a/packages/runtime/src/dataViews/transport/IdentityDVO.ts +++ b/packages/runtime/src/dataViews/transport/IdentityDVO.ts @@ -9,4 +9,5 @@ export interface IdentityDVO extends DataViewObject { isSelf: boolean; hasRelationship: boolean; relationship?: RelationshipDVO; + originalName?: string; } diff --git a/packages/runtime/src/dataViews/transport/RelationshipDVO.ts b/packages/runtime/src/dataViews/transport/RelationshipDVO.ts index 9d86f63ea..a744bfc95 100644 --- a/packages/runtime/src/dataViews/transport/RelationshipDVO.ts +++ b/packages/runtime/src/dataViews/transport/RelationshipDVO.ts @@ -21,6 +21,7 @@ export interface RelationshipDVO extends DataViewObject { attributeMap: Record; nameMap: Record; templateId: string; + originalName?: string; } export interface RelationshipTheme { diff --git a/packages/runtime/src/useCases/common/Schemas.ts b/packages/runtime/src/useCases/common/Schemas.ts index a2936689d..42537be14 100644 --- a/packages/runtime/src/useCases/common/Schemas.ts +++ b/packages/runtime/src/useCases/common/Schemas.ts @@ -20302,6 +20302,17 @@ export const GetSettingByKeyRequest: any = { "properties": { "key": { "type": "string" + }, + "reference": { + "type": "string" + }, + "scope": { + "type": "string", + "enum": [ + "Identity", + "Device", + "Relationship" + ] } }, "required": [ @@ -20447,13 +20458,28 @@ export const UpsertSettingByKeyRequest: any = { "key": { "type": "string" }, - "value": {} + "value": {}, + "reference": { + "$ref": "#/definitions/GenericIdString" + }, + "scope": { + "type": "string", + "enum": [ + "Identity", + "Device", + "Relationship" + ] + } }, "required": [ "key", "value" ], "additionalProperties": false + }, + "GenericIdString": { + "type": "string", + "pattern": "[A-Za-z0-9]{20}" } } } diff --git a/packages/runtime/src/useCases/consumption/settings/GetSettingByKey.ts b/packages/runtime/src/useCases/consumption/settings/GetSettingByKey.ts index 80c3500c0..662818dbc 100644 --- a/packages/runtime/src/useCases/consumption/settings/GetSettingByKey.ts +++ b/packages/runtime/src/useCases/consumption/settings/GetSettingByKey.ts @@ -1,5 +1,5 @@ import { Result } from "@js-soft/ts-utils"; -import { Setting, SettingsController } from "@nmshd/consumption"; +import { Setting, SettingsController, SettingScope } from "@nmshd/consumption"; import { Inject } from "typescript-ioc"; import { SettingDTO } from "../../../types"; import { RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common"; @@ -7,6 +7,8 @@ import { SettingMapper } from "./SettingMapper"; export interface GetSettingByKeyRequest { key: string; + reference?: string; + scope?: "Identity" | "Device" | "Relationship"; } class Validator extends SchemaValidator { @@ -24,7 +26,13 @@ export class GetSettingByKeyUseCase extends UseCase> { - const settings = await this.settingController.getSettings({ key: request.key }); + const query = { + key: request.key, + reference: request.reference ?? { $exists: false }, + scope: request.scope ?? SettingScope.Identity + }; + + const settings = await this.settingController.getSettings(query); if (settings.length === 0) { return Result.fail(RuntimeErrors.general.recordNotFound(Setting)); } diff --git a/packages/runtime/src/useCases/consumption/settings/UpsertSettingByKey.ts b/packages/runtime/src/useCases/consumption/settings/UpsertSettingByKey.ts index 839b8c619..edf8658d8 100644 --- a/packages/runtime/src/useCases/consumption/settings/UpsertSettingByKey.ts +++ b/packages/runtime/src/useCases/consumption/settings/UpsertSettingByKey.ts @@ -1,15 +1,18 @@ import { Serializable } from "@js-soft/ts-serval"; import { Result } from "@js-soft/ts-utils"; -import { SettingsController } from "@nmshd/consumption"; +import { SettingsController, SettingScope } from "@nmshd/consumption"; +import { CoreId } from "@nmshd/core-types"; import { AccountController } from "@nmshd/transport"; import { Inject } from "typescript-ioc"; import { SettingDTO } from "../../../types"; -import { SchemaRepository, SchemaValidator, UseCase } from "../../common"; +import { GenericIdString, SchemaRepository, SchemaValidator, UseCase } from "../../common"; import { SettingMapper } from "./SettingMapper"; export interface UpsertSettingByKeyRequest { key: string; value: any; + reference?: GenericIdString; + scope?: "Identity" | "Device" | "Relationship"; } class Validator extends SchemaValidator { @@ -28,12 +31,21 @@ export class UpsertSettingByKeyUseCase extends UseCase> { - const settings = await this.settingController.getSettings({ key: request.key }); + const settings = await this.settingController.getSettings({ + key: request.key, + reference: request.reference ?? { $exists: false }, + scope: request.scope ?? SettingScope.Identity + }); const newValue = Serializable.fromUnknown(request.value); if (settings.length === 0) { - const setting = await this.settingController.createSetting({ key: request.key, value: newValue }); + const setting = await this.settingController.createSetting({ + key: request.key, + value: newValue, + reference: request.reference ? CoreId.from(request.reference) : undefined, + scope: request.scope as SettingScope | undefined + }); await this.accountController.syncDatawallet(); return Result.ok(SettingMapper.toSettingDTO(setting)); } diff --git a/packages/runtime/test/consumption/settings.test.ts b/packages/runtime/test/consumption/settings.test.ts index 2b719825a..a23f73462 100644 --- a/packages/runtime/test/consumption/settings.test.ts +++ b/packages/runtime/test/consumption/settings.test.ts @@ -134,6 +134,20 @@ describe("Settings", () => { const setting = await consumptionServices.settings.getSettingByKey({ key: "a-key" }); expect(setting.value.value).toStrictEqual({ aKey: "aNewValue" }); }); + + test("should get the settings by key including a reference and type", async () => { + const key = "a-key"; + const value = { aKey: "a-value" }; + const reference = (await TransportIds.generic.generate()).toString(); + const scope = "Identity"; + + const upsertSettingResult = await consumptionServices.settings.upsertSettingByKey({ key, reference, scope, value }); + expect(upsertSettingResult).toBeSuccessful(); + + const result = await consumptionServices.settings.getSettingByKey({ key, reference, scope }); + expect(result).toBeSuccessful(); + expect(result.value.value).toStrictEqual(value); + }); }); describe("Settings query", () => { diff --git a/packages/runtime/test/dataViews/RelationshipDVO.test.ts b/packages/runtime/test/dataViews/RelationshipDVO.test.ts index 31fd4704a..cae3cead6 100644 --- a/packages/runtime/test/dataViews/RelationshipDVO.test.ts +++ b/packages/runtime/test/dataViews/RelationshipDVO.test.ts @@ -10,24 +10,21 @@ import { } from "@nmshd/content"; import { CoreAddress } from "@nmshd/core-types"; import { CoreIdHelper } from "@nmshd/transport"; -import { DataViewExpander, TransportServices } from "../../src"; -import { establishRelationshipWithContents, RuntimeServiceProvider } from "../lib"; +import { establishRelationshipWithContents, RuntimeServiceProvider, TestRuntimeServices } from "../lib"; const serviceProvider = new RuntimeServiceProvider(); -let transportServices1: TransportServices; -let transportServices2: TransportServices; -let expander1: DataViewExpander; -let expander2: DataViewExpander; + +let runtimeServices1: TestRuntimeServices; +let runtimeServices2: TestRuntimeServices; beforeAll(async () => { const runtimeServices = await serviceProvider.launch(2); - transportServices1 = runtimeServices[0].transport; - transportServices2 = runtimeServices[1].transport; - expander1 = runtimeServices[0].expander; - expander2 = runtimeServices[1].expander; + runtimeServices1 = runtimeServices[0]; + runtimeServices2 = runtimeServices[1]; + await establishRelationshipWithContents( - transportServices1, - transportServices2, + runtimeServices1.transport, + runtimeServices2.transport, RelationshipTemplateContent.from({ onNewRelationship: { @@ -53,7 +50,7 @@ beforeAll(async () => { result: ResponseItemResult.Accepted, attributeId: await CoreIdHelper.notPrefixed.generate(), attribute: IdentityAttribute.from({ - owner: CoreAddress.from((await transportServices1.account.getIdentityInfo()).value.address), + owner: CoreAddress.from((await runtimeServices1.transport.account.getIdentityInfo()).value.address), value: GivenName.from("AGivenName") }) }).toJSON() @@ -67,8 +64,8 @@ afterAll(() => serviceProvider.stop()); describe("RelationshipDVO", () => { test("check the relationship dvo for the templator", async () => { - const dtos = (await transportServices1.relationships.getRelationships({})).value; - const dvos = await expander1.expandRelationshipDTOs(dtos); + const dtos = (await runtimeServices1.transport.relationships.getRelationships({})).value; + const dvos = await runtimeServices1.expander.expandRelationshipDTOs(dtos); const dto = dtos[0]; const dvo = dvos[0]; expect(dvo).toBeDefined(); @@ -87,8 +84,8 @@ describe("RelationshipDVO", () => { }); test("check the relationship dvo for the requestor", async () => { - const dtos = (await transportServices2.relationships.getRelationships({})).value; - const dvos = await expander2.expandRelationshipDTOs(dtos); + const dtos = (await runtimeServices2.transport.relationships.getRelationships({})).value; + const dvos = await runtimeServices2.expander.expandRelationshipDTOs(dtos); const dto = dtos[0]; const dvo = dvos[0]; expect(dvo).toBeDefined(); @@ -105,4 +102,24 @@ describe("RelationshipDVO", () => { expect(dvo.relationship!.templateId).toBe(dto.template.id); }); + + test("check the relationship dvo for the templator with active relationshipSetting", async () => { + const dtos = (await runtimeServices1.transport.relationships.getRelationships({})).value; + const dto = dtos[0]; + + await runtimeServices1.consumption.settings.upsertSettingByKey({ + key: "relationshipSetting", + value: { userTitle: "aTitle", userDescription: "aDescription" }, + scope: "Relationship", + reference: dto.id + }); + + const dvos = await runtimeServices1.expander.expandRelationshipDTOs(dtos); + const dvo = dvos[0]; + + expect(dvo).toBeDefined(); + expect(dvo.name).toBe("aTitle"); + expect(dvo.originalName).toBe("i18n://dvo.identity.unknown"); + expect(dvo.description).toBe("aDescription"); + }); });