Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into refactor/remove-expec…
Browse files Browse the repository at this point in the history
…tthrowsasync
  • Loading branch information
Milena-Czierlinski committed Sep 19, 2024
2 parents a3c30f3 + 929c99f commit 139239f
Show file tree
Hide file tree
Showing 31 changed files with 763 additions and 35 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions packages/consumption/src/consumption/ConsumptionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
DraftsController,
FreeTextRequestItemProcessor,
GenericRequestItemProcessor,
IdentityMetadataController,
IncomingRequestsController,
NotificationItemConstructor,
NotificationItemProcessorConstructor,
Expand Down Expand Up @@ -86,6 +87,11 @@ export class ConsumptionController {
return this._notifications;
}

private _identityMetadata: IdentityMetadataController;
public get identityMetadata(): IdentityMetadataController {
return this._identityMetadata;
}

public async init(
requestItemProcessorOverrides = new Map<RequestItemConstructor, RequestItemProcessorConstructor>(),
notificationItemProcessorOverrides = new Map<NotificationItemConstructor, NotificationItemProcessorConstructor>()
Expand Down Expand Up @@ -135,6 +141,8 @@ export class ConsumptionController {
this.accountController.activeDevice
).init();

this._identityMetadata = await new IdentityMetadataController(this).init();

this._settings = await new SettingsController(this).init();
this._attributeListeners = await new AttributeListenersController(this, this.transport.eventBus, this.accountController.identity).init();
return this;
Expand Down Expand Up @@ -170,5 +178,6 @@ export class ConsumptionController {
await this.settings.deleteSettingsForRelationship(relationshipId);
await this.attributeListeners.deletePeerAttributeListeners(peer);
await this.notifications.deleteNotificationsExchangedWithPeer(peer);
await this.identityMetadata.deleteIdentityMetadataReferencedWithPeer(peer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export enum ConsumptionControllerName {
DraftsController = "DraftsController",
RequestsController = "RequestsController",
SettingsController = "SettingsController",
NotificationsController = "NotificationsController"
NotificationsController = "NotificationsController",
IdentityMetadataController = "IdentityMetadataController"
}
1 change: 1 addition & 0 deletions packages/consumption/src/consumption/ConsumptionIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export class ConsumptionIds {
public static readonly request = new CoreIdHelper("REQ");
public static readonly attributeListener = new CoreIdHelper("ATL");
public static readonly notification = new CoreIdHelper("NOT");
public static readonly identityMetadata = new CoreIdHelper("IDM");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { CoreAddress } from "@nmshd/core-types";
import { SynchronizedCollection } from "@nmshd/transport";
import { ConsumptionBaseController } from "../../consumption/ConsumptionBaseController";
import { ConsumptionController } from "../../consumption/ConsumptionController";
import { ConsumptionControllerName } from "../../consumption/ConsumptionControllerName";
import { ConsumptionIds } from "../../consumption/ConsumptionIds";
import { IdentityMetadata } from "./local/IdentityMetadata";
import { IUpsertIdentityMetadataParams, UpsertIdentityMetadataParams } from "./local/UpsertIdentityMetadataParams";

export class IdentityMetadataController extends ConsumptionBaseController {
private identityMetadata: SynchronizedCollection;

public constructor(parent: ConsumptionController) {
super(ConsumptionControllerName.IdentityMetadataController, parent);
}

public override async init(): Promise<this> {
await super.init();

this.identityMetadata = await this.parent.accountController.getSynchronizedCollection("IdentityMetadata");
return this;
}

public async getIdentityMetadata(reference: CoreAddress, key?: string): Promise<IdentityMetadata | undefined> {
const result = await this.identityMetadata.findOne({
reference: reference.toString(),
key: key ?? { $exists: false }
});

return result ? IdentityMetadata.from(result) : undefined;
}

public async upsertIdentityMetadata(params: IUpsertIdentityMetadataParams): Promise<IdentityMetadata> {
const parsedParams = UpsertIdentityMetadataParams.from(params);

const oldDoc = await this.identityMetadata.findOne({
reference: parsedParams.reference.toString(),
key: parsedParams.key ?? { $exists: false }
});

if (!oldDoc) {
const identityMetadata = IdentityMetadata.from({
id: await ConsumptionIds.identityMetadata.generate(),
key: parsedParams.key,
reference: parsedParams.reference,
value: parsedParams.value
});

await this.identityMetadata.create(identityMetadata);

return identityMetadata;
}

const identityMetadata = IdentityMetadata.from(oldDoc);
identityMetadata.value = parsedParams.value;

await this.identityMetadata.update(oldDoc, identityMetadata);

return identityMetadata;
}

public async deleteIdentityMetadata(identityMetadata: IdentityMetadata): Promise<void> {
await this.identityMetadata.delete(identityMetadata);
}

public async deleteIdentityMetadataReferencedWithPeer(peerAddress: CoreAddress): Promise<void> {
const docs = await this.identityMetadata.find({ reference: peerAddress.toString() });

for (const doc of docs) {
const identityMetadata = IdentityMetadata.from(doc);
await this.deleteIdentityMetadata(identityMetadata);
}
}
}
3 changes: 3 additions & 0 deletions packages/consumption/src/modules/identityMetadata/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./IdentityMetadataController";
export * from "./local/IdentityMetadata";
export * from "./local/UpsertIdentityMetadataParams";
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ISerializable, JSONWrapper, serialize, type, validate } from "@js-soft/ts-serval";
import { CoreAddress, ICoreAddress } from "@nmshd/core-types";
import { CoreSynchronizable, ICoreSynchronizable } from "@nmshd/transport";
import { nameof } from "ts-simple-nameof";

export interface IdentityMetadataJSON {
key?: string;
reference: string;
value: any;
}

export interface IIdentityMetadata extends ICoreSynchronizable {
key?: string;
reference: ICoreAddress;
value: ISerializable;
}

@type("IdentityMetadata")
export class IdentityMetadata extends CoreSynchronizable implements IIdentityMetadata {
public override readonly technicalProperties = ["@type", "@context", nameof<IdentityMetadata>((r) => r.key), nameof<IdentityMetadata>((r) => r.reference)];
public override readonly userdataProperties = [nameof<IdentityMetadata>((r) => r.value)];

@validate({ nullable: true })
@serialize()
public key?: string;

@validate()
@serialize()
public reference: CoreAddress;

@validate()
@serialize()
public value: JSONWrapper;

public static from(value: IIdentityMetadata | IdentityMetadataJSON): IdentityMetadata {
return this.fromAny(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ISerializable, JSONWrapper, Serializable, serialize, validate } from "@js-soft/ts-serval";
import { CoreAddress, ICoreAddress } from "@nmshd/core-types";

export interface IUpsertIdentityMetadataParams extends ISerializable {
key?: string;
reference: ICoreAddress;
value: ISerializable;
}

export class UpsertIdentityMetadataParams extends Serializable implements IUpsertIdentityMetadataParams {
@validate({ nullable: true })
@serialize()
public key?: string;

@validate()
@serialize()
public reference: CoreAddress;

@validate()
@serialize()
public value: JSONWrapper;

public static from(value: IUpsertIdentityMetadataParams): UpsertIdentityMetadataParams {
return this.fromAny(value);
}
}
1 change: 1 addition & 0 deletions packages/consumption/src/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from "./attributeListeners";
export * from "./attributes";
export * from "./common";
export * from "./drafts";
export * from "./identityMetadata";
export * from "./notifications";
export * from "./requests";
export * from "./settings";
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { IDatabaseConnection } from "@js-soft/docdb-access-abstractions";
import { JSONWrapper } from "@js-soft/ts-serval";
import { CoreAddress } from "@nmshd/core-types";
import { AccountController, Transport } from "@nmshd/transport";
import { ConsumptionController } from "../../../src";
import { TestUtil } from "../../core/TestUtil";
import { MockEventBus } from "../MockEventBus";

const mockEventBus = new MockEventBus();

describe("IdentityMetadataController", function () {
let connection: IDatabaseConnection;
let transport: Transport;

let consumptionController: ConsumptionController;
let testAccount: AccountController;

beforeAll(async function () {
connection = await TestUtil.createConnection();
transport = TestUtil.createTransport(connection, mockEventBus);

await transport.init();

const account = (await TestUtil.provideAccounts(transport, 1))[0];
({ accountController: testAccount, consumptionController } = account);
});

afterAll(async function () {
await testAccount.close();
await connection.close();
});

afterEach(async function () {
await consumptionController.identityMetadata["identityMetadata"]["parent"].delete({});
const count = await consumptionController.identityMetadata["identityMetadata"].count();
// eslint-disable-next-line jest/no-standalone-expect
expect(count).toBe(0);
});

test("should create an identity metadata", async function () {
const identityMetadata = await consumptionController.identityMetadata.upsertIdentityMetadata({
value: { a: "json" },
reference: CoreAddress.from("did:e:a-domain:dids:anidentity")
});

expect(identityMetadata.reference).toBeInstanceOf(CoreAddress);
expect(identityMetadata.reference.toString()).toBe("did:e:a-domain:dids:anidentity");

expect(identityMetadata.value).toBeInstanceOf(JSONWrapper);
expect(identityMetadata.value.toJSON()).toStrictEqual({ a: "json" });
});

test("should create an identity metadata with a key", async function () {
const identityMetadata = await consumptionController.identityMetadata.upsertIdentityMetadata({
value: { a: "json" },
reference: CoreAddress.from("did:e:a-domain:dids:anidentity"),
key: "key"
});

expect(identityMetadata.reference).toBeInstanceOf(CoreAddress);
expect(identityMetadata.reference.toString()).toBe("did:e:a-domain:dids:anidentity");

expect(identityMetadata.value).toBeInstanceOf(JSONWrapper);
expect(identityMetadata.value.toJSON()).toStrictEqual({ a: "json" });

expect(identityMetadata.key).toBe("key");
});

test("should update an identity metadata", async function () {
const query = { reference: CoreAddress.from("did:e:a-domain:dids:anidentity") };

await consumptionController.identityMetadata.upsertIdentityMetadata({
...query,
value: { a: "json" }
});

const updated = await consumptionController.identityMetadata.upsertIdentityMetadata({
...query,
value: { another: "json" }
});
expect(updated.value.toJSON()).toStrictEqual({ another: "json" });

const queried = await consumptionController.identityMetadata.getIdentityMetadata(CoreAddress.from("did:e:a-domain:dids:anidentity"));
expect(queried).toBeDefined();
expect(queried!.value.toJSON()).toStrictEqual({ another: "json" });
});

test("should update an identity metadata with a key", async function () {
const query = { reference: CoreAddress.from("did:e:a-domain:dids:anidentity"), key: "key" };

await consumptionController.identityMetadata.upsertIdentityMetadata({
...query,
value: { a: "json" }
});

const updated = await consumptionController.identityMetadata.upsertIdentityMetadata({
...query,
value: { another: "json" }
});
expect(updated.value.toJSON()).toStrictEqual({ another: "json" });

const queried = await consumptionController.identityMetadata.getIdentityMetadata(CoreAddress.from("did:e:a-domain:dids:anidentity"), "key");
expect(queried).toBeDefined();
expect(queried!.value.toJSON()).toStrictEqual({ another: "json" });
});

test("should delete an identity metadata", async function () {
const identityMetadata = await consumptionController.identityMetadata.upsertIdentityMetadata({
reference: CoreAddress.from("did:e:a-domain:dids:anidentity"),
value: { a: "json" }
});

expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(1);

await consumptionController.identityMetadata.deleteIdentityMetadata(identityMetadata);
expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(0);
});

test("should delete an identity metadata with a key", async function () {
const identityMetadata = await consumptionController.identityMetadata.upsertIdentityMetadata({
reference: CoreAddress.from("did:e:a-domain:dids:anidentity"),
key: "key",
value: { a: "json" }
});

expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(1);

await consumptionController.identityMetadata.deleteIdentityMetadata(identityMetadata);
expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(0);
});

test("should delete all identity metadata referenced with peer", async function () {
await consumptionController.identityMetadata.upsertIdentityMetadata({ reference: CoreAddress.from("did:e:a-domain:dids:anidentity"), value: { a: "json" } });
await consumptionController.identityMetadata.upsertIdentityMetadata({ reference: CoreAddress.from("did:e:a-domain:dids:anidentity"), value: { a: "json" }, key: "key" });
await consumptionController.identityMetadata.upsertIdentityMetadata({
reference: CoreAddress.from("did:e:a-domain:dids:anotheridentity"),
value: { a: "json" },
key: "key"
});
expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(3);

await consumptionController.identityMetadata.deleteIdentityMetadataReferencedWithPeer(CoreAddress.from("did:e:a-domain:dids:anidentity"));
expect(await consumptionController.identityMetadata["identityMetadata"].count()).toBe(1);
});
});
5 changes: 5 additions & 0 deletions packages/runtime/src/Runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
AttributesController,
ConsumptionController,
DraftsController,
IdentityMetadataController,
IncomingRequestsController,
NotificationsController,
OutgoingRequestsController,
Expand Down Expand Up @@ -281,6 +282,10 @@ export abstract class Runtime<TConfig extends RuntimeConfig = RuntimeConfig> {
.factory(() => this.getConsumptionController().settings)
.scope(Scope.Request);

Container.bind(IdentityMetadataController)
.factory(() => this.getConsumptionController().identityMetadata)
.scope(Scope.Request);

Container.bind(NotificationsController)
.factory(() => this.getConsumptionController().notifications)
.scope(Scope.Request);
Expand Down
Loading

0 comments on commit 139239f

Please sign in to comment.