Skip to content

Commit

Permalink
Simplify identity deletion process handling on second device by repub…
Browse files Browse the repository at this point in the history
…lishing events (#347)

* WIP: Enhance LocalAccountDTO with deletion Info

* feat: try to untangle changes

* feat: add getAccounts(Not)InDeletion functions

* test: clean up IdentityDeletionProcessStatusChangedModule test

* refactor: stuff

* refactor: clean up changes

* test: notes

* feat: publish DatawalletSynchronizedEvent in AccountController

* test: receive DatawalletSynchronizedEvent calling syncDatawallet use case

* feat: use runtime event in app-runtime

* feat: add DatawalletSynchronized module

* chore: remove LocalAccountDeletionDateChangedModule

* test: clean up IdentityDeletionProcessStatusChangedModule test

* fix: DatawalletSynchronizedModule

* fix: don't publish event updating LocalAccount deletionDate

* fix and test: getAccounts(Not)InDeletion

* test: don's skip tests

* test: remove unrelated test

* chore: remove dangerous getters

* fix: write deletionDate to cached local account from MultiAccountController

* fix: use correct apis

* refactor: massively simplify tests

* chore: naming

* chore: more asserts

* refactor: move event publish location

* fix: change location of publishing

* refactor: collect IDs for changed objects during datawallet sync

* feat: re-publish event

* refactor: update usage

* chore: simplify method

* refactor: remove all occurences of the DatawalletSynchronizedModule

* fix: publish event

* fix: for..of instead of for..in

* fix: properly await events

* chore: remove unused testutils

* chore: use proper eventbus

* chore: use for loop

* refactor: allow to announce that there are changes in IdentityDeletionProcesses without having a specific

* chore: simplify publishing

* chore: test wording

* feat: update logic

* fix: tests

---------

Co-authored-by: Siolto <simon.coen@js-soft.com>
Co-authored-by: Milena Czierlinski <milena.czierlinski@js-soft.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored Dec 4, 2024
1 parent c3f5ac2 commit 745223c
Show file tree
Hide file tree
Showing 21 changed files with 244 additions and 293 deletions.
6 changes: 0 additions & 6 deletions packages/app-runtime/src/AppConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ export function createAppConfig(...configs: AppConfigOverwrite[]): AppConfig {
location: "onboardingChangeReceived",
enabled: true
},
datawalletSynchronized: {
name: "datawalletSynchronized",
displayName: "Datawallet Synchronized Module",
location: "datawalletSynchronized",
enabled: true
},
identityDeletionProcessStatusChanged: {
name: "identityDeletionProcessStatusChanged",
displayName: "Identity Deletion Process Status Changed Module",
Expand Down
2 changes: 0 additions & 2 deletions packages/app-runtime/src/AppRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
AppLaunchModule,
AppRuntimeModuleConfiguration,
AppSyncModule,
DatawalletSynchronizedModule,
IAppRuntimeModuleConstructor,
IdentityDeletionProcessStatusChangedModule,
MailReceivedModule,
Expand Down Expand Up @@ -264,7 +263,6 @@ export class AppRuntime extends Runtime<AppConfig> {
pushNotification: PushNotificationModule,
mailReceived: MailReceivedModule,
onboardingChangeReceived: OnboardingChangeReceivedModule,
datawalletSynchronized: DatawalletSynchronizedModule,
identityDeletionProcessStatusChanged: IdentityDeletionProcessStatusChangedModule,
messageReceived: MessageReceivedModule,
relationshipChanged: RelationshipChangedModule,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CoreDate } from "@nmshd/core-types";
import { IdentityDeletionProcessStatus, IdentityDeletionProcessStatusChangedEvent } from "@nmshd/runtime";
import { AppRuntimeError } from "../../AppRuntimeError";
import { LocalAccountDeletionDateChangedEvent } from "../../events";
import { LocalAccountMapper } from "../../multiAccount/data/LocalAccountMapper";
import { AppRuntimeModule, AppRuntimeModuleConfiguration } from "../AppRuntimeModule";

export interface IdentityDeletionProcessStatusChangedModuleConfig extends AppRuntimeModuleConfiguration {}
Expand All @@ -19,25 +21,44 @@ export class IdentityDeletionProcessStatusChangedModule extends AppRuntimeModule
private async handleIdentityDeletionProcessStatusChanged(event: IdentityDeletionProcessStatusChangedEvent) {
const identityDeletionProcess = event.data;

if (!identityDeletionProcess) {
const services = await this.runtime.getServices(event.eventTargetAddress);
const identityDeletionProcesses = await services.transportServices.identityDeletionProcesses.getIdentityDeletionProcesses();

const approvedIdentityDeletionProcess = identityDeletionProcesses.value.filter((idp) => idp.status === IdentityDeletionProcessStatus.Approved).at(0);
const deletionDate = approvedIdentityDeletionProcess?.gracePeriodEndsAt ? CoreDate.from(approvedIdentityDeletionProcess.gracePeriodEndsAt) : undefined;

await this.updateLocalAccountDeletionDate(event.eventTargetAddress, deletionDate, true);
return;
}

switch (identityDeletionProcess.status) {
case IdentityDeletionProcessStatus.Approved:
await this.runtime.multiAccountController.updateLocalAccountDeletionDate(event.eventTargetAddress, CoreDate.from(identityDeletionProcess.gracePeriodEndsAt!));
await this.updateLocalAccountDeletionDate(event.eventTargetAddress, CoreDate.from(identityDeletionProcess.gracePeriodEndsAt!));
break;

case IdentityDeletionProcessStatus.Cancelled:
const account = await this.runtime.multiAccountController.getAccountByAddress(event.eventTargetAddress);
const previousDeletionDate = account.deletionDate;

if (!previousDeletionDate) break;

await this.runtime.multiAccountController.updateLocalAccountDeletionDate(event.eventTargetAddress, undefined);
await this.updateLocalAccountDeletionDate(event.eventTargetAddress, undefined);
break;

default:
break;
}
}

private async updateLocalAccountDeletionDate(eventTargetAddress: string, deletionDate: CoreDate | undefined, publishEvent = false) {
const account = await this.runtime.multiAccountController.getAccountByAddress(eventTargetAddress);
const previousDeletionDate = account.deletionDate;

if (!deletionDate && !previousDeletionDate) return;
if (deletionDate && previousDeletionDate && deletionDate.equals(previousDeletionDate)) return;

const localAccount = await this.runtime.multiAccountController.updateLocalAccountDeletionDate(eventTargetAddress, deletionDate);

if (!publishEvent) return;
this.runtime.eventBus.publish(new LocalAccountDeletionDateChangedEvent(eventTargetAddress, LocalAccountMapper.toLocalAccountDTO(localAccount)));
}

public override stop(): Promise<void> | void {
this.unsubscribeFromAllEvents();
}
Expand Down
1 change: 0 additions & 1 deletion packages/app-runtime/src/modules/runtimeEvents/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./DatawalletSynchronizedModule";
export * from "./IdentityDeletionProcessStatusChangedModule";
export * from "./MessageReceivedModule";
export * from "./RelationshipChangedModule";
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export class MultiAccountController {
await this._localAccounts.update(oldAccount, renamedAccount);
}

public async updateLocalAccountDeletionDate(address: string, deletionDate?: CoreDate): Promise<void> {
public async updateLocalAccountDeletionDate(address: string, deletionDate?: CoreDate): Promise<LocalAccount> {
const oldAccount = await this._localAccounts.findOne({ address });

if (!oldAccount) {
Expand All @@ -265,6 +265,8 @@ export class MultiAccountController {

const cachedAccount = this.sessionStorage.findSession(address)?.account;
if (cachedAccount) cachedAccount.deletionDate = deletionDate?.toString();

return account;
}

public async updateLastAccessedAt(accountId: string): Promise<void> {
Expand Down
44 changes: 2 additions & 42 deletions packages/app-runtime/test/lib/TestUtil.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable jest/no-standalone-expect */
import { ILoggerFactory } from "@js-soft/logging-abstractions";
import { SimpleLoggerFactory } from "@js-soft/simple-logger";
import { EventBus, Result, sleep, SubscriptionTarget } from "@js-soft/ts-utils";
import { EventBus, Result, sleep } from "@js-soft/ts-utils";
import { ArbitraryMessageContent, ArbitraryRelationshipCreationContent, ArbitraryRelationshipTemplateContent } from "@nmshd/content";
import { CoreDate } from "@nmshd/core-types";
import {
Expand Down Expand Up @@ -81,46 +81,6 @@ export class TestUtil {
TransportLoggerFactory.init(this.oldLogger);
}

public static async awaitEvent<TEvent>(
runtime: AppRuntime,
subscriptionTarget: SubscriptionTarget<TEvent>,
timeout?: number,
assertionFunction?: (t: TEvent) => boolean
): Promise<TEvent> {
const eventBus = runtime.eventBus;
let subscriptionId: number;

const eventPromise = new Promise<TEvent>((resolve) => {
subscriptionId = eventBus.subscribe(subscriptionTarget, (event: TEvent) => {
if (assertionFunction && !assertionFunction(event)) return;

resolve(event);
});
});
if (!timeout) {
return await eventPromise.finally(() => eventBus.unsubscribe(subscriptionId));
}

let timeoutId: NodeJS.Timeout;
const timeoutPromise = new Promise<TEvent>((_resolve, reject) => {
timeoutId = setTimeout(
() => reject(new Error(`timeout exceeded for waiting for event ${typeof subscriptionTarget === "string" ? subscriptionTarget : subscriptionTarget.name}`)),
timeout
);
});

return await Promise.race([eventPromise, timeoutPromise]).finally(() => {
eventBus.unsubscribe(subscriptionId);
clearTimeout(timeoutId);
});
}

public static async expectEvent<T>(runtime: AppRuntime, subscriptionTarget: SubscriptionTarget<T>, timeoutInMS = 1000): Promise<T> {
const eventInstance: T = await this.awaitEvent(runtime, subscriptionTarget, timeoutInMS);
expect(eventInstance, "Event received").toBeDefined();
return eventInstance;
}

public static expectThrows(method: Function | Promise<any>, errorMessageRegexp: RegExp | string): void {
let error: Error | undefined;
try {
Expand Down Expand Up @@ -292,7 +252,7 @@ export class TestUtil {
expiresAt: CoreDate.utc().add({ minutes: 5 }).toString(),
filename: "Test.bin",
mimetype: "application/json",
title: "Test",
title: "aFileName",
content: fileContent
});
return file.value;
Expand Down

This file was deleted.

Loading

0 comments on commit 745223c

Please sign in to comment.