Skip to content

Commit 5e81f68

Browse files
Magnus-Kuhnmergify[bot]britsta
authored
Add UseCases to delete Files, RelationshipTemplates and Tokens (#432)
* feat: delete files from backbone * feat: add isOwn check to tokens and templates * feat: adapt files, add use cases * test: add transport tests * refactor: remove unused error * test: add runtime tests * test: fix test * test: improve tests * test: fix token decomposition * fix: sync datawallet * refactor: test names * refactor: capitalize test describe block names Co-authored-by: Britta Stallknecht <[email protected]> * refactor: test name capitalization --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Britta Stallknecht <[email protected]>
1 parent 23b0ae3 commit 5e81f68

File tree

19 files changed

+383
-15
lines changed

19 files changed

+383
-15
lines changed

packages/runtime/src/extensibility/facades/transport/FilesFacade.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
CreateTokenQRCodeForFileRequest,
1111
CreateTokenQRCodeForFileResponse,
1212
CreateTokenQRCodeForFileUseCase,
13+
DeleteFileRequest,
14+
DeleteFileUseCase,
1315
DownloadFileRequest,
1416
DownloadFileResponse,
1517
DownloadFileUseCase,
@@ -30,6 +32,7 @@ export class FilesFacade {
3032
@Inject private readonly getFilesUseCase: GetFilesUseCase,
3133
@Inject private readonly downloadFileUseCase: DownloadFileUseCase,
3234
@Inject private readonly getFileUseCase: GetFileUseCase,
35+
@Inject private readonly deleteFileUseCase: DeleteFileUseCase,
3336
@Inject private readonly createQRCodeForFileUseCase: CreateQRCodeForFileUseCase,
3437
@Inject private readonly createTokenForFileUseCase: CreateTokenForFileUseCase,
3538
@Inject private readonly createTokenQRCodeForFileUseCase: CreateTokenQRCodeForFileUseCase
@@ -55,6 +58,10 @@ export class FilesFacade {
5558
return await this.uploadOwnFileUseCase.execute(request);
5659
}
5760

61+
public async deleteFile(request: DeleteFileRequest): Promise<Result<void>> {
62+
return await this.deleteFileUseCase.execute(request);
63+
}
64+
5865
public async createQRCodeForFile(request: CreateQRCodeForFileRequest): Promise<Result<CreateQRCodeForFileResponse>> {
5966
return await this.createQRCodeForFileUseCase.execute(request);
6067
}

packages/runtime/src/extensibility/facades/transport/RelationshipTemplatesFacade.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
CreateTokenQRCodeForOwnTemplateRequest,
1313
CreateTokenQRCodeForOwnTemplateResponse,
1414
CreateTokenQRCodeForOwnTemplateUseCase,
15+
DeleteRelationshipTemplateRequest,
16+
DeleteRelationshipTemplateUseCase,
1517
GetRelationshipTemplateRequest,
1618
GetRelationshipTemplateUseCase,
1719
GetRelationshipTemplatesRequest,
@@ -26,6 +28,7 @@ export class RelationshipTemplatesFacade {
2628
@Inject private readonly loadPeerRelationshipTemplateUseCase: LoadPeerRelationshipTemplateUseCase,
2729
@Inject private readonly getRelationshipTemplatesUseCase: GetRelationshipTemplatesUseCase,
2830
@Inject private readonly getRelationshipTemplateUseCase: GetRelationshipTemplateUseCase,
31+
@Inject private readonly deleteRelationshipTemplateUseCase: DeleteRelationshipTemplateUseCase,
2932
@Inject private readonly createQRCodeForOwnTemplateUseCase: CreateQRCodeForOwnTemplateUseCase,
3033
@Inject private readonly createTokenQRCodeForOwnTemplateUseCase: CreateTokenQRCodeForOwnTemplateUseCase,
3134
@Inject private readonly createTokenForOwnTemplateUseCase: CreateTokenForOwnTemplateUseCase
@@ -47,6 +50,10 @@ export class RelationshipTemplatesFacade {
4750
return await this.getRelationshipTemplateUseCase.execute(request);
4851
}
4952

53+
public async deleteRelationshipTemplate(request: DeleteRelationshipTemplateRequest): Promise<Result<void>> {
54+
return await this.deleteRelationshipTemplateUseCase.execute(request);
55+
}
56+
5057
public async createQRCodeForOwnTemplate(request: CreateQRCodeForOwnTemplateRequest): Promise<Result<CreateQRCodeForOwnTemplateResponse>> {
5158
return await this.createQRCodeForOwnTemplateUseCase.execute(request);
5259
}

packages/runtime/src/extensibility/facades/transport/TokensFacade.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { TokenDTO } from "../../../types";
44
import {
55
CreateOwnTokenRequest,
66
CreateOwnTokenUseCase,
7+
DeleteTokenRequest,
8+
DeleteTokenUseCase,
79
GetQRCodeForTokenRequest,
810
GetQRCodeForTokenResponse,
911
GetQRCodeForTokenUseCase,
@@ -21,6 +23,7 @@ export class TokensFacade {
2123
@Inject private readonly loadPeerTokenUseCase: LoadPeerTokenUseCase,
2224
@Inject private readonly getTokensUseCase: GetTokensUseCase,
2325
@Inject private readonly getTokenUseCase: GetTokenUseCase,
26+
@Inject private readonly deleteTokenUseCase: DeleteTokenUseCase,
2427
@Inject private readonly getQRCodeForTokenUseCase: GetQRCodeForTokenUseCase
2528
) {}
2629

@@ -40,6 +43,10 @@ export class TokensFacade {
4043
return await this.getTokenUseCase.execute(request);
4144
}
4245

46+
public async deleteToken(request: DeleteTokenRequest): Promise<Result<void>> {
47+
return await this.deleteTokenUseCase.execute(request);
48+
}
49+
4350
public async getQRCodeForToken(request: GetQRCodeForTokenRequest): Promise<Result<GetQRCodeForTokenResponse>> {
4451
return await this.getQRCodeForTokenUseCase.execute(request);
4552
}

packages/runtime/src/useCases/common/Schemas.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20284,6 +20284,29 @@ export const CreateTokenQRCodeForFileRequest: any = {
2028420284
}
2028520285
}
2028620286

20287+
export const DeleteFileRequest: any = {
20288+
"$schema": "http://json-schema.org/draft-07/schema#",
20289+
"$ref": "#/definitions/DeleteFileRequest",
20290+
"definitions": {
20291+
"DeleteFileRequest": {
20292+
"type": "object",
20293+
"properties": {
20294+
"fileId": {
20295+
"$ref": "#/definitions/FileIdString"
20296+
}
20297+
},
20298+
"required": [
20299+
"fileId"
20300+
],
20301+
"additionalProperties": false
20302+
},
20303+
"FileIdString": {
20304+
"type": "string",
20305+
"pattern": "FIL[A-Za-z0-9]{17}"
20306+
}
20307+
}
20308+
}
20309+
2028720310
export const GetFileRequest: any = {
2028820311
"$schema": "http://json-schema.org/draft-07/schema#",
2028920312
"$ref": "#/definitions/GetFileRequest",
@@ -21574,6 +21597,29 @@ export const CreateTokenQRCodeForOwnTemplateRequest: any = {
2157421597
}
2157521598
}
2157621599

21600+
export const DeleteRelationshipTemplateRequest: any = {
21601+
"$schema": "http://json-schema.org/draft-07/schema#",
21602+
"$ref": "#/definitions/DeleteRelationshipTemplateRequest",
21603+
"definitions": {
21604+
"DeleteRelationshipTemplateRequest": {
21605+
"type": "object",
21606+
"properties": {
21607+
"templateId": {
21608+
"$ref": "#/definitions/RelationshipTemplateIdString"
21609+
}
21610+
},
21611+
"required": [
21612+
"templateId"
21613+
],
21614+
"additionalProperties": false
21615+
},
21616+
"RelationshipTemplateIdString": {
21617+
"type": "string",
21618+
"pattern": "RLT[A-Za-z0-9]{17}"
21619+
}
21620+
}
21621+
}
21622+
2157721623
export const GetRelationshipTemplateRequest: any = {
2157821624
"$schema": "http://json-schema.org/draft-07/schema#",
2157921625
"$ref": "#/definitions/GetRelationshipTemplateRequest",
@@ -21839,6 +21885,29 @@ export const CreateOwnTokenRequest: any = {
2183921885
}
2184021886
}
2184121887

21888+
export const DeleteTokenRequest: any = {
21889+
"$schema": "http://json-schema.org/draft-07/schema#",
21890+
"$ref": "#/definitions/DeleteTokenRequest",
21891+
"definitions": {
21892+
"DeleteTokenRequest": {
21893+
"type": "object",
21894+
"properties": {
21895+
"tokenId": {
21896+
"$ref": "#/definitions/TokenIdString"
21897+
}
21898+
},
21899+
"required": [
21900+
"tokenId"
21901+
],
21902+
"additionalProperties": false
21903+
},
21904+
"TokenIdString": {
21905+
"type": "string",
21906+
"pattern": "TOK[A-Za-z0-9]{17}"
21907+
}
21908+
}
21909+
}
21910+
2184221911
export const GetQRCodeForTokenRequest: any = {
2184321912
"$schema": "http://json-schema.org/draft-07/schema#",
2184421913
"$ref": "#/definitions/GetQRCodeForTokenRequest",
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Result } from "@js-soft/ts-utils";
2+
import { CoreId } from "@nmshd/core-types";
3+
import { AccountController, File, FileController } from "@nmshd/transport";
4+
import { Inject } from "@nmshd/typescript-ioc";
5+
import { FileIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common";
6+
7+
export interface DeleteFileRequest {
8+
fileId: FileIdString;
9+
}
10+
11+
class Validator extends SchemaValidator<DeleteFileRequest> {
12+
public constructor(@Inject schemaRepository: SchemaRepository) {
13+
super(schemaRepository.getSchema("DeleteFileRequest"));
14+
}
15+
}
16+
17+
export class DeleteFileUseCase extends UseCase<DeleteFileRequest, void> {
18+
public constructor(
19+
@Inject private readonly fileController: FileController,
20+
@Inject private readonly accountController: AccountController,
21+
@Inject validator: Validator
22+
) {
23+
super(validator);
24+
}
25+
26+
protected async executeInternal(request: DeleteFileRequest): Promise<Result<void>> {
27+
const file = await this.fileController.getFile(CoreId.from(request.fileId));
28+
if (!file) {
29+
return Result.fail(RuntimeErrors.general.recordNotFound(File));
30+
}
31+
32+
await this.fileController.deleteFile(file);
33+
await this.accountController.syncDatawallet();
34+
35+
return Result.ok(undefined);
36+
}
37+
}

packages/runtime/src/useCases/transport/files/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export * from "./CreateQRCodeForFile";
22
export * from "./CreateTokenForFile";
33
export * from "./CreateTokenQRCodeForFile";
4+
export * from "./DeleteFile";
45
export * from "./DownloadFile";
56
export * from "./FileMapper";
67
export * from "./GetFile";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Result } from "@js-soft/ts-utils";
2+
import { CoreId } from "@nmshd/core-types";
3+
import { AccountController, RelationshipTemplate, RelationshipTemplateController } from "@nmshd/transport";
4+
import { Inject } from "@nmshd/typescript-ioc";
5+
import { RelationshipTemplateIdString, RuntimeErrors, SchemaRepository, SchemaValidator, UseCase } from "../../common";
6+
7+
export interface DeleteRelationshipTemplateRequest {
8+
templateId: RelationshipTemplateIdString;
9+
}
10+
11+
class Validator extends SchemaValidator<DeleteRelationshipTemplateRequest> {
12+
public constructor(@Inject schemaRepository: SchemaRepository) {
13+
super(schemaRepository.getSchema("DeleteRelationshipTemplateRequest"));
14+
}
15+
}
16+
17+
export class DeleteRelationshipTemplateUseCase extends UseCase<DeleteRelationshipTemplateRequest, void> {
18+
public constructor(
19+
@Inject private readonly relationshipTemplateController: RelationshipTemplateController,
20+
@Inject private readonly accountController: AccountController,
21+
@Inject validator: Validator
22+
) {
23+
super(validator);
24+
}
25+
26+
protected async executeInternal(request: DeleteRelationshipTemplateRequest): Promise<Result<void>> {
27+
const template = await this.relationshipTemplateController.getRelationshipTemplate(CoreId.from(request.templateId));
28+
if (!template) {
29+
return Result.fail(RuntimeErrors.general.recordNotFound(RelationshipTemplate));
30+
}
31+
32+
await this.relationshipTemplateController.deleteRelationshipTemplate(template);
33+
await this.accountController.syncDatawallet();
34+
35+
return Result.ok(undefined);
36+
}
37+
}

packages/runtime/src/useCases/transport/relationshipTemplates/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from "./CreateOwnRelationshipTemplate";
22
export * from "./CreateQRCodeForOwnRelationshipTemplate";
33
export * from "./CreateTokenForOwnRelationshipTemplate";
44
export * from "./CreateTokenQRCodeForOwnRelationshipTemplate";
5+
export * from "./DeleteRelationshipTemplate";
56
export * from "./GetRelationshipTemplate";
67
export * from "./GetRelationshipTemplates";
78
export * from "./LoadPeerRelationshipTemplate";
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Result } from "@js-soft/ts-utils";
2+
import { CoreId } from "@nmshd/core-types";
3+
import { AccountController, Token, TokenController } from "@nmshd/transport";
4+
import { Inject } from "@nmshd/typescript-ioc";
5+
import { RuntimeErrors, SchemaRepository, SchemaValidator, TokenIdString, UseCase } from "../../common";
6+
7+
export interface DeleteTokenRequest {
8+
tokenId: TokenIdString;
9+
}
10+
11+
class Validator extends SchemaValidator<DeleteTokenRequest> {
12+
public constructor(@Inject schemaRepository: SchemaRepository) {
13+
super(schemaRepository.getSchema("DeleteTokenRequest"));
14+
}
15+
}
16+
17+
export class DeleteTokenUseCase extends UseCase<DeleteTokenRequest, void> {
18+
public constructor(
19+
@Inject private readonly tokenController: TokenController,
20+
@Inject private readonly accountController: AccountController,
21+
@Inject validator: Validator
22+
) {
23+
super(validator);
24+
}
25+
26+
protected async executeInternal(request: DeleteTokenRequest): Promise<Result<void>> {
27+
const token = await this.tokenController.getToken(CoreId.from(request.tokenId));
28+
if (!token) {
29+
return Result.fail(RuntimeErrors.general.recordNotFound(Token));
30+
}
31+
32+
await this.tokenController.delete(token);
33+
await this.accountController.syncDatawallet();
34+
35+
return Result.ok(undefined);
36+
}
37+
}

packages/runtime/src/useCases/transport/tokens/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from "./CreateOwnToken";
2+
export * from "./DeleteToken";
23
export * from "./GetQRCodeForToken";
34
export * from "./GetToken";
45
export * from "./GetTokens";

packages/runtime/test/transport/files.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,26 @@ describe("Upload big files", () => {
197197
});
198198
});
199199

200+
describe("Delete file", () => {
201+
test("accessing invalid file id causes an error", async () => {
202+
const response = await transportServices1.files.deleteFile({ fileId: UNKNOWN_FILE_ID });
203+
expect(response).toBeAnError("File not found. Make sure the ID exists and the record is not expired.", "error.runtime.recordNotFound");
204+
});
205+
206+
test("successfully delete file", async () => {
207+
const uploadResponse = await transportServices1.files.uploadOwnFile(await makeUploadRequest());
208+
expect(uploadResponse).toBeSuccessful();
209+
const file = uploadResponse.value;
210+
expect(file).toBeDefined();
211+
212+
const deleteFileResponse = await transportServices1.files.deleteFile({ fileId: file.id });
213+
expect(deleteFileResponse).toBeSuccessful();
214+
215+
const getFileResponse = await transportServices1.files.getFile({ id: file.id });
216+
expect(getFileResponse).toBeAnError("File not found. Make sure the ID exists and the record is not expired.", "error.runtime.recordNotFound");
217+
});
218+
});
219+
200220
describe("Files query", () => {
201221
test("files can be queried by their attributes", async () => {
202222
const file = await uploadFile(transportServices1);

packages/runtime/test/transport/relationshipTemplates.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const serviceProvider = new RuntimeServiceProvider();
77
let runtimeServices1: TestRuntimeServices;
88
let runtimeServices2: TestRuntimeServices;
99

10+
const UNKNOWN_TEMPLATE_ID = "RLTXXXXXXXXXXXXXXXXX";
11+
1012
beforeAll(async () => {
1113
const runtimeServices = await serviceProvider.launch(2);
1214
runtimeServices1 = runtimeServices[0];
@@ -247,6 +249,28 @@ describe("RelationshipTemplate Tests", () => {
247249
expect(createQRCodeWithoutPersonalizationResult).toBeAnError(/.*/, "error.runtime.relationshipTemplates.personalizationMustBeInherited");
248250
});
249251
});
252+
253+
describe("Delete template", () => {
254+
test("accessing invalid template id causes an error", async () => {
255+
const response = await runtimeServices1.transport.relationshipTemplates.deleteRelationshipTemplate({ templateId: UNKNOWN_TEMPLATE_ID });
256+
expect(response).toBeAnError("RelationshipTemplate not found. Make sure the ID exists and the record is not expired.", "error.runtime.recordNotFound");
257+
});
258+
259+
test("successfully delete template", async () => {
260+
const template = (
261+
await runtimeServices1.transport.relationshipTemplates.createOwnRelationshipTemplate({
262+
content: emptyRelationshipTemplateContent,
263+
expiresAt: DateTime.utc().plus({ minutes: 1 }).toString()
264+
})
265+
).value;
266+
267+
const deleteTemplateResponse = await runtimeServices1.transport.relationshipTemplates.deleteRelationshipTemplate({ templateId: template.id });
268+
expect(deleteTemplateResponse).toBeSuccessful();
269+
270+
const getTemplateResponse = await runtimeServices1.transport.relationshipTemplates.getRelationshipTemplate({ id: template.id });
271+
expect(getTemplateResponse).toBeAnError("RelationshipTemplate not found. Make sure the ID exists and the record is not expired.", "error.runtime.recordNotFound");
272+
});
273+
});
250274
});
251275

252276
describe("Serialization Errors", () => {

0 commit comments

Comments
 (0)