@tstdl/base 0.92.138 → 0.92.140
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/ai.service.js +1 -1
- package/css/css-variables.d.ts +14 -0
- package/css/css-variables.js +55 -0
- package/css/index.d.ts +1 -0
- package/css/index.js +1 -0
- package/document-management/api/document-management.api.d.ts +59 -0
- package/document-management/api/document-management.api.js +28 -0
- package/document-management/server/api/document-management.api.d.ts +4 -1
- package/document-management/server/api/document-management.api.js +61 -28
- package/document-management/server/configure.d.ts +2 -0
- package/document-management/server/configure.js +9 -0
- package/document-management/server/drizzle/{0000_magical_madame_hydra.sql → 0000_moaning_luckman.sql} +4 -15
- package/document-management/server/drizzle/meta/0000_snapshot.json +25 -96
- package/document-management/server/drizzle/meta/_journal.json +2 -2
- package/document-management/server/index.d.ts +1 -0
- package/document-management/server/index.js +1 -0
- package/document-management/server/module.d.ts +3 -2
- package/document-management/server/module.js +2 -6
- package/document-management/server/services/document-category-type.service.d.ts +0 -1
- package/document-management/server/services/document-category-type.service.js +7 -7
- package/document-management/server/services/document-file.service.js +2 -2
- package/document-management/server/services/document-management-ai.service.js +5 -1
- package/document-management/server/services/document-management-ancillary.service.d.ts +2 -83
- package/document-management/server/services/document-management-ancillary.service.js +1 -23
- package/document-management/server/services/document-management-authorization.service.d.ts +85 -0
- package/document-management/server/services/document-management-authorization.service.js +28 -0
- package/document-management/server/services/document-management.service.d.ts +10 -2
- package/document-management/server/services/document-management.service.js +69 -6
- package/document-management/server/services/document-property.service.d.ts +7 -3
- package/document-management/server/services/document-property.service.js +8 -4
- package/document-management/server/services/document-workflow.service.js +2 -2
- package/document-management/server/services/enum-type-key.d.ts +1 -0
- package/document-management/server/services/enum-type-key.js +1 -0
- package/document-management/server/services/index.d.ts +1 -0
- package/document-management/server/services/index.js +1 -0
- package/document-management/service-models/enriched/enriched-document-category.view.d.ts +1 -0
- package/document-management/service-models/enriched/enriched-document-category.view.js +8 -0
- package/document-management/service-models/enriched/enriched-document.view.d.ts +3 -1
- package/document-management/service-models/enriched/enriched-document.view.js +2 -0
- package/examples/api/streaming.js +8 -8
- package/examples/document-management/categories-and-types.d.ts +357 -312
- package/examples/document-management/categories-and-types.js +690 -350
- package/examples/document-management/main.d.ts +18 -16
- package/examples/document-management/main.js +29 -20
- package/file/mime-type.d.ts +2 -1
- package/file/mime-type.js +10 -18
- package/file/mime-types.js +1 -2
- package/http/server/http-server-response.js +2 -2
- package/package.json +5 -3
- package/schema/converters/openapi-converter.js +15 -12
- package/sse/server-sent-events-source.js +2 -2
- package/utils/object/object.js +1 -1
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import './schemas.js';
|
|
2
2
|
import { type InjectionToken } from '../../injector/index.js';
|
|
3
3
|
import type { DatabaseConfig } from '../../orm/server/module.js';
|
|
4
|
-
import { DocumentManagementAncillaryService } from './services/document-management-ancillary.service.js';
|
|
4
|
+
import type { DocumentManagementAncillaryService } from './services/document-management-ancillary.service.js';
|
|
5
|
+
import type { DocumentManagementAuthorizationService } from './services/document-management-authorization.service.js';
|
|
5
6
|
export declare class DocumentManagementConfig {
|
|
6
7
|
ancillaryService: InjectionToken<DocumentManagementAncillaryService>;
|
|
8
|
+
authorizationService: InjectionToken<DocumentManagementAuthorizationService>;
|
|
7
9
|
fileObjectStorageModule: string;
|
|
8
10
|
fileUploadObjectStorageModule: string;
|
|
9
11
|
filePreviewObjectStorageModule: string;
|
|
10
12
|
database?: DatabaseConfig;
|
|
11
13
|
maxFileSize?: number;
|
|
12
14
|
}
|
|
13
|
-
export declare function configureDocumentManagement(config: DocumentManagementConfig): void;
|
|
14
15
|
export declare function migrateDocumentManagementSchema(): Promise<void>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import './schemas.js';
|
|
2
|
-
import { inject
|
|
2
|
+
import { inject } from '../../injector/index.js';
|
|
3
3
|
import { Database, migrate } from '../../orm/server/database.js';
|
|
4
|
-
import { DocumentManagementAncillaryService } from './services/document-management-ancillary.service.js';
|
|
5
4
|
export class DocumentManagementConfig {
|
|
6
5
|
ancillaryService;
|
|
6
|
+
authorizationService;
|
|
7
7
|
fileObjectStorageModule;
|
|
8
8
|
fileUploadObjectStorageModule;
|
|
9
9
|
filePreviewObjectStorageModule;
|
|
@@ -11,10 +11,6 @@ export class DocumentManagementConfig {
|
|
|
11
11
|
maxFileSize;
|
|
12
12
|
}
|
|
13
13
|
;
|
|
14
|
-
export function configureDocumentManagement(config) {
|
|
15
|
-
Injector.register(DocumentManagementConfig, { useValue: config });
|
|
16
|
-
Injector.register(DocumentManagementAncillaryService, { useToken: config.ancillaryService });
|
|
17
|
-
}
|
|
18
14
|
export async function migrateDocumentManagementSchema() {
|
|
19
15
|
const connection = inject(DocumentManagementConfig, undefined, { optional: true })?.database?.connection;
|
|
20
16
|
const database = inject(Database, connection);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Transactional } from '../../../orm/server/index.js';
|
|
2
2
|
import { DocumentCategory, DocumentType } from '../../models/index.js';
|
|
3
3
|
import type { DocumentCategoryView } from '../../service-models/index.js';
|
|
4
|
-
export declare const enumTypeKey = "enum-type";
|
|
5
4
|
export declare class DocumentCategoryTypeService extends Transactional {
|
|
6
5
|
#private;
|
|
7
6
|
readonly categoryRepository: import("../../../orm/server/repository.js").EntityRepository<DocumentCategory>;
|
|
@@ -13,29 +13,29 @@ import { injectRepository } from '../../../orm/server/repository.js';
|
|
|
13
13
|
import { groupToMap } from '../../../utils/iterable-helpers/group-to-map.js';
|
|
14
14
|
import { isUndefined } from '../../../utils/type-guards.js';
|
|
15
15
|
import { DocumentCategory, DocumentType } from '../../models/index.js';
|
|
16
|
+
import { enumTypeKey } from './enum-type-key.js';
|
|
16
17
|
import { DocumentManagementSingleton } from './singleton.js';
|
|
17
|
-
export const enumTypeKey = 'enum-type';
|
|
18
18
|
let DocumentCategoryTypeService = DocumentCategoryTypeService_1 = class DocumentCategoryTypeService extends Transactional {
|
|
19
19
|
#logger = inject(Logger, DocumentCategoryTypeService_1.name);
|
|
20
20
|
categoryRepository = injectRepository(DocumentCategory);
|
|
21
21
|
typeRepository = injectRepository(DocumentType);
|
|
22
22
|
async loadCategory(id) {
|
|
23
|
-
return this.categoryRepository.load(id);
|
|
23
|
+
return await this.categoryRepository.load(id);
|
|
24
24
|
}
|
|
25
25
|
async loadType(id) {
|
|
26
|
-
return this.typeRepository.load(id);
|
|
26
|
+
return await this.typeRepository.load(id);
|
|
27
27
|
}
|
|
28
28
|
async createCategory(label, parentId, enumKey) {
|
|
29
|
-
return this.categoryRepository.insert({ label, parentId, metadata: { attributes: { [enumTypeKey]: enumKey } } });
|
|
29
|
+
return await this.categoryRepository.insert({ label, parentId, metadata: { attributes: { [enumTypeKey]: enumKey } } });
|
|
30
30
|
}
|
|
31
31
|
async createType(label, categoryId, enumKey) {
|
|
32
|
-
return this.typeRepository.insert({ label, categoryId, metadata: { attributes: { [enumTypeKey]: enumKey } } });
|
|
32
|
+
return await this.typeRepository.insert({ label, categoryId, metadata: { attributes: { [enumTypeKey]: enumKey } } });
|
|
33
33
|
}
|
|
34
34
|
async updateCategory(id, update) {
|
|
35
|
-
return this.categoryRepository.update(id, update);
|
|
35
|
+
return await this.categoryRepository.update(id, update);
|
|
36
36
|
}
|
|
37
37
|
async updateType(id, update) {
|
|
38
|
-
return this.typeRepository.update(id, update);
|
|
38
|
+
return await this.typeRepository.update(id, update);
|
|
39
39
|
}
|
|
40
40
|
async loadCategoryGraph(categoryId) {
|
|
41
41
|
const category = await this.categoryRepository.load(categoryId);
|
|
@@ -63,7 +63,7 @@ import { match } from 'ts-pattern';
|
|
|
63
63
|
import { AiService } from '../../../ai/ai.service.js';
|
|
64
64
|
import { ForbiddenError } from '../../../errors/forbidden.error.js';
|
|
65
65
|
import { NotImplementedError } from '../../../errors/not-implemented.error.js';
|
|
66
|
-
import { getMimeType, getMimeTypeExtensions } from '../../../file/index.js';
|
|
66
|
+
import { getMimeType, getMimeTypeExtensions, mimeTypes } from '../../../file/index.js';
|
|
67
67
|
import { TemporaryFile } from '../../../file/server/index.js';
|
|
68
68
|
import { inject } from '../../../injector/inject.js';
|
|
69
69
|
import { Logger } from '../../../logger/logger.js';
|
|
@@ -122,7 +122,7 @@ let DocumentFileService = DocumentFileService_1 = class DocumentFileService exte
|
|
|
122
122
|
? await this.#fileUploadObjectStorage.getContent(content.uploadId)
|
|
123
123
|
: (isUint8Array(content) ? content : await readBinaryStream(content));
|
|
124
124
|
const hash = await digest('SHA-256', contentAsUint8Array).toHex();
|
|
125
|
-
const mimeType = await getMimeType(contentAsUint8Array);
|
|
125
|
+
const mimeType = await getMimeType(contentAsUint8Array, 'application/octet-stream');
|
|
126
126
|
const metadata = {
|
|
127
127
|
mimeType,
|
|
128
128
|
size: contentAsUint8Array.length,
|
|
@@ -188,6 +188,7 @@ let DocumentManagementAiService = DocumentManagementAiService_1 = class Document
|
|
|
188
188
|
{
|
|
189
189
|
text: `Extrahiere den Inhalt des Dokuments in das angegebenen JSON Schema.
|
|
190
190
|
|
|
191
|
+
Vermeide es, den Titel im Untertitel zu wiederholen.
|
|
191
192
|
Gib in der summary ausführlich an, welche Informationen in dem Dokument vorkommen (ohne konkrete Werte).
|
|
192
193
|
Erstelle bis zu 7 möglichst spezifische Tags.
|
|
193
194
|
Antworte auf deutsch.`,
|
|
@@ -346,5 +347,8 @@ DocumentManagementAiService = DocumentManagementAiService_1 = __decorate([
|
|
|
346
347
|
], DocumentManagementAiService);
|
|
347
348
|
export { DocumentManagementAiService };
|
|
348
349
|
function getDescriptiveTypeLabels(categories, prefix = 'Category: ') {
|
|
349
|
-
return categories.flatMap((category) => [
|
|
350
|
+
return categories.flatMap((category) => [
|
|
351
|
+
...category.types.map((type) => ({ id: type.id, label: `${prefix}${category.label} | Type: ${type.label}` })),
|
|
352
|
+
...getDescriptiveTypeLabels(category.children, `${prefix}${category.label} -> `),
|
|
353
|
+
]);
|
|
350
354
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DocumentCollection
|
|
1
|
+
import { DocumentCollection } from '../../models/index.js';
|
|
2
2
|
export type DocumentCollectionMetadata = {
|
|
3
3
|
/**
|
|
4
4
|
* User-friendly name of the collection
|
|
@@ -13,97 +13,16 @@ export type DocumentCollectionMetadata = {
|
|
|
13
13
|
*/
|
|
14
14
|
group: string | null;
|
|
15
15
|
};
|
|
16
|
-
export declare abstract class DocumentManagementAncillaryService
|
|
16
|
+
export declare abstract class DocumentManagementAncillaryService {
|
|
17
17
|
#private;
|
|
18
18
|
resolveMetadata<const T extends (DocumentCollection | string)[]>(...collectionsOrIds: T): Promise<{
|
|
19
19
|
[K in keyof T]: DocumentCollectionMetadata;
|
|
20
20
|
}>;
|
|
21
21
|
resolveMetadataMap(...collectionsOrIds: (DocumentCollection | string)[]): Promise<Record<string, DocumentCollectionMetadata>>;
|
|
22
|
-
canReadDocument(documentId: string, token?: Token): Promise<boolean>;
|
|
23
|
-
canManageRequest(requestId: string, token?: Token): Promise<boolean>;
|
|
24
22
|
/**
|
|
25
23
|
* Resolves application-specific metadata for a list of document collections.
|
|
26
24
|
* @param collections An array of DocumentCollection entities.
|
|
27
25
|
* @returns A promise that resolves to an array of DocumentCollectionMetadata, corresponding to the input collections.
|
|
28
26
|
*/
|
|
29
27
|
abstract _resolveMetadata(collections: DocumentCollection[]): DocumentCollectionMetadata[] | Promise<DocumentCollectionMetadata[]>;
|
|
30
|
-
/**
|
|
31
|
-
* Gets the subject from the request token.
|
|
32
|
-
* @param token The token of the request
|
|
33
|
-
*/
|
|
34
|
-
abstract getSubject(token?: Token): string | Promise<string>;
|
|
35
|
-
/**
|
|
36
|
-
* Checks if a user can read/view a specific document collection and its documents.
|
|
37
|
-
* @param collectionId The ID of the document collection.
|
|
38
|
-
* @param token The token of the request
|
|
39
|
-
*/
|
|
40
|
-
abstract canReadCollection(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
41
|
-
/**
|
|
42
|
-
* Checks if a user can create new *unassigned* documents (lands in "inbox", which then require assigning to request/collection) in a specific collection.
|
|
43
|
-
* @param collectionId The ID of the document collection.
|
|
44
|
-
* @param token The token of the request.
|
|
45
|
-
*/
|
|
46
|
-
abstract canCreateDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
47
|
-
abstract canUpdateDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
48
|
-
abstract canDeleteDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
49
|
-
/**
|
|
50
|
-
* Checks if a user can assign documents to requests in the collection or directly to the collection.
|
|
51
|
-
* @param collectionId The ID of the document collection.
|
|
52
|
-
* @param token The token of the request.
|
|
53
|
-
*/
|
|
54
|
-
abstract canAssignDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
55
|
-
/**
|
|
56
|
-
* Checks if a user can approve a specific document. This implicitly allows fulfilling document requests by approving their linked document.
|
|
57
|
-
* This is usually a privileged action for staff members.
|
|
58
|
-
* @param documentId The ID of the document.
|
|
59
|
-
* @param token The token of the request
|
|
60
|
-
* @returns A promise that resolves to true if approval is allowed, false otherwise.
|
|
61
|
-
*/
|
|
62
|
-
abstract canApproveDocument(documentId: string, token?: Token): boolean | Promise<boolean>;
|
|
63
|
-
/**
|
|
64
|
-
* Checks if a user can reject a specific document.
|
|
65
|
-
* This is usually a privileged action for staff members, often an alternative to approval.
|
|
66
|
-
* @param documentId The ID of the document.
|
|
67
|
-
* @param token The token of the request.
|
|
68
|
-
* @returns A promise that resolves to true if rejection is allowed, false otherwise.
|
|
69
|
-
*/
|
|
70
|
-
abstract canRejectDocument(documentId: string, token?: Token): boolean | Promise<boolean>;
|
|
71
|
-
/**
|
|
72
|
-
* Checks if a user can create, update, delete requests and assign documents to them in a collection.
|
|
73
|
-
* @param collectionId The ID of the document collection.
|
|
74
|
-
* @param token The token of the request
|
|
75
|
-
*/
|
|
76
|
-
abstract canManageRequests(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
77
|
-
/**
|
|
78
|
-
* Checks if a user can manage document categories, types and their properties (create, update, delete).
|
|
79
|
-
* Typically an administrator function.
|
|
80
|
-
* @param token The token of the request.
|
|
81
|
-
*/
|
|
82
|
-
abstract canManageCategoriesAndTypes(token?: Token): boolean | Promise<boolean>;
|
|
83
|
-
/**
|
|
84
|
-
* Checks if a user can read document request templates.
|
|
85
|
-
* @param token The token of the request.
|
|
86
|
-
*/
|
|
87
|
-
abstract canReadDocumentRequestsTemplates(token?: Token): boolean | Promise<boolean>;
|
|
88
|
-
/**
|
|
89
|
-
* Checks if a user can manage document request templates (create, update, delete).
|
|
90
|
-
* Typically an administrator function.
|
|
91
|
-
* @param token The token of the request.
|
|
92
|
-
*/
|
|
93
|
-
abstract canManageDocumentRequestsTemplates(token?: Token): boolean | Promise<boolean>;
|
|
94
|
-
/**
|
|
95
|
-
* Checks if a user can manage document validation definitions and their assignment to types.
|
|
96
|
-
* Typically an administrator function.
|
|
97
|
-
* @param token The token of the request.
|
|
98
|
-
*/
|
|
99
|
-
abstract canManageValidationDefinitions(token?: Token): boolean | Promise<boolean>;
|
|
100
|
-
/**
|
|
101
|
-
* Checks if a user can progress a document through its workflow.
|
|
102
|
-
* This implies reviewing the current step's output, making corrections if necessary,
|
|
103
|
-
* and then confirming to proceed to the next phase or finalization.
|
|
104
|
-
* @param documentId The ID of the document.
|
|
105
|
-
* @param currentWorkflowStep The current step of the workflow the user is interacting with.
|
|
106
|
-
* @param token The token of the request.
|
|
107
|
-
*/
|
|
108
|
-
abstract canProgressDocumentWorkflow(documentId: string, currentWorkflowStep: DocumentWorkflowStep, token?: Token): boolean | Promise<boolean>;
|
|
109
28
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { injectRepository } from '../../../orm/server/index.js';
|
|
2
2
|
import { fromEntries } from '../../../utils/object/index.js';
|
|
3
3
|
import { assertDefinedPass, isString } from '../../../utils/type-guards.js';
|
|
4
|
-
import { DocumentCollection
|
|
4
|
+
import { DocumentCollection } from '../../models/index.js';
|
|
5
5
|
export class DocumentManagementAncillaryService {
|
|
6
6
|
#documentCollectionRepository = injectRepository(DocumentCollection);
|
|
7
|
-
#documentCollectionAssignmentRepository = injectRepository(DocumentCollectionAssignment);
|
|
8
|
-
#documentRequestCollectionAssignmentRepository = injectRepository(DocumentRequestCollectionAssignment);
|
|
9
7
|
async resolveMetadata(...collectionsOrIds) {
|
|
10
8
|
if (collectionsOrIds.length == 0) {
|
|
11
9
|
return [];
|
|
@@ -25,24 +23,4 @@ export class DocumentManagementAncillaryService {
|
|
|
25
23
|
const entries = collectionsOrIds.map((collectionOrId, index) => [isString(collectionOrId) ? collectionOrId : collectionOrId.id, names[index]]);
|
|
26
24
|
return fromEntries(entries);
|
|
27
25
|
}
|
|
28
|
-
async canReadDocument(documentId, token) {
|
|
29
|
-
const assignments = await this.#documentCollectionAssignmentRepository.loadManyByQuery({ documentId });
|
|
30
|
-
for (const assignment of assignments) {
|
|
31
|
-
const canReadCollection = await this.canReadCollection(assignment.collectionId, token);
|
|
32
|
-
if (canReadCollection) {
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
async canManageRequest(requestId, token) {
|
|
39
|
-
const assignments = await this.#documentRequestCollectionAssignmentRepository.loadManyByQuery({ requestId });
|
|
40
|
-
for (const assignment of assignments) {
|
|
41
|
-
const canManageRequest = await this.canManageRequests(assignment.collectionId, token);
|
|
42
|
-
if (!canManageRequest) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
26
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { type DocumentWorkflowStep } from '../../models/index.js';
|
|
2
|
+
export declare abstract class DocumentManagementAuthorizationService<Token = unknown> {
|
|
3
|
+
#private;
|
|
4
|
+
canReadDocument(documentId: string, token?: Token): Promise<boolean>;
|
|
5
|
+
canManageRequest(requestId: string, token?: Token): Promise<boolean>;
|
|
6
|
+
/**
|
|
7
|
+
* Gets the subject from the request token.
|
|
8
|
+
* @param token The token of the request
|
|
9
|
+
*/
|
|
10
|
+
abstract getSubject(token?: Token): string | Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a user can read/view a specific document collection and its documents.
|
|
13
|
+
* @param collectionId The ID of the document collection.
|
|
14
|
+
* @param token The token of the request
|
|
15
|
+
*/
|
|
16
|
+
abstract canReadCollection(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* Checks if a user can create new *unassigned* documents (lands in "inbox", which then require assigning to request/collection) in a specific collection.
|
|
19
|
+
* @param collectionId The ID of the document collection.
|
|
20
|
+
* @param token The token of the request.
|
|
21
|
+
*/
|
|
22
|
+
abstract canCreateDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
23
|
+
abstract canUpdateDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
24
|
+
abstract canDeleteDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if a user can assign documents to requests in the collection or directly to the collection.
|
|
27
|
+
* @param collectionId The ID of the document collection.
|
|
28
|
+
* @param token The token of the request.
|
|
29
|
+
*/
|
|
30
|
+
abstract canAssignDocuments(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a user can approve a specific document. This implicitly allows fulfilling document requests by approving their linked document.
|
|
33
|
+
* This is usually a privileged action for staff members.
|
|
34
|
+
* @param documentId The ID of the document.
|
|
35
|
+
* @param token The token of the request
|
|
36
|
+
* @returns A promise that resolves to true if approval is allowed, false otherwise.
|
|
37
|
+
*/
|
|
38
|
+
abstract canApproveDocument(documentId: string, token?: Token): boolean | Promise<boolean>;
|
|
39
|
+
/**
|
|
40
|
+
* Checks if a user can reject a specific document.
|
|
41
|
+
* This is usually a privileged action for staff members, often an alternative to approval.
|
|
42
|
+
* @param documentId The ID of the document.
|
|
43
|
+
* @param token The token of the request.
|
|
44
|
+
* @returns A promise that resolves to true if rejection is allowed, false otherwise.
|
|
45
|
+
*/
|
|
46
|
+
abstract canRejectDocument(documentId: string, token?: Token): boolean | Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Checks if a user can create, update, delete requests and assign documents to them in a collection.
|
|
49
|
+
* @param collectionId The ID of the document collection.
|
|
50
|
+
* @param token The token of the request
|
|
51
|
+
*/
|
|
52
|
+
abstract canManageRequests(collectionId: string, token?: Token): boolean | Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a user can manage document categories, types and their properties (create, update, delete).
|
|
55
|
+
* Typically an administrator function.
|
|
56
|
+
* @param token The token of the request.
|
|
57
|
+
*/
|
|
58
|
+
abstract canManageCategoriesAndTypes(token?: Token): boolean | Promise<boolean>;
|
|
59
|
+
/**
|
|
60
|
+
* Checks if a user can read document request templates.
|
|
61
|
+
* @param token The token of the request.
|
|
62
|
+
*/
|
|
63
|
+
abstract canReadDocumentRequestsTemplates(token?: Token): boolean | Promise<boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* Checks if a user can manage document request templates (create, update, delete).
|
|
66
|
+
* Typically an administrator function.
|
|
67
|
+
* @param token The token of the request.
|
|
68
|
+
*/
|
|
69
|
+
abstract canManageDocumentRequestsTemplates(token?: Token): boolean | Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* Checks if a user can manage document validation definitions and their assignment to types.
|
|
72
|
+
* Typically an administrator function.
|
|
73
|
+
* @param token The token of the request.
|
|
74
|
+
*/
|
|
75
|
+
abstract canManageValidationDefinitions(token?: Token): boolean | Promise<boolean>;
|
|
76
|
+
/**
|
|
77
|
+
* Checks if a user can progress a document through its workflow.
|
|
78
|
+
* This implies reviewing the current step's output, making corrections if necessary,
|
|
79
|
+
* and then confirming to proceed to the next phase or finalization.
|
|
80
|
+
* @param documentId The ID of the document.
|
|
81
|
+
* @param currentWorkflowStep The current step of the workflow the user is interacting with.
|
|
82
|
+
* @param token The token of the request.
|
|
83
|
+
*/
|
|
84
|
+
abstract canProgressDocumentWorkflow(documentId: string, currentWorkflowStep: DocumentWorkflowStep, token?: Token): boolean | Promise<boolean>;
|
|
85
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { inject } from '../../../injector/inject.js';
|
|
2
|
+
import { injectRepository } from '../../../orm/server/index.js';
|
|
3
|
+
import { DocumentRequestCollectionAssignment } from '../../models/index.js';
|
|
4
|
+
import { DocumentManagementService } from './document-management.service.js';
|
|
5
|
+
export class DocumentManagementAuthorizationService {
|
|
6
|
+
#documentManagementService = inject(DocumentManagementService);
|
|
7
|
+
#documentRequestCollectionAssignmentRepository = injectRepository(DocumentRequestCollectionAssignment);
|
|
8
|
+
async canReadDocument(documentId, token) {
|
|
9
|
+
const relevantCollectionIds = await this.#documentManagementService.getRelevantDocumentCollectionIds(documentId);
|
|
10
|
+
for (const collectionId of relevantCollectionIds) {
|
|
11
|
+
const canReadCollection = await this.canReadCollection(collectionId, token);
|
|
12
|
+
if (canReadCollection) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
async canManageRequest(requestId, token) {
|
|
19
|
+
const assignments = await this.#documentRequestCollectionAssignmentRepository.loadManyByQuery({ requestId });
|
|
20
|
+
for (const assignment of assignments) {
|
|
21
|
+
const canManageRequest = await this.canManageRequests(assignment.collectionId, token);
|
|
22
|
+
if (!canManageRequest) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import { Transactional } from '../../../orm/server/index.js';
|
|
2
2
|
import type { Record } from '../../../types.js';
|
|
3
|
-
import { DocumentCategory, DocumentType } from '../../models/index.js';
|
|
3
|
+
import { DocumentCategory, DocumentType, type DocumentProperty, type DocumentPropertyDataType } from '../../models/index.js';
|
|
4
4
|
import type { DocumentManagementData, DocumentRequestsTemplateData } from '../../service-models/index.js';
|
|
5
5
|
export declare class DocumentManagementService extends Transactional {
|
|
6
6
|
#private;
|
|
7
|
+
/**
|
|
8
|
+
* Get all relevant document collection IDs for a given document. This includes direct assignments, request assignments, and assignment scopes.
|
|
9
|
+
* This method is used to determine which collections a document is associated with, either directly or through requests and assignments.
|
|
10
|
+
* @param documentId The ID of the document to retrieve collection IDs for.
|
|
11
|
+
*/
|
|
12
|
+
getRelevantDocumentCollectionIds(documentId: string): Promise<string[]>;
|
|
13
|
+
loadDataStream(collectionIds: string[]): ReadableStream<DocumentManagementData>;
|
|
7
14
|
loadData(collectionIds: string[]): Promise<DocumentManagementData>;
|
|
8
15
|
loadDocumentRequestsTemplateData(): Promise<DocumentRequestsTemplateData>;
|
|
9
|
-
initializeCategoriesAndTypes<CategoryKey extends string, TypeKey extends string>(categoryLabels: Record<CategoryKey, string>, categoryParents: Record<CategoryKey, CategoryKey | null>, typeLabels: Record<TypeKey, string>, typeCategories: Record<TypeKey, CategoryKey>): Promise<{
|
|
16
|
+
initializeCategoriesAndTypes<CategoryKey extends string, TypeKey extends string, DocumentPropertyKey extends string>(categoryLabels: Record<CategoryKey, string>, categoryParents: Record<CategoryKey, CategoryKey | null>, typeLabels: Record<TypeKey, string>, typeCategories: Record<TypeKey, CategoryKey>, propertyKeys: Record<DocumentPropertyKey, [DocumentPropertyDataType, string]>, typeProperties: Record<TypeKey, DocumentPropertyKey[]>): Promise<{
|
|
10
17
|
categories: Record<CategoryKey, DocumentCategory>;
|
|
11
18
|
types: Record<TypeKey, DocumentType>;
|
|
19
|
+
properties: Record<DocumentPropertyKey, DocumentProperty>;
|
|
12
20
|
}>;
|
|
13
21
|
}
|
|
@@ -4,6 +4,8 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
+
import { eq } from 'drizzle-orm';
|
|
8
|
+
import { union } from 'drizzle-orm/pg-core';
|
|
7
9
|
import { Enumerable } from '../../../enumerable/index.js';
|
|
8
10
|
import { inject } from '../../../injector/index.js';
|
|
9
11
|
import { Transactional, injectRepository } from '../../../orm/server/index.js';
|
|
@@ -11,13 +13,16 @@ import { distinct } from '../../../utils/array/index.js';
|
|
|
11
13
|
import { compareByValueSelectionToOrder } from '../../../utils/comparison.js';
|
|
12
14
|
import { groupToMap, groupToSingleMap } from '../../../utils/iterable-helpers/index.js';
|
|
13
15
|
import { fromEntries, objectEntries } from '../../../utils/object/index.js';
|
|
16
|
+
import { timeout } from '../../../utils/timing.js';
|
|
14
17
|
import { assertDefinedPass, isDefined, isNotNull, isNotNullOrUndefined, isNull, isUndefined } from '../../../utils/type-guards.js';
|
|
15
|
-
import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
|
|
16
|
-
import {
|
|
18
|
+
import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentTypeProperty, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
|
|
19
|
+
import { documentAssignmentScope, documentAssignmentTask, documentCollectionAssignment, documentRequest, documentRequestCollectionAssignment } from '../schemas.js';
|
|
20
|
+
import { DocumentCategoryTypeService } from './document-category-type.service.js';
|
|
17
21
|
import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
|
|
18
22
|
import { DocumentPropertyService } from './document-property.service.js';
|
|
19
23
|
import { DocumentWorkflowService } from './document-workflow.service.js';
|
|
20
24
|
import { DocumentService } from './document.service.js';
|
|
25
|
+
import { enumTypeKey } from './enum-type-key.js';
|
|
21
26
|
import { DocumentManagementSingleton } from './singleton.js';
|
|
22
27
|
let DocumentManagementService = class DocumentManagementService extends Transactional {
|
|
23
28
|
#ancillaryService = inject(DocumentManagementAncillaryService);
|
|
@@ -34,8 +39,41 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
34
39
|
#documentRequestsTemplateRepository = injectRepository(DocumentRequestsTemplate);
|
|
35
40
|
#documentRequestTemplateRepository = injectRepository(DocumentRequestTemplate);
|
|
36
41
|
#documentTypeRepository = injectRepository(DocumentType);
|
|
42
|
+
#documentTypePropertyRepository = injectRepository(DocumentTypeProperty);
|
|
37
43
|
#documentWorkflowService = inject(DocumentWorkflowService);
|
|
38
44
|
#documentValidationExecutionRepository = injectRepository(DocumentValidationExecution);
|
|
45
|
+
/**
|
|
46
|
+
* Get all relevant document collection IDs for a given document. This includes direct assignments, request assignments, and assignment scopes.
|
|
47
|
+
* This method is used to determine which collections a document is associated with, either directly or through requests and assignments.
|
|
48
|
+
* @param documentId The ID of the document to retrieve collection IDs for.
|
|
49
|
+
*/
|
|
50
|
+
async getRelevantDocumentCollectionIds(documentId) {
|
|
51
|
+
const directAssignments = this.#documentCollectionRepository.session.$with('directAssignments').as((qb) => qb
|
|
52
|
+
.select({ collectionId: documentCollectionAssignment.id })
|
|
53
|
+
.from(documentCollectionAssignment)
|
|
54
|
+
.where(eq(documentCollectionAssignment.documentId, documentId)));
|
|
55
|
+
const requestAssignments = this.#documentRequestCollectionAssignmentRepository.session.$with('requestAssignments').as((qb) => qb
|
|
56
|
+
.select({ collectionId: documentRequestCollectionAssignment.collectionId })
|
|
57
|
+
.from(documentRequest)
|
|
58
|
+
.innerJoin(documentRequestCollectionAssignment, eq(documentRequestCollectionAssignment.requestId, documentRequest.id))
|
|
59
|
+
.where(eq(documentRequest.documentId, documentId)));
|
|
60
|
+
const assignmentScopes = this.#documentAssignmentScopeRepository.session.$with('assignmentScopes').as((qb) => qb
|
|
61
|
+
.select({ collectionId: documentAssignmentScope.collectionId })
|
|
62
|
+
.from(documentAssignmentTask)
|
|
63
|
+
.innerJoin(documentAssignmentScope, eq(documentAssignmentScope.taskId, documentAssignmentTask.id))
|
|
64
|
+
.where(eq(documentAssignmentTask.documentId, documentId)));
|
|
65
|
+
const result = await union(this.#documentService.session.with(directAssignments).selectDistinct().from(directAssignments), this.#documentService.session.with(requestAssignments).selectDistinct().from(requestAssignments), this.#documentService.session.with(assignmentScopes).selectDistinct().from(assignmentScopes));
|
|
66
|
+
return result.map((row) => row.collectionId);
|
|
67
|
+
}
|
|
68
|
+
loadDataStream(collectionIds) {
|
|
69
|
+
return new ReadableStream({
|
|
70
|
+
pull: async (controller) => {
|
|
71
|
+
const data = await this.loadData(collectionIds);
|
|
72
|
+
controller.enqueue(data);
|
|
73
|
+
await timeout(1000);
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
39
77
|
async loadData(collectionIds) {
|
|
40
78
|
return await this.transaction(async (tx) => {
|
|
41
79
|
const [collections, collectionsMetadataMap, documentCollectionAssignments, requestAssignments, assignmentScopes, categories, types] = await Promise.all([
|
|
@@ -96,7 +134,7 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
96
134
|
});
|
|
97
135
|
const requestViews = requests.map((request) => ({
|
|
98
136
|
...request,
|
|
99
|
-
collectionIds: requestAssignments.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId)
|
|
137
|
+
collectionIds: requestAssignments.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId),
|
|
100
138
|
}));
|
|
101
139
|
return {
|
|
102
140
|
collections: collectionViews,
|
|
@@ -120,15 +158,19 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
120
158
|
return { templates };
|
|
121
159
|
});
|
|
122
160
|
}
|
|
123
|
-
async initializeCategoriesAndTypes(categoryLabels, categoryParents, typeLabels, typeCategories) {
|
|
161
|
+
async initializeCategoriesAndTypes(categoryLabels, categoryParents, typeLabels, typeCategories, propertyKeys, typeProperties) {
|
|
124
162
|
const categoryEntries = objectEntries(categoryLabels);
|
|
125
163
|
const typeEntries = objectEntries(typeLabels);
|
|
126
|
-
const
|
|
164
|
+
const propertyEntries = objectEntries(propertyKeys);
|
|
165
|
+
const { categoryMap, typeMap, propertyMap } = await this.transaction(async (tx) => {
|
|
127
166
|
const { categories: dbCategories, types: dbTypes } = await this.#documentCategoryTypeService.withTransaction(tx).loadCategoriesAndTypes();
|
|
167
|
+
const dbProperties = await this.#documentPropertyService.withTransaction(tx).repository.loadAll();
|
|
128
168
|
const categories = dbCategories.filter((category) => isNotNullOrUndefined(category.metadata.attributes[enumTypeKey]));
|
|
129
169
|
const types = dbTypes.filter((type) => isNotNullOrUndefined(type.metadata.attributes[enumTypeKey]));
|
|
170
|
+
const properties = dbProperties.filter((property) => isNotNullOrUndefined(property.metadata.attributes[enumTypeKey]));
|
|
130
171
|
const enumKeyCategoryMap = groupToSingleMap(categories, (category) => category.metadata.attributes[enumTypeKey]);
|
|
131
172
|
const enumKeyTypeMap = groupToSingleMap(types, (type) => type.metadata.attributes[enumTypeKey]);
|
|
173
|
+
const enumKeyPropertyMap = groupToSingleMap(properties, (property) => property.metadata.attributes[enumTypeKey]);
|
|
132
174
|
for (const [key, label] of categoryEntries) {
|
|
133
175
|
const category = enumKeyCategoryMap.get(key);
|
|
134
176
|
const parentKey = assertDefinedPass(categoryParents[key], `Parent category not defined for ${key}`);
|
|
@@ -156,13 +198,34 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
156
198
|
enumKeyTypeMap.set(key, updatedType);
|
|
157
199
|
}
|
|
158
200
|
}
|
|
159
|
-
|
|
201
|
+
for (const [key, [dataType, label]] of propertyEntries) {
|
|
202
|
+
const property = enumKeyPropertyMap.get(key);
|
|
203
|
+
if (isUndefined(property)) {
|
|
204
|
+
const newProperty = await this.#documentPropertyService.withTransaction(tx).createProperty(label, dataType, key);
|
|
205
|
+
enumKeyPropertyMap.set(key, newProperty);
|
|
206
|
+
}
|
|
207
|
+
else if ((property.label != label) || (property.dataType != dataType)) {
|
|
208
|
+
const updatedProperty = await this.#documentPropertyService.withTransaction(tx).updateProperty(property.id, { label, dataType });
|
|
209
|
+
enumKeyPropertyMap.set(key, updatedProperty);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const [typeKey, propertyKeys] of objectEntries(typeProperties)) {
|
|
213
|
+
const type = assertDefinedPass(enumKeyTypeMap.get(typeKey), `Type ${typeKey} not found.`);
|
|
214
|
+
const newEntities = propertyKeys.map((propertyKey) => ({
|
|
215
|
+
typeId: type.id,
|
|
216
|
+
propertyId: assertDefinedPass(enumKeyPropertyMap.get(propertyKey), 'Could not get property').id,
|
|
217
|
+
}));
|
|
218
|
+
await this.#documentTypePropertyRepository.withTransaction(tx).upsertMany(['typeId', 'propertyId'], newEntities);
|
|
219
|
+
}
|
|
220
|
+
return { categoryMap: enumKeyCategoryMap, typeMap: enumKeyTypeMap, propertyMap: enumKeyPropertyMap };
|
|
160
221
|
});
|
|
161
222
|
const mappedCategories = categoryEntries.map(([key]) => [key, assertDefinedPass(categoryMap.get(key), 'Could not map document category.')]);
|
|
162
223
|
const mappedTypes = typeEntries.map(([key]) => [key, assertDefinedPass(typeMap.get(key), 'Could not map document type.')]);
|
|
224
|
+
const mappedProperties = propertyEntries.map(([key]) => [key, assertDefinedPass(propertyMap.get(key), 'Could not map document property.')]);
|
|
163
225
|
return {
|
|
164
226
|
categories: fromEntries(mappedCategories),
|
|
165
227
|
types: fromEntries(mappedTypes),
|
|
228
|
+
properties: fromEntries(mappedProperties),
|
|
166
229
|
};
|
|
167
230
|
}
|
|
168
231
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Transactional } from '../../../orm/server/index.js';
|
|
2
2
|
import type { OneOrMany } from '../../../types.js';
|
|
3
|
-
import {
|
|
3
|
+
import { DocumentProperty, DocumentPropertyDataType } from '../../models/index.js';
|
|
4
4
|
import type { DocumentPropertyValueView, SetDocumentPropertyParameters } from '../../service-models/index.js';
|
|
5
5
|
export declare class DocumentPropertyService extends Transactional {
|
|
6
6
|
#private;
|
|
7
|
-
readonly repository: import("../../../orm/server/repository.js").EntityRepository<
|
|
7
|
+
readonly repository: import("../../../orm/server/repository.js").EntityRepository<DocumentProperty>;
|
|
8
8
|
readonly documentProperties: import("drizzle-orm/pg-core").WithSubqueryWithSelection<{
|
|
9
9
|
documentId: import("drizzle-orm").SQL.Aliased<string>;
|
|
10
10
|
propertyId: import("drizzle-orm").SQL.Aliased<string>;
|
|
@@ -44,7 +44,11 @@ export declare class DocumentPropertyService extends Transactional {
|
|
|
44
44
|
}, {}, {}>;
|
|
45
45
|
value: import("drizzle-orm").SQL.Aliased<string | number | boolean | null>;
|
|
46
46
|
}, "documentProperties">;
|
|
47
|
-
createProperty(label: string, dataType: DocumentPropertyDataType): Promise<DocumentProperty>;
|
|
47
|
+
createProperty(label: string, dataType: DocumentPropertyDataType, enumKey?: string): Promise<DocumentProperty>;
|
|
48
|
+
updateProperty(id: string, update: {
|
|
49
|
+
label?: string;
|
|
50
|
+
dataType?: DocumentPropertyDataType;
|
|
51
|
+
}): Promise<DocumentProperty>;
|
|
48
52
|
assignPropertyToType(typeId: string, propertyId: string): Promise<void>;
|
|
49
53
|
loadDocumentProperties(documentId: OneOrMany<string>, includeNulls?: boolean): Promise<DocumentPropertyValueView[]>;
|
|
50
54
|
setPropertyValues(documentId: string, propertyValues: SetDocumentPropertyParameters[]): Promise<void>;
|
|
@@ -11,8 +11,9 @@ import { Transactional } from '../../../orm/server/index.js';
|
|
|
11
11
|
import { injectRepository } from '../../../orm/server/repository.js';
|
|
12
12
|
import { toArray } from '../../../utils/array/index.js';
|
|
13
13
|
import { assertBooleanPass, assertDefinedPass, assertNumberPass, assertStringPass, isBoolean, isNotNull, isNull, isNumber, isString } from '../../../utils/type-guards.js';
|
|
14
|
-
import {
|
|
14
|
+
import { DocumentProperty, DocumentPropertyDataType, DocumentPropertyValue, DocumentTypeProperty } from '../../models/index.js';
|
|
15
15
|
import { document, documentProperty, documentPropertyValue, documentType, documentTypeProperty } from '../schemas.js';
|
|
16
|
+
import { enumTypeKey } from './enum-type-key.js';
|
|
16
17
|
import { DocumentManagementSingleton } from './singleton.js';
|
|
17
18
|
const documentPropertyValueValidators = {
|
|
18
19
|
[DocumentPropertyDataType.Text]: (value) => isString(value) || isNull(value),
|
|
@@ -25,7 +26,7 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
|
|
|
25
26
|
#documentPropertyRepository = injectRepository(DocumentProperty);
|
|
26
27
|
#documentPropertyValueRepository = injectRepository(DocumentPropertyValue);
|
|
27
28
|
#documentTypePropertyRepository = injectRepository(DocumentTypeProperty);
|
|
28
|
-
repository = injectRepository(
|
|
29
|
+
repository = injectRepository(DocumentProperty).withSession(this.session);
|
|
29
30
|
documentProperties = this.session.$with('documentProperties').as((qb) => qb
|
|
30
31
|
.select({
|
|
31
32
|
documentId: autoAlias(document.id),
|
|
@@ -39,8 +40,11 @@ let DocumentPropertyService = class DocumentPropertyService extends Transactiona
|
|
|
39
40
|
.innerJoin(documentTypeProperty, eq(documentTypeProperty.typeId, documentType.id))
|
|
40
41
|
.innerJoin(documentProperty, eq(documentProperty.id, documentTypeProperty.propertyId))
|
|
41
42
|
.leftJoin(documentPropertyValue, and(eq(documentPropertyValue.documentId, document.id), eq(documentPropertyValue.propertyId, documentProperty.id))));
|
|
42
|
-
async createProperty(label, dataType) {
|
|
43
|
-
return await this.#documentPropertyRepository.insert({ label, dataType });
|
|
43
|
+
async createProperty(label, dataType, enumKey) {
|
|
44
|
+
return await this.#documentPropertyRepository.insert({ label, dataType, metadata: { attributes: { [enumTypeKey]: enumKey } } });
|
|
45
|
+
}
|
|
46
|
+
async updateProperty(id, update) {
|
|
47
|
+
return await this.#documentPropertyRepository.update(id, update);
|
|
44
48
|
}
|
|
45
49
|
async assignPropertyToType(typeId, propertyId) {
|
|
46
50
|
await this.#documentTypePropertyRepository.insert({ typeId, propertyId });
|