@tstdl/base 0.92.137 → 0.92.139
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/document-management/api/document-management.api.d.ts +40 -0
- package/document-management/api/document-management.api.js +20 -0
- package/document-management/server/api/document-management.api.d.ts +2 -0
- package/document-management/server/api/document-management.api.js +34 -32
- 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 +9 -2
- package/document-management/server/services/document-management.service.js +59 -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/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 +27 -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/orm/sqls.d.ts +8 -2
- package/package.json +3 -2
- package/schema/converters/openapi-converter.js +15 -12
|
@@ -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,20 @@
|
|
|
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[]>;
|
|
7
13
|
loadData(collectionIds: string[]): Promise<DocumentManagementData>;
|
|
8
14
|
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<{
|
|
15
|
+
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
16
|
categories: Record<CategoryKey, DocumentCategory>;
|
|
11
17
|
types: Record<TypeKey, DocumentType>;
|
|
18
|
+
properties: Record<DocumentPropertyKey, DocumentProperty>;
|
|
12
19
|
}>;
|
|
13
20
|
}
|
|
@@ -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';
|
|
@@ -12,12 +14,14 @@ 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';
|
|
14
16
|
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 {
|
|
17
|
+
import { DocumentApproval, DocumentAssignmentScope, DocumentAssignmentTask, DocumentCategory, DocumentCollection, DocumentCollectionAssignment, DocumentRequest, DocumentRequestCollectionAssignment, DocumentRequestTemplate, DocumentRequestsTemplate, DocumentType, DocumentTypeProperty, DocumentValidationExecution, DocumentWorkflowStep } from '../../models/index.js';
|
|
18
|
+
import { documentAssignmentScope, documentAssignmentTask, documentCollectionAssignment, documentRequest, documentRequestCollectionAssignment } from '../schemas.js';
|
|
19
|
+
import { DocumentCategoryTypeService } from './document-category-type.service.js';
|
|
17
20
|
import { DocumentManagementAncillaryService } from './document-management-ancillary.service.js';
|
|
18
21
|
import { DocumentPropertyService } from './document-property.service.js';
|
|
19
22
|
import { DocumentWorkflowService } from './document-workflow.service.js';
|
|
20
23
|
import { DocumentService } from './document.service.js';
|
|
24
|
+
import { enumTypeKey } from './enum-type-key.js';
|
|
21
25
|
import { DocumentManagementSingleton } from './singleton.js';
|
|
22
26
|
let DocumentManagementService = class DocumentManagementService extends Transactional {
|
|
23
27
|
#ancillaryService = inject(DocumentManagementAncillaryService);
|
|
@@ -34,8 +38,32 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
34
38
|
#documentRequestsTemplateRepository = injectRepository(DocumentRequestsTemplate);
|
|
35
39
|
#documentRequestTemplateRepository = injectRepository(DocumentRequestTemplate);
|
|
36
40
|
#documentTypeRepository = injectRepository(DocumentType);
|
|
41
|
+
#documentTypePropertyRepository = injectRepository(DocumentTypeProperty);
|
|
37
42
|
#documentWorkflowService = inject(DocumentWorkflowService);
|
|
38
43
|
#documentValidationExecutionRepository = injectRepository(DocumentValidationExecution);
|
|
44
|
+
/**
|
|
45
|
+
* Get all relevant document collection IDs for a given document. This includes direct assignments, request assignments, and assignment scopes.
|
|
46
|
+
* This method is used to determine which collections a document is associated with, either directly or through requests and assignments.
|
|
47
|
+
* @param documentId The ID of the document to retrieve collection IDs for.
|
|
48
|
+
*/
|
|
49
|
+
async getRelevantDocumentCollectionIds(documentId) {
|
|
50
|
+
const directAssignments = this.#documentCollectionRepository.session.$with('directAssignments').as((qb) => qb
|
|
51
|
+
.select({ collectionId: documentCollectionAssignment.id })
|
|
52
|
+
.from(documentCollectionAssignment)
|
|
53
|
+
.where(eq(documentCollectionAssignment.documentId, documentId)));
|
|
54
|
+
const requestAssignments = this.#documentRequestCollectionAssignmentRepository.session.$with('requestAssignments').as((qb) => qb
|
|
55
|
+
.select({ collectionId: documentRequestCollectionAssignment.collectionId })
|
|
56
|
+
.from(documentRequest)
|
|
57
|
+
.innerJoin(documentRequestCollectionAssignment, eq(documentRequestCollectionAssignment.requestId, documentRequest.id))
|
|
58
|
+
.where(eq(documentRequest.documentId, documentId)));
|
|
59
|
+
const assignmentScopes = this.#documentAssignmentScopeRepository.session.$with('assignmentScopes').as((qb) => qb
|
|
60
|
+
.select({ collectionId: documentAssignmentScope.collectionId })
|
|
61
|
+
.from(documentAssignmentTask)
|
|
62
|
+
.innerJoin(documentAssignmentScope, eq(documentAssignmentScope.taskId, documentAssignmentTask.id))
|
|
63
|
+
.where(eq(documentAssignmentTask.documentId, documentId)));
|
|
64
|
+
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));
|
|
65
|
+
return result.map((row) => row.collectionId);
|
|
66
|
+
}
|
|
39
67
|
async loadData(collectionIds) {
|
|
40
68
|
return await this.transaction(async (tx) => {
|
|
41
69
|
const [collections, collectionsMetadataMap, documentCollectionAssignments, requestAssignments, assignmentScopes, categories, types] = await Promise.all([
|
|
@@ -96,7 +124,7 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
96
124
|
});
|
|
97
125
|
const requestViews = requests.map((request) => ({
|
|
98
126
|
...request,
|
|
99
|
-
collectionIds: requestAssignments.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId)
|
|
127
|
+
collectionIds: requestAssignments.filter((requestCollection) => requestCollection.requestId == request.id).map((requestCollection) => requestCollection.collectionId),
|
|
100
128
|
}));
|
|
101
129
|
return {
|
|
102
130
|
collections: collectionViews,
|
|
@@ -120,15 +148,19 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
120
148
|
return { templates };
|
|
121
149
|
});
|
|
122
150
|
}
|
|
123
|
-
async initializeCategoriesAndTypes(categoryLabels, categoryParents, typeLabels, typeCategories) {
|
|
151
|
+
async initializeCategoriesAndTypes(categoryLabels, categoryParents, typeLabels, typeCategories, propertyKeys, typeProperties) {
|
|
124
152
|
const categoryEntries = objectEntries(categoryLabels);
|
|
125
153
|
const typeEntries = objectEntries(typeLabels);
|
|
126
|
-
const
|
|
154
|
+
const propertyEntries = objectEntries(propertyKeys);
|
|
155
|
+
const { categoryMap, typeMap, propertyMap } = await this.transaction(async (tx) => {
|
|
127
156
|
const { categories: dbCategories, types: dbTypes } = await this.#documentCategoryTypeService.withTransaction(tx).loadCategoriesAndTypes();
|
|
157
|
+
const dbProperties = await this.#documentPropertyService.withTransaction(tx).repository.loadAll();
|
|
128
158
|
const categories = dbCategories.filter((category) => isNotNullOrUndefined(category.metadata.attributes[enumTypeKey]));
|
|
129
159
|
const types = dbTypes.filter((type) => isNotNullOrUndefined(type.metadata.attributes[enumTypeKey]));
|
|
160
|
+
const properties = dbProperties.filter((property) => isNotNullOrUndefined(property.metadata.attributes[enumTypeKey]));
|
|
130
161
|
const enumKeyCategoryMap = groupToSingleMap(categories, (category) => category.metadata.attributes[enumTypeKey]);
|
|
131
162
|
const enumKeyTypeMap = groupToSingleMap(types, (type) => type.metadata.attributes[enumTypeKey]);
|
|
163
|
+
const enumKeyPropertyMap = groupToSingleMap(properties, (property) => property.metadata.attributes[enumTypeKey]);
|
|
132
164
|
for (const [key, label] of categoryEntries) {
|
|
133
165
|
const category = enumKeyCategoryMap.get(key);
|
|
134
166
|
const parentKey = assertDefinedPass(categoryParents[key], `Parent category not defined for ${key}`);
|
|
@@ -156,13 +188,34 @@ let DocumentManagementService = class DocumentManagementService extends Transact
|
|
|
156
188
|
enumKeyTypeMap.set(key, updatedType);
|
|
157
189
|
}
|
|
158
190
|
}
|
|
159
|
-
|
|
191
|
+
for (const [key, [dataType, label]] of propertyEntries) {
|
|
192
|
+
const property = enumKeyPropertyMap.get(key);
|
|
193
|
+
if (isUndefined(property)) {
|
|
194
|
+
const newProperty = await this.#documentPropertyService.withTransaction(tx).createProperty(label, dataType, key);
|
|
195
|
+
enumKeyPropertyMap.set(key, newProperty);
|
|
196
|
+
}
|
|
197
|
+
else if ((property.label != label) || (property.dataType != dataType)) {
|
|
198
|
+
const updatedProperty = await this.#documentPropertyService.withTransaction(tx).updateProperty(property.id, { label, dataType });
|
|
199
|
+
enumKeyPropertyMap.set(key, updatedProperty);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const [typeKey, propertyKeys] of objectEntries(typeProperties)) {
|
|
203
|
+
const type = assertDefinedPass(enumKeyTypeMap.get(typeKey), `Type ${typeKey} not found.`);
|
|
204
|
+
const newEntities = propertyKeys.map((propertyKey) => ({
|
|
205
|
+
typeId: type.id,
|
|
206
|
+
propertyId: assertDefinedPass(enumKeyPropertyMap.get(propertyKey), 'Could not get property').id,
|
|
207
|
+
}));
|
|
208
|
+
await this.#documentTypePropertyRepository.withTransaction(tx).upsertMany(['typeId', 'propertyId'], newEntities);
|
|
209
|
+
}
|
|
210
|
+
return { categoryMap: enumKeyCategoryMap, typeMap: enumKeyTypeMap, propertyMap: enumKeyPropertyMap };
|
|
160
211
|
});
|
|
161
212
|
const mappedCategories = categoryEntries.map(([key]) => [key, assertDefinedPass(categoryMap.get(key), 'Could not map document category.')]);
|
|
162
213
|
const mappedTypes = typeEntries.map(([key]) => [key, assertDefinedPass(typeMap.get(key), 'Could not map document type.')]);
|
|
214
|
+
const mappedProperties = propertyEntries.map(([key]) => [key, assertDefinedPass(propertyMap.get(key), 'Could not map document property.')]);
|
|
163
215
|
return {
|
|
164
216
|
categories: fromEntries(mappedCategories),
|
|
165
217
|
types: fromEntries(mappedTypes),
|
|
218
|
+
properties: fromEntries(mappedProperties),
|
|
166
219
|
};
|
|
167
220
|
}
|
|
168
221
|
};
|
|
@@ -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 });
|
|
@@ -89,8 +89,8 @@ let DocumentWorkflowService = DocumentWorkflowService_1 = class DocumentWorkflow
|
|
|
89
89
|
await this.repository.update(id, { state, failReason });
|
|
90
90
|
}
|
|
91
91
|
async processWorkflowJob(job) {
|
|
92
|
-
this.#logger.verbose(`Processing workflow job for workflow "${job.data.workflowId}"`);
|
|
93
92
|
const workflow = await this.repository.load(job.data.workflowId);
|
|
93
|
+
this.#logger.verbose(`Processing workflow "${workflow.step}" for document "${workflow.documentId}"`);
|
|
94
94
|
try {
|
|
95
95
|
await this.setWorkflowState(workflow.id, DocumentWorkflowState.Running);
|
|
96
96
|
await match(workflow.step)
|
|
@@ -106,11 +106,11 @@ let DocumentWorkflowService = DocumentWorkflowService_1 = class DocumentWorkflow
|
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
catch (error) {
|
|
109
|
-
this.#logger.error(error);
|
|
110
109
|
const isLastTry = job.tries == this.#queue.maxTries;
|
|
111
110
|
if (isLastTry) {
|
|
112
111
|
await this.repository.update(workflow.id, { state: DocumentWorkflowState.Error });
|
|
113
112
|
}
|
|
113
|
+
throw error;
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
async processClassificationWorkflow(workflow) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const enumTypeKey = "enum-type";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const enumTypeKey = 'enum-type';
|
|
@@ -3,6 +3,7 @@ export * from './document-collection.service.js';
|
|
|
3
3
|
export * from './document-file.service.js';
|
|
4
4
|
export * from './document-management-ai.service.js';
|
|
5
5
|
export * from './document-management-ancillary.service.js';
|
|
6
|
+
export * from './document-management-authorization.service.js';
|
|
6
7
|
export * from './document-management.service.js';
|
|
7
8
|
export * from './document-property.service.js';
|
|
8
9
|
export * from './document-request.service.js';
|
|
@@ -3,6 +3,7 @@ export * from './document-collection.service.js';
|
|
|
3
3
|
export * from './document-file.service.js';
|
|
4
4
|
export * from './document-management-ai.service.js';
|
|
5
5
|
export * from './document-management-ancillary.service.js';
|
|
6
|
+
export * from './document-management-authorization.service.js';
|
|
6
7
|
export * from './document-management.service.js';
|
|
7
8
|
export * from './document-property.service.js';
|
|
8
9
|
export * from './document-request.service.js';
|
|
@@ -6,6 +6,7 @@ export declare class EnrichedDocumentCategory implements Pick<DocumentCategory,
|
|
|
6
6
|
readonly id: string;
|
|
7
7
|
readonly label: string;
|
|
8
8
|
readonly parent: EnrichedDocumentCategory | null;
|
|
9
|
+
get rootCategory(): EnrichedDocumentCategory;
|
|
9
10
|
get children(): EnrichedDocumentCategory[];
|
|
10
11
|
get childrenDeep(): EnrichedDocumentCategory[];
|
|
11
12
|
get types(): EnrichedDocumentType[];
|
|
@@ -14,6 +14,9 @@ export class EnrichedDocumentCategory {
|
|
|
14
14
|
id;
|
|
15
15
|
label;
|
|
16
16
|
parent;
|
|
17
|
+
get rootCategory() {
|
|
18
|
+
return (this.parent?.rootCategory ?? this);
|
|
19
|
+
}
|
|
17
20
|
get children() {
|
|
18
21
|
return this.#data.rawData.categories.filter((category) => category.parentId == this.id).map((category) => new EnrichedDocumentCategory(this.#data, category, this));
|
|
19
22
|
}
|
|
@@ -30,6 +33,11 @@ export class EnrichedDocumentCategory {
|
|
|
30
33
|
this.parent = parent;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
36
|
+
__decorate([
|
|
37
|
+
Memoize(),
|
|
38
|
+
__metadata("design:type", EnrichedDocumentCategory),
|
|
39
|
+
__metadata("design:paramtypes", [])
|
|
40
|
+
], EnrichedDocumentCategory.prototype, "rootCategory", null);
|
|
33
41
|
__decorate([
|
|
34
42
|
Memoize(),
|
|
35
43
|
__metadata("design:type", Array),
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import type { EntityMetadata } from '../../../orm/entity.js';
|
|
1
2
|
import type { TypedOmit } from '../../../types.js';
|
|
2
3
|
import type { DocumentApproval, DocumentValidationExecution, DocumentWorkflow } from '../../models/index.js';
|
|
3
4
|
import type { DocumentPropertyValueView, DocumentView } from '../document-management.view-model.js';
|
|
4
5
|
import { EnrichedDocumentAssignment } from './enriched-document-assignment.view.js';
|
|
5
6
|
import type { EnrichedDocumentManagementData } from './enriched-document-management-data.view.js';
|
|
6
7
|
import type { EnrichedDocumentType } from './enriched-document-type.view.js';
|
|
7
|
-
export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId' | 'assignment' | 'createUserId'
|
|
8
|
+
export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId' | 'assignment' | 'createUserId'> {
|
|
8
9
|
#private;
|
|
9
10
|
readonly id: string;
|
|
10
11
|
readonly title: string | null;
|
|
@@ -22,6 +23,7 @@ export declare class EnrichedDocument implements TypedOmit<DocumentView, 'typeId
|
|
|
22
23
|
readonly properties: DocumentPropertyValueView[];
|
|
23
24
|
readonly currentWorkflow: DocumentWorkflow | null;
|
|
24
25
|
readonly validations: DocumentValidationExecution[] | null;
|
|
26
|
+
readonly metadata: EntityMetadata;
|
|
25
27
|
get type(): EnrichedDocumentType | null;
|
|
26
28
|
get assignments(): EnrichedDocumentAssignment;
|
|
27
29
|
constructor(data: EnrichedDocumentManagementData, document: DocumentView);
|
|
@@ -29,6 +29,7 @@ export class EnrichedDocument {
|
|
|
29
29
|
properties;
|
|
30
30
|
currentWorkflow;
|
|
31
31
|
validations;
|
|
32
|
+
metadata;
|
|
32
33
|
get type() {
|
|
33
34
|
if (isNull(this.#documentView.typeId)) {
|
|
34
35
|
return null;
|
|
@@ -57,6 +58,7 @@ export class EnrichedDocument {
|
|
|
57
58
|
this.properties = document.properties;
|
|
58
59
|
this.currentWorkflow = document.currentWorkflow;
|
|
59
60
|
this.validations = document.validations;
|
|
61
|
+
this.metadata = document.metadata;
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
__decorate([
|