Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend DeciderModule to automatically decide Requests #269

Merged
merged 79 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
0e1ee5e
feat: first draft
Milena-Czierlinski Aug 23, 2024
c83cf61
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Aug 29, 2024
1295ff7
feat: second draft
Milena-Czierlinski Aug 30, 2024
031412d
feat: add checkCompatibility
Milena-Czierlinski Sep 3, 2024
37f0aa5
feat: improve RequestItemConfig
Milena-Czierlinski Sep 3, 2024
54ff50d
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 3, 2024
2943fbf
feat: improve compatibility check e.g. for tags
Milena-Czierlinski Sep 4, 2024
22034e1
feat: validate responseConfig compatibility
Milena-Czierlinski Sep 4, 2024
6e0ff87
feat: use Results
Milena-Czierlinski Sep 9, 2024
f876f8e
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 9, 2024
2e92401
feat: publish event if request automatically decided
Milena-Czierlinski Sep 10, 2024
f560892
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 10, 2024
35a1105
refactor: rename function
Milena-Czierlinski Sep 11, 2024
4d6ee60
Merge branch 'main' into automatically-processed-requests
Milena-Czierlinski Sep 11, 2024
edb8e40
test: decide GeneralRequestConfig
Milena-Czierlinski Sep 11, 2024
d66d963
refactor: logging
Milena-Czierlinski Sep 11, 2024
a4c9eeb
feat: validate automationConfig in init
Milena-Czierlinski Sep 11, 2024
5d286d3
feat: improve error handling
Milena-Czierlinski Sep 11, 2024
78398ca
refactor: use containsDeep to check for RequestItems with requireManu…
Milena-Czierlinski Sep 11, 2024
ce3245c
fix: handle requestConfigs containing general and item-specific parts
Milena-Czierlinski Sep 12, 2024
fb44c78
test: RequestConfigs
Milena-Czierlinski Sep 12, 2024
ede1a7f
fix: consider RequestItemGroups correctly
Milena-Czierlinski Sep 13, 2024
52e1f53
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 13, 2024
74b5d4a
fix: adjust containsDeep to work with item objects
Milena-Czierlinski Sep 16, 2024
855e054
fix: check canDecide correctly
Milena-Czierlinski Sep 16, 2024
84e22f3
test: RequestItemDerivationConfigs
Milena-Czierlinski Sep 16, 2024
71e8514
feat: begin to frickle change of config using restart
Milena-Czierlinski Sep 16, 2024
5a6281a
Revert "feat: begin to frickle change of config using restart"
Milena-Czierlinski Sep 17, 2024
87bb34b
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 17, 2024
cdee5a1
test: all RequestItemDerivationConfigs
Milena-Czierlinski Sep 17, 2024
52fd818
feat: remove configs related to existing attributes
Milena-Czierlinski Sep 17, 2024
ae90f1f
test: validateAutomationConfig for all combinations
Milena-Czierlinski Sep 17, 2024
2469c12
test: remove unit tests that were effectively duplicated
Milena-Czierlinski Sep 17, 2024
caa092c
chore: remove todo comments
Milena-Czierlinski Sep 17, 2024
2b98d80
chore: remove todo comment
Milena-Czierlinski Sep 17, 2024
3e9cedc
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 17, 2024
460e8e6
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 18, 2024
bca6ae9
feat: hide automatically answered Request from user
Milena-Czierlinski Sep 18, 2024
103a99c
refactor: use jest's rejects.toThrow
Milena-Czierlinski Sep 18, 2024
692ff55
Merge branch 'automatically-processed-requests' of github.com:nmshd/r…
Milena-Czierlinski Sep 18, 2024
b925291
test: automatically decide Request from RelationshipTemplate
Milena-Czierlinski Sep 18, 2024
c2b1e1f
feat: integrate comments on DeciderModule
Milena-Czierlinski Sep 18, 2024
15024e8
refactor: integrate comments on DeciderModule test
Milena-Czierlinski Sep 18, 2024
d66fe66
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 18, 2024
c2a1918
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 19, 2024
61dcb6d
Merge remote-tracking branch 'origin/main' into automatically-process…
Milena-Czierlinski Sep 20, 2024
4dc4eeb
feat: extend functionality of GeneralRequestConfig
Milena-Czierlinski Sep 20, 2024
a7ab954
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 20, 2024
e641d97
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 23, 2024
62ad91b
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 23, 2024
aa96dd5
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 23, 2024
8162c66
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 23, 2024
15dd4f3
refactor: use explicit if instead of else if
Milena-Czierlinski Sep 24, 2024
dc6ee79
refactor: reoder RelationshipTemplateProcessResults
Milena-Czierlinski Sep 24, 2024
77ccbbf
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 25, 2024
5a1a4d2
Merge branch 'main' into automatically-processed-requests
mergify[bot] Sep 30, 2024
af7c91c
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 1, 2024
06bc854
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 1, 2024
ab6f06a
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 2, 2024
ad35ee3
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 2, 2024
8e0ff0a
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 2, 2024
6f5d006
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 7, 2024
df61611
feat: allow date comparisons
Magnus-Kuhn Oct 8, 2024
6858e27
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 8, 2024
0ae01c6
refactor: variable naming
Magnus-Kuhn Oct 8, 2024
eba9c7e
Merge branch 'automatically-processed-requests' of https://github.com…
Magnus-Kuhn Oct 8, 2024
42188c0
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 8, 2024
9a2d3e1
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 10, 2024
afc4540
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 11, 2024
4216eb4
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 11, 2024
f7e60c5
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 14, 2024
06f5d83
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 16, 2024
fe6b92b
chore: build schemas
Milena-Czierlinski Oct 16, 2024
d2ea0e8
refactor: move functions outside of module
Milena-Czierlinski Oct 16, 2024
41ad2aa
Merge branch 'automatically-processed-requests' of github.com:nmshd/r…
Milena-Czierlinski Oct 16, 2024
f32fadf
refactor: make validateAutomationConfig private
Milena-Czierlinski Oct 16, 2024
b150bcb
refactor: don't use Results
Milena-Czierlinski Oct 16, 2024
c8cb270
refactor: split test file
Milena-Czierlinski Oct 16, 2024
c85bb04
Merge branch 'main' into automatically-processed-requests
mergify[bot] Oct 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export class RelationshipTemplateProcessedModule extends AppRuntimeModule<Relati
);
break;
}

case RelationshipTemplateProcessedResult.RequestAutomaticallyDecided: {
break;
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions packages/runtime/src/RuntimeConfig.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { IConfigOverwrite } from "@nmshd/transport";
import { ModuleConfiguration } from "./extensibility/modules/RuntimeModule";
import { DeciderModuleConfiguration } from "./modules";

export interface RuntimeConfig {
transportLibrary: Omit<IConfigOverwrite, "supportedIdentityVersion">;

modules: Record<string, ModuleConfiguration>;
modules: Record<string, ModuleConfiguration> & {
decider: DeciderModuleConfiguration;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class MessageProcessedEvent extends DataEvent<MessageProcessedEventData>
}

export enum MessageProcessedResult {
RequestAutomaticallyDecided = "RequestAutomaticallyDecided",
ManualRequestDecisionRequired = "ManualRequestDecisionRequired",
NoRequest = "NoRequest",
Error = "Error"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class RelationshipTemplateProcessedEvent extends DataEvent<RelationshipTe
}

export enum RelationshipTemplateProcessedResult {
RequestAutomaticallyDecided = "RequestAutomaticallyDecided",
ManualRequestDecisionRequired = "ManualRequestDecisionRequired",
NonCompletedRequestExists = "NonCompletedRequestExists",
RelationshipExists = "RelationshipExists",
Expand All @@ -20,6 +21,11 @@ export enum RelationshipTemplateProcessedResult {
}

export type RelationshipTemplateProcessedEventData =
| {
template: RelationshipTemplateDTO;
result: RelationshipTemplateProcessedResult.RequestAutomaticallyDecided;
requestId: string;
}
| {
template: RelationshipTemplateDTO;
result: RelationshipTemplateProcessedResult.ManualRequestDecisionRequired;
Expand Down
333 changes: 322 additions & 11 deletions packages/runtime/src/modules/DeciderModule.ts

Large diffs are not rendered by default.

147 changes: 147 additions & 0 deletions packages/runtime/src/modules/decide/RequestConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { RelationshipAttributeConfidentiality } from "@nmshd/content";

export interface GeneralRequestConfig {
peer?: string | string[];
createdAt?: string | string[];
"source.type"?: "Message" | "RelationshipTemplate";
"content.expiresAt"?: string | string[];
"content.title"?: string | string[];
"content.description"?: string | string[];
"content.metadata"?: object | object[];
}

export interface RequestItemConfig extends GeneralRequestConfig {
"content.item.@type"?: string | string[];
"content.item.mustBeAccepted"?: boolean;
"content.item.title"?: string | string[];
"content.item.description"?: string | string[];
"content.item.metadata"?: object | object[];
}

export interface AuthenticationRequestItemConfig extends RequestItemConfig {
"content.item.@type": "AuthenticationRequestItem";
}

export interface ConsentRequestItemConfig extends RequestItemConfig {
"content.item.@type": "ConsentRequestItem";
"content.item.consent"?: string | string[];
"content.item.link"?: string | string[];
}

export interface CreateAttributeRequestItemConfig extends RequestItemConfig {
"content.item.@type": "CreateAttributeRequestItem";
"content.item.attribute.@type"?: "IdentityAttribute" | "RelationshipAttribute";
"content.item.attribute.owner"?: string | string[];
"content.item.attribute.validFrom"?: string | string[];
"content.item.attribute.validTo"?: string | string[];
"content.item.attribute.tags"?: string[];
"content.item.attribute.key"?: string | string[];
"content.item.attribute.isTechnical"?: boolean;
"content.item.attribute.confidentiality"?: RelationshipAttributeConfidentiality | RelationshipAttributeConfidentiality[];
"content.item.attribute.value.@type"?: string | string[];
"content.item.attribute.value.value"?: string | string[];
"content.item.attribute.value.title"?: string | string[];
"content.item.attribute.value.description"?: string | string[];
}

export interface DeleteAttributeRequestItemConfig extends RequestItemConfig {
"content.item.@type": "DeleteAttributeRequestItem";
}

export interface FreeTextRequestItemConfig extends RequestItemConfig {
"content.item.@type": "FreeTextRequestItem";
"content.item.freeText"?: string | string[];
}

export interface ProposeAttributeRequestItemConfig extends RequestItemConfig {
"content.item.@type": "ProposeAttributeRequestItem";
"content.item.attribute.@type"?: "IdentityAttribute" | "RelationshipAttribute";
"content.item.attribute.owner"?: string | string[];
"content.item.attribute.validFrom"?: string | string[];
"content.item.attribute.validTo"?: string | string[];
"content.item.attribute.tags"?: string[];
"content.item.attribute.key"?: string | string[];
"content.item.attribute.isTechnical"?: boolean;
"content.item.attribute.confidentiality"?: RelationshipAttributeConfidentiality | RelationshipAttributeConfidentiality[];
"content.item.attribute.value.@type"?: string | string[];
"content.item.attribute.value.value"?: string | string[];
"content.item.attribute.value.title"?: string | string[];
"content.item.attribute.value.description"?: string | string[];
"content.item.query.@type"?: "IdentityAttributeQuery" | "RelationshipAttributeQuery" | "IQLQuery";
"content.item.query.validFrom"?: string | string[];
"content.item.query.validTo"?: string | string[];
"content.item.query.valueType"?: string | string[];
"content.item.query.tags"?: string[];
"content.item.query.key"?: string | string[];
"content.item.query.owner"?: string | string[];
"content.item.query.queryString"?: string | string[];
"content.item.query.attributeCreationHints.title"?: string | string[];
"content.item.query.attributeCreationHints.description"?: string | string[];
"content.item.query.attributeCreationHints.valueType"?: string | string[];
"content.item.query.attributeCreationHints.confidentiality"?: RelationshipAttributeConfidentiality | RelationshipAttributeConfidentiality[];
"content.item.query.attributeCreationHints.tags"?: string[];
}

export interface ReadAttributeRequestItemConfig extends RequestItemConfig {
"content.item.@type": "ReadAttributeRequestItem";
"content.item.query.@type"?: "IdentityAttributeQuery" | "RelationshipAttributeQuery" | "IQLQuery";
"content.item.query.validFrom"?: string | string[];
"content.item.query.validTo"?: string | string[];
"content.item.query.valueType"?: string | string[];
"content.item.query.tags"?: string[];
"content.item.query.key"?: string | string[];
"content.item.query.owner"?: string | string[];
"content.item.query.queryString"?: string | string[];
"content.item.query.attributeCreationHints.title"?: string | string[];
"content.item.query.attributeCreationHints.description"?: string | string[];
"content.item.query.attributeCreationHints.valueType"?: string | string[];
"content.item.query.attributeCreationHints.confidentiality"?: RelationshipAttributeConfidentiality | RelationshipAttributeConfidentiality[];
"content.item.query.attributeCreationHints.tags"?: string[];
}

export interface RegisterAttributeListenerRequestItemConfig extends RequestItemConfig {
"content.item.@type": "RegisterAttributeListenerRequestItem";
"content.item.query.@type"?: "IdentityAttributeQuery";
"content.item.query.validFrom"?: string | string[];
"content.item.query.validTo"?: string | string[];
"content.item.query.valueType"?: string | string[];
"content.item.query.tags"?: string[];
}

export interface ShareAttributeRequestItemConfig extends RequestItemConfig {
"content.item.@type": "ShareAttributeRequestItem";
"content.item.attribute.@type"?: "IdentityAttribute" | "RelationshipAttribute";
"content.item.attribute.owner"?: string | string[];
"content.item.attribute.validFrom"?: string | string[];
"content.item.attribute.validTo"?: string | string[];
"content.item.attribute.tags"?: string[];
"content.item.attribute.key"?: string | string[];
"content.item.attribute.isTechnical"?: boolean;
"content.item.attribute.confidentiality"?: RelationshipAttributeConfidentiality | RelationshipAttributeConfidentiality[];
"content.item.attribute.value.@type"?: string | string[];
"content.item.attribute.value.value"?: string | string[];
"content.item.attribute.value.title"?: string | string[];
"content.item.attribute.value.description"?: string | string[];
}

export type RequestItemDerivationConfig =
| RequestItemConfig
| AuthenticationRequestItemConfig
| ConsentRequestItemConfig
| CreateAttributeRequestItemConfig
| DeleteAttributeRequestItemConfig
| FreeTextRequestItemConfig
| ProposeAttributeRequestItemConfig
| ReadAttributeRequestItemConfig
| RegisterAttributeListenerRequestItemConfig
| ShareAttributeRequestItemConfig;

export function isGeneralRequestConfig(input: any): input is GeneralRequestConfig {
return !Object.keys(input).some((key) => key.startsWith("content.item."));
}

export function isRequestItemDerivationConfig(input: any): input is RequestItemDerivationConfig {
return Object.keys(input).some((key) => key.startsWith("content.item."));
}

export type RequestConfig = GeneralRequestConfig | RequestItemDerivationConfig;
64 changes: 64 additions & 0 deletions packages/runtime/src/modules/decide/ResponseConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { IdentityAttribute, RelationshipAttribute } from "@nmshd/content";

export interface RejectResponseConfig {
accept: false;
code?: string;
message?: string;
}

export function isRejectResponseConfig(input: any): input is RejectResponseConfig {
return input.accept === false;
}

export interface AcceptResponseConfig {
accept: true;
}

export function isAcceptResponseConfig(input: any): input is AcceptResponseConfig {
return input.accept === true;
}

export function isSimpleAcceptResponseConfig(input: any): input is AcceptResponseConfig {
return input.accept === true && Object.keys(input).length === 1;
}

export interface DeleteAttributeAcceptResponseConfig extends AcceptResponseConfig {
deletionDate: string;
}

export function isDeleteAttributeAcceptResponseConfig(object: any): object is DeleteAttributeAcceptResponseConfig {
return "deletionDate" in object;
}

export interface FreeTextAcceptResponseConfig extends AcceptResponseConfig {
freeText: string;
}

export function isFreeTextAcceptResponseConfig(object: any): object is FreeTextAcceptResponseConfig {
return "freeText" in object;
}

export interface ProposeAttributeWithNewAttributeAcceptResponseConfig extends AcceptResponseConfig {
attribute: IdentityAttribute | RelationshipAttribute;
}

export function isProposeAttributeWithNewAttributeAcceptResponseConfig(object: any): object is ProposeAttributeWithNewAttributeAcceptResponseConfig {
return "attribute" in object;
}

export interface ReadAttributeWithNewAttributeAcceptResponseConfig extends AcceptResponseConfig {
newAttribute: IdentityAttribute | RelationshipAttribute;
}

export function isReadAttributeWithNewAttributeAcceptResponseConfig(object: any): object is ReadAttributeWithNewAttributeAcceptResponseConfig {
return "newAttribute" in object;
}

export type AcceptResponseConfigDerivation =
| AcceptResponseConfig
| DeleteAttributeAcceptResponseConfig
| FreeTextAcceptResponseConfig
| ProposeAttributeWithNewAttributeAcceptResponseConfig
| ReadAttributeWithNewAttributeAcceptResponseConfig;

export type ResponseConfig = AcceptResponseConfigDerivation | RejectResponseConfig;
2 changes: 2 additions & 0 deletions packages/runtime/src/modules/decide/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./RequestConfig";
export * from "./ResponseConfig";
34 changes: 34 additions & 0 deletions packages/runtime/src/useCases/common/RuntimeErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,39 @@ class IdentityDeletionProcess {
}
}

class DeciderModule {
public doesNotHaveAutomationConfig() {
return new ApplicationError("error.runtime.decide.doesNotHaveAutomationConfig", "The Request can't be decided automatically, since no automationConfig was provided.");
}

public someItemsOfRequestCouldNotBeDecidedAutomatically() {
return new ApplicationError(
"error.runtime.decide.someItemsOfRequestCouldNotBeDecidedAutomatically",
"The Request couldn't be decided automatically, since it contains RequestItems for which no suitable automationConfig was provided."
);
}

public requestConfigDoesNotMatchResponseConfig() {
return new ApplicationError("error.runtime.decide.requestConfigDoesNotMatchResponseConfig", "The RequestConfig does not match the ResponseConfig.");
}

public canRejectRequestFailed(requestId: string, errorMessage?: string) {
return new ApplicationError("error.runtime.decide.canRejectRequestFailed", `Can not reject Request ${requestId}: ${errorMessage}`);
}

public canAcceptRequestFailed(requestId: string, errorMessage?: string) {
return new ApplicationError("error.runtime.decide.canAcceptRequestFailed", `Can not accept Request ${requestId}: ${errorMessage}`);
}

public rejectRequestFailed(requestId: string, errorMessage: string) {
return new ApplicationError("error.runtime.decide.rejectRequestFailed", `An error occured trying to reject Request ${requestId}: ${errorMessage}`);
}

public acceptRequestFailed(requestId: string, errorMessage: string) {
return new ApplicationError("error.runtime.decide.acceptRequestFailed", `An error occured trying to accept Request ${requestId}: ${errorMessage}`);
}
}

export class RuntimeErrors {
public static readonly general = new General();
public static readonly serval = new Serval();
Expand All @@ -253,4 +286,5 @@ export class RuntimeErrors {
public static readonly notifications = new Notifications();
public static readonly attributes = new Attributes();
public static readonly identityDeletionProcess = new IdentityDeletionProcess();
public static readonly deciderModule = new DeciderModule();
}
6 changes: 5 additions & 1 deletion packages/runtime/test/lib/RuntimeServiceProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import correlator from "correlation-id";
import { AnonymousServices, ConsumptionServices, DataViewExpander, RuntimeConfig, TransportServices } from "../../src";
import { AnonymousServices, ConsumptionServices, DataViewExpander, DeciderModuleConfigurationOverwrite, RuntimeConfig, TransportServices } from "../../src";
import { MockEventBus } from "./MockEventBus";
import { TestRuntime } from "./TestRuntime";

Expand All @@ -15,6 +15,7 @@ export interface TestRuntimeServices {
export interface LaunchConfiguration {
enableDatawallet?: boolean;
enableDeciderModule?: boolean;
configureDeciderModule?: DeciderModuleConfigurationOverwrite;
enableRequestModule?: boolean;
enableAttributeListenerModule?: boolean;
enableNotificationModule?: boolean;
Expand Down Expand Up @@ -86,13 +87,16 @@ export class RuntimeServiceProvider {
if (launchConfiguration.enableAttributeListenerModule) config.modules.attributeListener.enabled = true;
if (launchConfiguration.enableNotificationModule) config.modules.notification.enabled = true;

config.modules.decider.automationConfig = launchConfiguration.configureDeciderModule?.automationConfig;

const runtime = new TestRuntime(
config,
{
setDefaultRepositoryAttributes: launchConfiguration.enableDefaultRepositoryAttributes ?? false
},
launchConfiguration.useCorrelator ? correlator : undefined
);

this.runtimes.push(runtime);

await runtime.init();
Expand Down
Loading