@twin.org/document-management-service 0.0.1-next.2 → 0.0.1-next.20
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/dist/cjs/index.cjs +779 -408
- package/dist/esm/index.mjs +782 -413
- package/dist/types/documentManagementRoutes.d.ts +20 -4
- package/dist/types/documentManagementService.d.ts +84 -34
- package/dist/types/models/IDocumentManagementStorageServiceConstructorOptions.d.ts +5 -0
- package/docs/changelog.md +196 -1
- package/docs/open-api/spec.json +623 -1459
- package/docs/reference/classes/DocumentManagementService.md +193 -61
- package/docs/reference/functions/{documentManagementSet.md → documentManagementCreate.md} +4 -4
- package/docs/reference/functions/documentManagementGetRevision.md +31 -0
- package/docs/reference/functions/documentManagementUpdate.md +31 -0
- package/docs/reference/index.md +3 -1
- package/docs/reference/interfaces/IDocumentManagementServiceConstructorOptions.md +14 -0
- package/locales/en.json +6 -5
- package/package.json +3 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var auditableItemGraphModels = require('@twin.org/auditable-item-graph-models');
|
|
4
4
|
var core = require('@twin.org/core');
|
|
5
5
|
var documentManagementModels = require('@twin.org/document-management-models');
|
|
6
6
|
var standardsSchemaOrg = require('@twin.org/standards-schema-org');
|
|
7
7
|
var standardsUnece = require('@twin.org/standards-unece');
|
|
8
8
|
var web = require('@twin.org/web');
|
|
9
9
|
var attestationModels = require('@twin.org/attestation-models');
|
|
10
|
-
var auditableItemGraphModels = require('@twin.org/auditable-item-graph-models');
|
|
11
10
|
var blobStorageModels = require('@twin.org/blob-storage-models');
|
|
12
11
|
var crypto = require('@twin.org/crypto');
|
|
13
12
|
var dataJsonLd = require('@twin.org/data-json-ld');
|
|
14
13
|
|
|
15
|
-
// Copyright 2024 IOTA Stiftung.
|
|
16
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
17
14
|
/**
|
|
18
15
|
* The source used when communicating about these routes.
|
|
19
16
|
*/
|
|
@@ -34,22 +31,19 @@ const tagsDocumentManagement = [
|
|
|
34
31
|
* @returns The generated routes.
|
|
35
32
|
*/
|
|
36
33
|
function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
37
|
-
const
|
|
34
|
+
const documentManagementCreateRoute = {
|
|
38
35
|
operationId: "DocumentManagementSet",
|
|
39
36
|
summary: "Store a document in an auditable item graph vertex and add its content to blob storage.",
|
|
40
37
|
tag: tagsDocumentManagement[0].name,
|
|
41
38
|
method: "POST",
|
|
42
|
-
path: `${baseRouteName}
|
|
43
|
-
handler: async (httpRequestContext, request) =>
|
|
39
|
+
path: `${baseRouteName}/`,
|
|
40
|
+
handler: async (httpRequestContext, request) => documentManagementCreate(httpRequestContext, componentName, request),
|
|
44
41
|
requestType: {
|
|
45
|
-
type: "
|
|
42
|
+
type: "IDocumentManagementCreateRequest",
|
|
46
43
|
examples: [
|
|
47
44
|
{
|
|
48
|
-
id: "
|
|
45
|
+
id: "DocumentManagementCreateRequestExample",
|
|
49
46
|
request: {
|
|
50
|
-
pathParams: {
|
|
51
|
-
auditableItemGraphId: "aig:123456"
|
|
52
|
-
},
|
|
53
47
|
body: {
|
|
54
48
|
documentId: "2721000",
|
|
55
49
|
documentIdFormat: "bol",
|
|
@@ -71,11 +65,11 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
71
65
|
type: "ICreatedResponse",
|
|
72
66
|
examples: [
|
|
73
67
|
{
|
|
74
|
-
id: "
|
|
68
|
+
id: "DocumentManagementCreateResponseExample",
|
|
75
69
|
response: {
|
|
76
70
|
statusCode: web.HttpStatusCode.created,
|
|
77
71
|
headers: {
|
|
78
|
-
[web.HeaderTypes.Location]: "
|
|
72
|
+
[web.HeaderTypes.Location]: "aig:123456"
|
|
79
73
|
}
|
|
80
74
|
}
|
|
81
75
|
}
|
|
@@ -83,12 +77,54 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
83
77
|
}
|
|
84
78
|
]
|
|
85
79
|
};
|
|
80
|
+
const documentManagementUpdateRoute = {
|
|
81
|
+
operationId: "DocumentManagementUpdate",
|
|
82
|
+
summary: "Update a document in an auditable item graph vertex and add its content to blob storage.",
|
|
83
|
+
tag: tagsDocumentManagement[0].name,
|
|
84
|
+
method: "PUT",
|
|
85
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId`,
|
|
86
|
+
handler: async (httpRequestContext, request) => documentManagementUpdate(httpRequestContext, componentName, request),
|
|
87
|
+
requestType: {
|
|
88
|
+
type: "IDocumentManagementUpdateRequest",
|
|
89
|
+
examples: [
|
|
90
|
+
{
|
|
91
|
+
id: "DocumentManagementUpdateRequestExample",
|
|
92
|
+
request: {
|
|
93
|
+
pathParams: {
|
|
94
|
+
auditableItemGraphDocumentId: "aig:123456"
|
|
95
|
+
},
|
|
96
|
+
body: {
|
|
97
|
+
blob: "SGVsbG8gV29ybGQ=",
|
|
98
|
+
annotationObject: {
|
|
99
|
+
"@context": "https://schema.org",
|
|
100
|
+
"@type": "DigitalDocument",
|
|
101
|
+
name: "myfile.pdf"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
responseType: [
|
|
109
|
+
{
|
|
110
|
+
type: "INoContentResponse",
|
|
111
|
+
examples: [
|
|
112
|
+
{
|
|
113
|
+
id: "DocumentManagementCreateResponseExample",
|
|
114
|
+
response: {
|
|
115
|
+
statusCode: web.HttpStatusCode.noContent
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
};
|
|
86
122
|
const documentManagementGetRoute = {
|
|
87
123
|
operationId: "DocumentManagementGet",
|
|
88
124
|
summary: "Get the data for a document from document management",
|
|
89
125
|
tag: tagsDocumentManagement[0].name,
|
|
90
126
|
method: "GET",
|
|
91
|
-
path: `${baseRouteName}/:
|
|
127
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId`,
|
|
92
128
|
handler: async (httpRequestContext, request) => documentManagementGet(httpRequestContext, componentName, request),
|
|
93
129
|
requestType: {
|
|
94
130
|
type: "IDocumentManagementGetRequest",
|
|
@@ -97,8 +133,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
97
133
|
id: "DocumentManagementGetRequestExample",
|
|
98
134
|
request: {
|
|
99
135
|
pathParams: {
|
|
100
|
-
|
|
101
|
-
documentId: "documents:123456:705:2721000"
|
|
136
|
+
auditableItemGraphDocumentId: "aig:123456"
|
|
102
137
|
}
|
|
103
138
|
}
|
|
104
139
|
}
|
|
@@ -113,16 +148,130 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
113
148
|
response: {
|
|
114
149
|
body: {
|
|
115
150
|
"@context": [
|
|
116
|
-
|
|
117
|
-
documentManagementModels.
|
|
118
|
-
|
|
151
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
|
|
152
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
153
|
+
documentManagementModels.DocumentContexts.ContextRootCommon
|
|
154
|
+
],
|
|
155
|
+
type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
|
|
156
|
+
[standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
|
|
157
|
+
{
|
|
158
|
+
"@context": [
|
|
159
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
160
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
161
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
162
|
+
],
|
|
163
|
+
type: documentManagementModels.DocumentTypes.Document,
|
|
164
|
+
id: "2721000:0",
|
|
165
|
+
documentId: "2721000",
|
|
166
|
+
documentIdFormat: "bol",
|
|
167
|
+
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
168
|
+
documentRevision: 0,
|
|
169
|
+
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
170
|
+
blobHash: "sha256:123456",
|
|
171
|
+
dateCreated: "2024-01-01T00:00:00Z",
|
|
172
|
+
annotationObject: {
|
|
173
|
+
"@context": "https://schema.org",
|
|
174
|
+
"@type": "DigitalDocument",
|
|
175
|
+
name: "myfile.pdf"
|
|
176
|
+
},
|
|
177
|
+
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
178
|
+
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
type: "IDocumentManagementGetResponse",
|
|
188
|
+
mimeType: web.MimeTypes.JsonLd,
|
|
189
|
+
examples: [
|
|
190
|
+
{
|
|
191
|
+
id: "DocumentManagementGetResponseExample",
|
|
192
|
+
response: {
|
|
193
|
+
body: {
|
|
194
|
+
"@context": [
|
|
195
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
|
|
196
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
197
|
+
documentManagementModels.DocumentContexts.ContextRootCommon
|
|
198
|
+
],
|
|
199
|
+
type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
|
|
200
|
+
[standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
|
|
201
|
+
{
|
|
202
|
+
"@context": [
|
|
203
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
204
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
205
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
206
|
+
],
|
|
207
|
+
type: documentManagementModels.DocumentTypes.Document,
|
|
208
|
+
id: "2721000:0",
|
|
209
|
+
documentId: "2721000",
|
|
210
|
+
documentIdFormat: "bol",
|
|
211
|
+
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
212
|
+
documentRevision: 0,
|
|
213
|
+
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
214
|
+
blobHash: "sha256:123456",
|
|
215
|
+
dateCreated: "2024-01-01T00:00:00Z",
|
|
216
|
+
annotationObject: {
|
|
217
|
+
"@context": "https://schema.org",
|
|
218
|
+
"@type": "DigitalDocument",
|
|
219
|
+
name: "myfile.pdf"
|
|
220
|
+
},
|
|
221
|
+
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
222
|
+
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
type: "INotFoundResponse"
|
|
232
|
+
}
|
|
233
|
+
]
|
|
234
|
+
};
|
|
235
|
+
const documentManagementGetRevisionRoute = {
|
|
236
|
+
operationId: "DocumentManagementGetRevision",
|
|
237
|
+
summary: "Get the data for a document revision from document management",
|
|
238
|
+
tag: tagsDocumentManagement[0].name,
|
|
239
|
+
method: "GET",
|
|
240
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId/:revision`,
|
|
241
|
+
handler: async (httpRequestContext, request) => documentManagementGetRevision(httpRequestContext, componentName, request),
|
|
242
|
+
requestType: {
|
|
243
|
+
type: "IDocumentManagementGetRequest",
|
|
244
|
+
examples: [
|
|
245
|
+
{
|
|
246
|
+
id: "DocumentManagementGetRevisionRequestExample",
|
|
247
|
+
request: {
|
|
248
|
+
pathParams: {
|
|
249
|
+
auditableItemGraphDocumentId: "aig:123456",
|
|
250
|
+
revision: "1"
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
responseType: [
|
|
257
|
+
{
|
|
258
|
+
type: "IDocumentManagementGetRevisionResponse",
|
|
259
|
+
examples: [
|
|
260
|
+
{
|
|
261
|
+
id: "DocumentManagementGetRevisionResponseExample",
|
|
262
|
+
response: {
|
|
263
|
+
body: {
|
|
264
|
+
"@context": [
|
|
265
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
266
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
267
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
119
268
|
],
|
|
120
269
|
type: documentManagementModels.DocumentTypes.Document,
|
|
121
|
-
id: "
|
|
270
|
+
id: "2721000:0",
|
|
122
271
|
documentId: "2721000",
|
|
123
272
|
documentIdFormat: "bol",
|
|
124
273
|
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
125
|
-
documentRevision:
|
|
274
|
+
documentRevision: 1,
|
|
126
275
|
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
127
276
|
blobHash: "sha256:123456",
|
|
128
277
|
dateCreated: "2024-01-01T00:00:00Z",
|
|
@@ -130,31 +279,33 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
130
279
|
"@context": "https://schema.org",
|
|
131
280
|
"@type": "DigitalDocument",
|
|
132
281
|
name: "myfile.pdf"
|
|
133
|
-
}
|
|
282
|
+
},
|
|
283
|
+
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
284
|
+
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
134
285
|
}
|
|
135
286
|
}
|
|
136
287
|
}
|
|
137
288
|
]
|
|
138
289
|
},
|
|
139
290
|
{
|
|
140
|
-
type: "
|
|
291
|
+
type: "IDocumentManagementGetRevisionResponse",
|
|
141
292
|
mimeType: web.MimeTypes.JsonLd,
|
|
142
293
|
examples: [
|
|
143
294
|
{
|
|
144
|
-
id: "
|
|
295
|
+
id: "DocumentManagementGetRevisionResponseExample",
|
|
145
296
|
response: {
|
|
146
297
|
body: {
|
|
147
298
|
"@context": [
|
|
148
|
-
documentManagementModels.
|
|
149
|
-
documentManagementModels.
|
|
150
|
-
standardsSchemaOrg.
|
|
299
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
300
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
301
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
151
302
|
],
|
|
152
303
|
type: documentManagementModels.DocumentTypes.Document,
|
|
153
|
-
id: "
|
|
304
|
+
id: "2721000:0",
|
|
154
305
|
documentId: "2721000",
|
|
155
306
|
documentIdFormat: "bol",
|
|
156
307
|
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
157
|
-
documentRevision:
|
|
308
|
+
documentRevision: 1,
|
|
158
309
|
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
159
310
|
blobHash: "sha256:123456",
|
|
160
311
|
dateCreated: "2024-01-01T00:00:00Z",
|
|
@@ -162,7 +313,9 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
162
313
|
"@context": "https://schema.org",
|
|
163
314
|
"@type": "DigitalDocument",
|
|
164
315
|
name: "myfile.pdf"
|
|
165
|
-
}
|
|
316
|
+
},
|
|
317
|
+
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
318
|
+
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
166
319
|
}
|
|
167
320
|
}
|
|
168
321
|
}
|
|
@@ -173,12 +326,12 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
173
326
|
}
|
|
174
327
|
]
|
|
175
328
|
};
|
|
176
|
-
const
|
|
329
|
+
const documentManagementRemoveRevisionRoute = {
|
|
177
330
|
operationId: "DocumentManagementRemove",
|
|
178
331
|
summary: "Remove an document from an auditable item graph vertex",
|
|
179
332
|
tag: tagsDocumentManagement[0].name,
|
|
180
333
|
method: "DELETE",
|
|
181
|
-
path: `${baseRouteName}/:
|
|
334
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId/:revision`,
|
|
182
335
|
handler: async (httpRequestContext, request) => documentManagementRemove(httpRequestContext, componentName, request),
|
|
183
336
|
requestType: {
|
|
184
337
|
type: "IDocumentManagementRemoveRequest",
|
|
@@ -187,8 +340,8 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
187
340
|
id: "DocumentManagementRemoveRequestExample",
|
|
188
341
|
request: {
|
|
189
342
|
pathParams: {
|
|
190
|
-
|
|
191
|
-
|
|
343
|
+
auditableItemGraphDocumentId: "aig:1234",
|
|
344
|
+
revision: "1"
|
|
192
345
|
}
|
|
193
346
|
}
|
|
194
347
|
}
|
|
@@ -208,7 +361,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
208
361
|
summary: "Query the items from an auditable item graph vertex",
|
|
209
362
|
tag: tagsDocumentManagement[0].name,
|
|
210
363
|
method: "GET",
|
|
211
|
-
path: `${baseRouteName}
|
|
364
|
+
path: `${baseRouteName}/`,
|
|
212
365
|
handler: async (httpRequestContext, request) => documentManagementQuery(httpRequestContext, componentName, request),
|
|
213
366
|
requestType: {
|
|
214
367
|
type: "IDocumentManagementQueryRequest",
|
|
@@ -216,8 +369,8 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
216
369
|
{
|
|
217
370
|
id: "DocumentManagementQueryRequestExample",
|
|
218
371
|
request: {
|
|
219
|
-
|
|
220
|
-
|
|
372
|
+
query: {
|
|
373
|
+
documentId: "2721000"
|
|
221
374
|
}
|
|
222
375
|
}
|
|
223
376
|
}
|
|
@@ -231,67 +384,54 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
231
384
|
id: "DocumentManagementQueryResponseExample",
|
|
232
385
|
response: {
|
|
233
386
|
body: {
|
|
234
|
-
"@context": [
|
|
235
|
-
type:
|
|
236
|
-
|
|
387
|
+
"@context": [standardsSchemaOrg.SchemaOrgContexts.ContextRoot, auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot],
|
|
388
|
+
type: [standardsSchemaOrg.SchemaOrgTypes.ItemList, auditableItemGraphModels.AuditableItemGraphTypes.VertexList],
|
|
389
|
+
[standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
|
|
237
390
|
{
|
|
238
391
|
"@context": [
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
standardsSchemaOrg.SchemaOrgTypes.ContextRoot
|
|
392
|
+
auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
393
|
+
auditableItemGraphModels.AuditableItemGraphContexts.ContextRootCommon
|
|
242
394
|
],
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
"@context": "https://schema.org",
|
|
254
|
-
"@type": "DigitalDocument",
|
|
255
|
-
name: "myfile.pdf"
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
]
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
]
|
|
263
|
-
},
|
|
264
|
-
{
|
|
265
|
-
type: "IDocumentManagementQueryResponse",
|
|
266
|
-
mimeType: web.MimeTypes.JsonLd,
|
|
267
|
-
examples: [
|
|
268
|
-
{
|
|
269
|
-
id: "DocumentManagementListResponseJsonLdExample",
|
|
270
|
-
response: {
|
|
271
|
-
body: {
|
|
272
|
-
"@context": [documentManagementModels.DocumentTypes.ContextRoot, documentManagementModels.DocumentTypes.ContextRootCommon],
|
|
273
|
-
type: documentManagementModels.DocumentTypes.DocumentList,
|
|
274
|
-
documents: [
|
|
275
|
-
{
|
|
276
|
-
"@context": [
|
|
277
|
-
documentManagementModels.DocumentTypes.ContextRoot,
|
|
278
|
-
documentManagementModels.DocumentTypes.ContextRootCommon,
|
|
279
|
-
standardsSchemaOrg.SchemaOrgTypes.ContextRoot
|
|
395
|
+
id: "aig:c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7c7",
|
|
396
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Vertex,
|
|
397
|
+
dateCreated: "2024-08-22T04:13:20.000Z",
|
|
398
|
+
aliases: [
|
|
399
|
+
{
|
|
400
|
+
"@context": [auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot],
|
|
401
|
+
id: "test-id-0",
|
|
402
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
403
|
+
dateCreated: "2024-08-22T04:13:20.000Z"
|
|
404
|
+
}
|
|
280
405
|
],
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
406
|
+
resources: [
|
|
407
|
+
{
|
|
408
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
409
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
410
|
+
dateCreated: "2024-08-22T04:13:20.000Z",
|
|
411
|
+
resourceObject: {
|
|
412
|
+
"@context": [
|
|
413
|
+
"https://schema.twindev.org/documents/",
|
|
414
|
+
"https://schema.twindev.org/common/",
|
|
415
|
+
"https://schema.org"
|
|
416
|
+
],
|
|
417
|
+
type: "Document",
|
|
418
|
+
id: "test-id-0:0",
|
|
419
|
+
documentId: "test-id-0",
|
|
420
|
+
documentCode: "unece:DocumentCodeList#705",
|
|
421
|
+
documentRevision: 0,
|
|
422
|
+
annotationObject: {
|
|
423
|
+
"@context": "https://schema.org",
|
|
424
|
+
type: "DigitalDocument",
|
|
425
|
+
name: "bill-of-lading"
|
|
426
|
+
},
|
|
427
|
+
blobHash: "sha256:E3Duqrp6bHojSx+CzDttAToAiP1eFkCDAPBbKLABVGM=",
|
|
428
|
+
blobStorageId: "blob:memory:1370eeaaba7a6c7a234b1f82cc3b6d013a0088fd5e16408300f05b28b0015463",
|
|
429
|
+
dateCreated: "2024-08-22T04:13:20.000Z",
|
|
430
|
+
nodeIdentity: "did:entity-storage:0x0101010101010101010101010101010101010101010101010101010101010101",
|
|
431
|
+
userIdentity: "did:entity-storage:0x0404040404040404040404040404040404040404040404040404040404040404"
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
]
|
|
295
435
|
}
|
|
296
436
|
]
|
|
297
437
|
}
|
|
@@ -302,27 +442,31 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
302
442
|
]
|
|
303
443
|
};
|
|
304
444
|
return [
|
|
305
|
-
|
|
445
|
+
documentManagementCreateRoute,
|
|
446
|
+
documentManagementUpdateRoute,
|
|
306
447
|
documentManagementGetRoute,
|
|
307
|
-
|
|
448
|
+
documentManagementGetRevisionRoute,
|
|
449
|
+
documentManagementRemoveRevisionRoute,
|
|
308
450
|
documentManagementQueryRoute
|
|
309
451
|
];
|
|
310
452
|
}
|
|
311
453
|
/**
|
|
312
|
-
*
|
|
454
|
+
* Create a document as an auditable item graph vertex.
|
|
313
455
|
* @param httpRequestContext The request context for the API.
|
|
314
456
|
* @param componentName The name of the component to use in the routes.
|
|
315
457
|
* @param request The request.
|
|
316
458
|
* @returns The response object with additional http response properties.
|
|
317
459
|
*/
|
|
318
|
-
async function
|
|
460
|
+
async function documentManagementCreate(httpRequestContext, componentName, request) {
|
|
319
461
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
320
|
-
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
321
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphId", request.pathParams.auditableItemGraphId);
|
|
322
462
|
core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
|
|
323
463
|
core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
|
|
324
464
|
const component = core.ComponentFactory.get(componentName);
|
|
325
|
-
const id = await component.
|
|
465
|
+
const id = await component.create(request.body.documentId, request.body.documentIdFormat, request.body.documentCode, core.Converter.base64ToBytes(request.body.blob), request.body.annotationObject, request.body.auditableItemGraphEdges, {
|
|
466
|
+
createAttestation: request.body.createAttestation,
|
|
467
|
+
addAlias: request.body.addAlias,
|
|
468
|
+
aliasAnnotationObject: request.body.aliasAnnotationObject
|
|
469
|
+
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
326
470
|
return {
|
|
327
471
|
statusCode: web.HttpStatusCode.created,
|
|
328
472
|
headers: {
|
|
@@ -340,17 +484,46 @@ async function documentManagementSet(httpRequestContext, componentName, request)
|
|
|
340
484
|
async function documentManagementGet(httpRequestContext, componentName, request) {
|
|
341
485
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
342
486
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
343
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.
|
|
344
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.documentId", request.pathParams.documentId);
|
|
487
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
345
488
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
346
489
|
const component = core.ComponentFactory.get(componentName);
|
|
347
|
-
const result = await component.get(request.pathParams.
|
|
490
|
+
const result = await component.get(request.pathParams.auditableItemGraphDocumentId, {
|
|
348
491
|
includeBlobStorageMetadata: core.Coerce.boolean(request.query?.includeBlobStorageMetadata),
|
|
349
492
|
includeBlobStorageData: core.Coerce.boolean(request.query?.includeBlobStorageData),
|
|
350
493
|
includeAttestation: core.Coerce.boolean(request.query?.includeAttestation),
|
|
351
494
|
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved),
|
|
352
|
-
|
|
353
|
-
|
|
495
|
+
extractRuleGroupId: request.query?.extractRuleGroupId,
|
|
496
|
+
extractMimeType: request.query?.extractMimeType
|
|
497
|
+
}, request.query?.cursor, core.Coerce.integer(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
498
|
+
return {
|
|
499
|
+
headers: {
|
|
500
|
+
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
501
|
+
},
|
|
502
|
+
body: result
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Get the document revision from the auditable item graph vertex.
|
|
507
|
+
* @param httpRequestContext The request context for the API.
|
|
508
|
+
* @param componentName The name of the component to use in the routes.
|
|
509
|
+
* @param request The request.
|
|
510
|
+
* @returns The response object with additional http response properties.
|
|
511
|
+
*/
|
|
512
|
+
async function documentManagementGetRevision(httpRequestContext, componentName, request) {
|
|
513
|
+
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
514
|
+
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
515
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
516
|
+
const revision = core.Coerce.integer(request.pathParams.revision);
|
|
517
|
+
core.Guards.integer(ROUTES_SOURCE, "revision", revision);
|
|
518
|
+
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
519
|
+
const component = core.ComponentFactory.get(componentName);
|
|
520
|
+
const result = await component.getRevision(request.pathParams.auditableItemGraphDocumentId, revision, {
|
|
521
|
+
includeBlobStorageMetadata: core.Coerce.boolean(request.query?.includeBlobStorageMetadata),
|
|
522
|
+
includeBlobStorageData: core.Coerce.boolean(request.query?.includeBlobStorageData),
|
|
523
|
+
includeAttestation: core.Coerce.boolean(request.query?.includeAttestation),
|
|
524
|
+
extractRuleGroupId: request.query?.extractRuleGroupId,
|
|
525
|
+
extractMimeType: request.query?.extractMimeType
|
|
526
|
+
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
354
527
|
return {
|
|
355
528
|
headers: {
|
|
356
529
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -358,6 +531,23 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
358
531
|
body: result
|
|
359
532
|
};
|
|
360
533
|
}
|
|
534
|
+
/**
|
|
535
|
+
* Update the document from the auditable item graph vertex.
|
|
536
|
+
* @param httpRequestContext The request context for the API.
|
|
537
|
+
* @param componentName The name of the component to use in the routes.
|
|
538
|
+
* @param request The request.
|
|
539
|
+
* @returns The response object with additional http response properties.
|
|
540
|
+
*/
|
|
541
|
+
async function documentManagementUpdate(httpRequestContext, componentName, request) {
|
|
542
|
+
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
543
|
+
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
544
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
545
|
+
const component = core.ComponentFactory.get(componentName);
|
|
546
|
+
await component.update(request.pathParams.auditableItemGraphDocumentId, core.Is.stringValue(request.body.blob) ? core.Converter.base64ToBytes(request.body.blob) : undefined, request.body.annotationObject, request.body.auditableItemGraphEdges, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
547
|
+
return {
|
|
548
|
+
statusCode: web.HttpStatusCode.noContent
|
|
549
|
+
};
|
|
550
|
+
}
|
|
361
551
|
/**
|
|
362
552
|
* Remove the document from the auditable item graph vertex.
|
|
363
553
|
* @param httpRequestContext The request context for the API.
|
|
@@ -368,12 +558,11 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
368
558
|
async function documentManagementRemove(httpRequestContext, componentName, request) {
|
|
369
559
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
370
560
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
371
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.
|
|
372
|
-
core.
|
|
561
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
562
|
+
const revision = core.Coerce.number(request.pathParams.revision);
|
|
563
|
+
core.Guards.integer(ROUTES_SOURCE, "request.pathParams.revision", revision);
|
|
373
564
|
const component = core.ComponentFactory.get(componentName);
|
|
374
|
-
await component.
|
|
375
|
-
removeAllRevisions: request.query?.removeAllRevisions
|
|
376
|
-
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
565
|
+
await component.removeRevision(request.pathParams.auditableItemGraphDocumentId, revision, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
377
566
|
return {
|
|
378
567
|
statusCode: web.HttpStatusCode.noContent
|
|
379
568
|
};
|
|
@@ -387,14 +576,11 @@ async function documentManagementRemove(httpRequestContext, componentName, reque
|
|
|
387
576
|
*/
|
|
388
577
|
async function documentManagementQuery(httpRequestContext, componentName, request) {
|
|
389
578
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
390
|
-
core.Guards.object(ROUTES_SOURCE, "request.
|
|
391
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.
|
|
579
|
+
core.Guards.object(ROUTES_SOURCE, "request.query", request.query);
|
|
580
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.query.documentId", request.query.documentId);
|
|
392
581
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
393
582
|
const component = core.ComponentFactory.get(componentName);
|
|
394
|
-
const result = await component.query(request.
|
|
395
|
-
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved),
|
|
396
|
-
includeMostRecentRevisions: core.Coerce.boolean(request.query?.includeMostRecentRevisions)
|
|
397
|
-
}, request.query?.cursor, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
583
|
+
const result = await component.query(request.query.documentId, request.query?.cursor, core.Coerce.integer(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
398
584
|
return {
|
|
399
585
|
headers: {
|
|
400
586
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -411,11 +597,6 @@ class DocumentManagementService {
|
|
|
411
597
|
* The namespace supported by the document management service.
|
|
412
598
|
*/
|
|
413
599
|
static NAMESPACE = "documents";
|
|
414
|
-
/**
|
|
415
|
-
* Default Page Size for cursor.
|
|
416
|
-
* @internal
|
|
417
|
-
*/
|
|
418
|
-
static _DEFAULT_PAGE_SIZE = 20;
|
|
419
600
|
/**
|
|
420
601
|
* Runtime name for the class.
|
|
421
602
|
*/
|
|
@@ -435,6 +616,11 @@ class DocumentManagementService {
|
|
|
435
616
|
* @internal
|
|
436
617
|
*/
|
|
437
618
|
_attestationComponent;
|
|
619
|
+
/**
|
|
620
|
+
* The connector for the data processing.
|
|
621
|
+
* @internal
|
|
622
|
+
*/
|
|
623
|
+
_dataProcessingComponent;
|
|
438
624
|
/**
|
|
439
625
|
* Create a new instance of DocumentManagementService.
|
|
440
626
|
* @param options The options for the service.
|
|
@@ -443,133 +629,218 @@ class DocumentManagementService {
|
|
|
443
629
|
this._auditableItemGraphComponent = core.ComponentFactory.get(options?.auditableItemGraphComponentType ?? "auditable-item-graph");
|
|
444
630
|
this._blobStorageComponent = core.ComponentFactory.get(options?.blobStorageComponentType ?? "blob-storage");
|
|
445
631
|
this._attestationComponent = core.ComponentFactory.get(options?.attestationComponentType ?? "attestation");
|
|
632
|
+
this._dataProcessingComponent = core.ComponentFactory.get(options?.dataProcessingComponentType ?? "data-processing");
|
|
446
633
|
standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
|
|
447
634
|
}
|
|
448
635
|
/**
|
|
449
|
-
* Store a document
|
|
636
|
+
* Store a document as an auditable item graph vertex and add its content to blob storage.
|
|
450
637
|
* If the document id already exists and the blob data is different a new revision will be created.
|
|
451
638
|
* For any other changes the current revision will be updated.
|
|
452
|
-
* @param auditableItemGraphId The auditable item graph vertex id to create the document on.
|
|
453
639
|
* @param documentId The document id to create.
|
|
454
640
|
* @param documentIdFormat The format of the document identifier.
|
|
455
641
|
* @param documentCode The code for the document type.
|
|
456
|
-
* @param blob The data to create the document.
|
|
642
|
+
* @param blob The data to create the document with.
|
|
457
643
|
* @param annotationObject Additional information to associate with the document.
|
|
458
|
-
* @param
|
|
644
|
+
* @param auditableItemGraphEdges The auditable item graph vertices to connect the document to.
|
|
645
|
+
* @param options Additional options for the set operation.
|
|
646
|
+
* @param options.createAttestation Flag to create an attestation for the document, defaults to false.
|
|
647
|
+
* @param options.addAlias Flag to add the document id as an alias to the aig vertex, defaults to true.
|
|
648
|
+
* @param options.aliasAnnotationObject Annotation object for the alias.
|
|
459
649
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
460
650
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
461
|
-
* @returns The
|
|
651
|
+
* @returns The auditable item graph vertex created for the document including its revision.
|
|
462
652
|
*/
|
|
463
|
-
async
|
|
464
|
-
core.Guards.stringValue(this.CLASS_NAME, "auditableItemGraphId", auditableItemGraphId);
|
|
653
|
+
async create(documentId, documentIdFormat, documentCode, blob, annotationObject, auditableItemGraphEdges, options, userIdentity, nodeIdentity) {
|
|
465
654
|
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
466
655
|
core.Guards.arrayOneOf(this.CLASS_NAME, "documentCode", documentCode, Object.values(standardsUnece.UneceDocumentCodes));
|
|
467
656
|
core.Guards.uint8Array(this.CLASS_NAME, "blob", blob);
|
|
657
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
658
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
468
659
|
try {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const matchingDocIds = this.findMatchingDocs(vertexDocs, documentId, documentCode, true);
|
|
475
|
-
// Calculate the hash for the blob.
|
|
476
|
-
const blobHash = this.generateBlobHash(blob);
|
|
477
|
-
let documentRevision;
|
|
478
|
-
if (core.Is.arrayValue(matchingDocIds) && matchingDocIds[0].blobHash === blobHash) {
|
|
479
|
-
documentRevision = matchingDocIds[0].documentRevision;
|
|
480
|
-
// If there is already a doc with the matching blob hash no need to create a new revision
|
|
481
|
-
// instead we just update the annotation object if it has changed.
|
|
482
|
-
if (!core.ObjectHelper.equal(matchingDocIds[0].annotationObject, annotationObject, false)) {
|
|
483
|
-
matchingDocIds[0].dateModified = new Date().toISOString();
|
|
484
|
-
matchingDocIds[0].annotationObject = annotationObject;
|
|
485
|
-
await this._auditableItemGraphComponent.update(vertex, userIdentity, nodeIdentity);
|
|
660
|
+
// Get the connected vertices first, if one fails we abort the create
|
|
661
|
+
const connectedVertices = {};
|
|
662
|
+
if (core.Is.arrayValue(auditableItemGraphEdges)) {
|
|
663
|
+
for (const edge of auditableItemGraphEdges) {
|
|
664
|
+
connectedVertices[edge.id] = await this._auditableItemGraphComponent.get(edge.id);
|
|
486
665
|
}
|
|
487
|
-
return matchingDocIds[0].id;
|
|
488
666
|
}
|
|
489
|
-
|
|
667
|
+
const documentVertex = {};
|
|
668
|
+
if (options?.addAlias ?? true) {
|
|
669
|
+
documentVertex.aliases ??= [];
|
|
670
|
+
documentVertex.aliases.push({
|
|
671
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
672
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
673
|
+
id: documentId,
|
|
674
|
+
aliasFormat: documentIdFormat,
|
|
675
|
+
annotationObject: options?.aliasAnnotationObject
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
// Add the blob to blob storage
|
|
490
679
|
const blobStorageId = await this._blobStorageComponent.create(core.Converter.bytesToBase64(blob), undefined, undefined, undefined, undefined, userIdentity, nodeIdentity);
|
|
491
|
-
|
|
492
|
-
// We are creating a new document, if there is already docs with the same id and code we use the list length
|
|
493
|
-
// to determine the next revision number.
|
|
494
|
-
const document = {
|
|
680
|
+
const currentRevision = {
|
|
495
681
|
"@context": [
|
|
496
|
-
documentManagementModels.
|
|
497
|
-
documentManagementModels.
|
|
498
|
-
standardsSchemaOrg.
|
|
682
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
683
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
684
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
499
685
|
],
|
|
500
686
|
type: documentManagementModels.DocumentTypes.Document,
|
|
501
|
-
id: this.
|
|
687
|
+
id: this.createDocumentId(documentId, 0),
|
|
502
688
|
documentId,
|
|
503
689
|
documentIdFormat,
|
|
504
690
|
documentCode,
|
|
505
|
-
documentRevision,
|
|
691
|
+
documentRevision: 0,
|
|
692
|
+
annotationObject,
|
|
693
|
+
blobHash: this.generateBlobHash(blob),
|
|
506
694
|
blobStorageId,
|
|
507
|
-
|
|
508
|
-
|
|
695
|
+
dateCreated: new Date(Date.now()).toISOString(),
|
|
696
|
+
nodeIdentity,
|
|
697
|
+
userIdentity
|
|
509
698
|
};
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
// Add the new revision in to the AIG
|
|
518
|
-
vertex.resources.push({
|
|
519
|
-
"@context": auditableItemGraphModels.AuditableItemGraphTypes.ContextRoot,
|
|
699
|
+
if (options?.createAttestation ?? false) {
|
|
700
|
+
currentRevision.attestationId = await this.createAttestation(currentRevision, userIdentity, nodeIdentity);
|
|
701
|
+
}
|
|
702
|
+
// Add the new revision in to the vertex
|
|
703
|
+
documentVertex.resources ??= [];
|
|
704
|
+
documentVertex.resources.push({
|
|
705
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
520
706
|
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
521
|
-
resourceObject:
|
|
707
|
+
resourceObject: currentRevision
|
|
522
708
|
});
|
|
523
|
-
|
|
524
|
-
|
|
709
|
+
// Add the edges from the document to the items
|
|
710
|
+
this.updateEdges(documentVertex, auditableItemGraphEdges);
|
|
711
|
+
// And create the vertex
|
|
712
|
+
const vertexId = await this._auditableItemGraphComponent.create(documentVertex, userIdentity, nodeIdentity);
|
|
713
|
+
// Now add the edges to the connected vertices
|
|
714
|
+
await this.updateConnectedEdges(connectedVertices, vertexId, [], auditableItemGraphEdges, documentId, documentIdFormat, userIdentity, nodeIdentity);
|
|
715
|
+
return vertexId;
|
|
525
716
|
}
|
|
526
717
|
catch (error) {
|
|
527
718
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
528
719
|
throw error;
|
|
529
720
|
}
|
|
530
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
721
|
+
throw new core.GeneralError(this.CLASS_NAME, "createFailed", undefined, error);
|
|
531
722
|
}
|
|
532
723
|
}
|
|
533
724
|
/**
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
725
|
+
* Update a document as an auditable item graph vertex and add its content to blob storage.
|
|
726
|
+
* If the blob data is different a new revision will be created.
|
|
727
|
+
* For any other changes the current revision will be updated.
|
|
728
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
729
|
+
* @param blob The data to update the document with.
|
|
730
|
+
* @param annotationObject Additional information to associate with the document.
|
|
731
|
+
* @param auditableItemGraphEdges The auditable item graph vertices to connect the document to, if undefined retains current connections.
|
|
732
|
+
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
733
|
+
* @param nodeIdentity The node identity to use for vault operations.
|
|
734
|
+
* @returns Nothing.
|
|
735
|
+
*/
|
|
736
|
+
async update(auditableItemGraphDocumentId, blob, annotationObject, auditableItemGraphEdges, userIdentity, nodeIdentity) {
|
|
737
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
738
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
739
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
740
|
+
try {
|
|
741
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId, { includeDeleted: true });
|
|
742
|
+
if (core.Is.empty(documentVertex.resources)) {
|
|
743
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
744
|
+
}
|
|
745
|
+
const documents = await this.getDocumentsFromVertex(documentVertex);
|
|
746
|
+
const latestRevision = documents.itemListElement[0];
|
|
747
|
+
documentVertex.resources = documentVertex.resources.filter(r => core.Is.empty(r.dateDeleted));
|
|
748
|
+
if (core.Is.empty(latestRevision)) {
|
|
749
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
750
|
+
}
|
|
751
|
+
// If auditableItemGraphEdges is undefined we are not updating the edges
|
|
752
|
+
// an empty array can be passed to remove all edges
|
|
753
|
+
const connectedVertices = {};
|
|
754
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
755
|
+
// Get the updated connected vertices first, if one fails we abort the update
|
|
756
|
+
for (const edge of auditableItemGraphEdges) {
|
|
757
|
+
connectedVertices[edge.id] = await this._auditableItemGraphComponent.get(edge.id);
|
|
758
|
+
}
|
|
759
|
+
// Also get the current edges in case some need disconnecting
|
|
760
|
+
if (core.Is.arrayValue(documents.edges)) {
|
|
761
|
+
for (const edgeId of documents.edges) {
|
|
762
|
+
// If we haven't retrieved the edge then it must be one that needs removing
|
|
763
|
+
if (core.Is.empty(connectedVertices[edgeId])) {
|
|
764
|
+
connectedVertices[edgeId] = await this._auditableItemGraphComponent.get(edgeId);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
let updatedVertex = false;
|
|
770
|
+
// If the blob is set and its hash has changed then we create a new revision
|
|
771
|
+
if (core.Is.uint8Array(blob)) {
|
|
772
|
+
const newBlobHash = this.generateBlobHash(blob);
|
|
773
|
+
if (latestRevision.blobHash !== newBlobHash) {
|
|
774
|
+
// Add the blob to blob storage
|
|
775
|
+
const blobStorageId = await this._blobStorageComponent.create(core.Converter.bytesToBase64(blob), undefined, undefined, undefined, undefined, userIdentity, nodeIdentity);
|
|
776
|
+
const newRevision = core.ObjectHelper.clone(latestRevision);
|
|
777
|
+
newRevision.documentRevision++;
|
|
778
|
+
newRevision.id = this.createDocumentId(newRevision.documentId, newRevision.documentRevision);
|
|
779
|
+
newRevision.blobHash = newBlobHash;
|
|
780
|
+
newRevision.blobStorageId = blobStorageId;
|
|
781
|
+
newRevision.annotationObject = annotationObject;
|
|
782
|
+
if (core.Is.stringValue(latestRevision.attestationId)) {
|
|
783
|
+
newRevision.attestationId = await this.createAttestation(newRevision, userIdentity, nodeIdentity);
|
|
784
|
+
}
|
|
785
|
+
documentVertex.resources.push({
|
|
786
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
787
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
788
|
+
resourceObject: newRevision
|
|
789
|
+
});
|
|
790
|
+
updatedVertex = true;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
// If the blob wasn't updated but the annotation object has then update the current revision
|
|
794
|
+
// instead of creating a new one
|
|
795
|
+
if (!updatedVertex &&
|
|
796
|
+
!core.ObjectHelper.equal(latestRevision.annotationObject, annotationObject)) {
|
|
797
|
+
updatedVertex = true;
|
|
798
|
+
latestRevision.annotationObject = annotationObject;
|
|
799
|
+
latestRevision.dateModified = new Date(Date.now()).toISOString();
|
|
800
|
+
}
|
|
801
|
+
const existingEdgeIds = documentVertex.edges?.map(e => e.id) ?? [];
|
|
802
|
+
// Update the edges from the document to the items
|
|
803
|
+
const edgesUpdated = this.updateEdges(documentVertex, auditableItemGraphEdges);
|
|
804
|
+
if (edgesUpdated) {
|
|
805
|
+
updatedVertex = true;
|
|
806
|
+
}
|
|
807
|
+
if (updatedVertex) {
|
|
808
|
+
await this._auditableItemGraphComponent.update(documentVertex, userIdentity, nodeIdentity);
|
|
809
|
+
}
|
|
810
|
+
if (edgesUpdated) {
|
|
811
|
+
await this.updateConnectedEdges(connectedVertices, auditableItemGraphDocumentId, existingEdgeIds, auditableItemGraphEdges, latestRevision.documentId, latestRevision.documentIdFormat, userIdentity, nodeIdentity);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
816
|
+
throw error;
|
|
817
|
+
}
|
|
818
|
+
throw new core.GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Get a document using it's auditable item graph vertex id and optional revision.
|
|
823
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
537
824
|
* @param options Additional options for the get operation.
|
|
538
825
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
539
826
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
540
827
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
541
828
|
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
542
|
-
* @param options.
|
|
543
|
-
* @param
|
|
829
|
+
* @param options.extractRuleGroupId If provided will extract data from the document using the specified rule group id.
|
|
830
|
+
* @param options.extractMimeType By default extraction will auto detect the mime type of the document, this can be used to override the detection.
|
|
831
|
+
* @param cursor The cursor to get the next chunk of revisions.
|
|
832
|
+
* @param pageSize Page size of items to return, defaults to 1 so only most recent is returned.
|
|
544
833
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
545
834
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
546
835
|
* @returns The documents and revisions if requested, ordered by revision descending, cursor is set if there are more document revisions.
|
|
547
836
|
*/
|
|
548
|
-
async get(
|
|
549
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
550
|
-
core.Urn.guard(this.CLASS_NAME, "identifier", identifier);
|
|
837
|
+
async get(auditableItemGraphDocumentId, options, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
838
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
551
839
|
try {
|
|
552
|
-
const
|
|
553
|
-
const includeBlobStorageData = options?.includeBlobStorageData ?? false;
|
|
554
|
-
const includeAttestation = options?.includeAttestation ?? false;
|
|
555
|
-
const includeRemoved = options?.includeRemoved ?? false;
|
|
556
|
-
const revCursor = Math.max(core.Coerce.integer(revisionCursor) ?? 0, 0);
|
|
557
|
-
const maxRevisionCount = Math.max(core.Coerce.integer(options?.maxRevisionCount) ?? 0);
|
|
558
|
-
const documentIdParts = this.parseDocumentId(identifier);
|
|
559
|
-
const vertex = await this._auditableItemGraphComponent.get(auditableItemGraphId);
|
|
560
|
-
// Get all the docs from the AIG vertex
|
|
561
|
-
const vertexDocs = this.filterDocumentsFromVertex(vertex);
|
|
562
|
-
// Reduce the list to those with a matching id and code
|
|
563
|
-
const matchingDocIds = this.findMatchingDocs(vertexDocs, documentIdParts.documentId, documentIdParts.documentCode, includeRemoved);
|
|
840
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId, { includeDeleted: options?.includeRemoved });
|
|
564
841
|
// Populate the document and revisions with the options set
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
includeBlobStorageData,
|
|
568
|
-
includeAttestation,
|
|
569
|
-
includeRemoved,
|
|
570
|
-
maxRevisionCount
|
|
571
|
-
}, revCursor, userIdentity, nodeIdentity);
|
|
572
|
-
return dataJsonLd.JsonLdProcessor.compact(document, document["@context"]);
|
|
842
|
+
const documents = await this.getDocumentsFromVertex(documentVertex, options, cursor, pageSize, userIdentity, nodeIdentity);
|
|
843
|
+
return dataJsonLd.JsonLdProcessor.compact(documents, documents["@context"]);
|
|
573
844
|
}
|
|
574
845
|
catch (error) {
|
|
575
846
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
@@ -579,218 +850,237 @@ class DocumentManagementService {
|
|
|
579
850
|
}
|
|
580
851
|
}
|
|
581
852
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
* @param
|
|
585
|
-
* @param
|
|
586
|
-
* @param options
|
|
587
|
-
* @param options.
|
|
853
|
+
* Get a document revision using it's auditable item graph vertex id.
|
|
854
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
855
|
+
* @param revision The revision id for the document.
|
|
856
|
+
* @param options Additional options for the get operation.
|
|
857
|
+
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
858
|
+
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
859
|
+
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
860
|
+
* @param options.extractRuleGroupId If provided will extract data from the document using the specified rule group id.
|
|
861
|
+
* @param options.extractMimeType By default extraction will auto detect the mime type of the document, this can be used to override the detection.
|
|
588
862
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
589
863
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
590
|
-
* @returns
|
|
864
|
+
* @returns The documents and revisions if requested, ordered by revision descending, cursor is set if there are more document revisions.
|
|
591
865
|
*/
|
|
592
|
-
async
|
|
593
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
594
|
-
core.
|
|
866
|
+
async getRevision(auditableItemGraphDocumentId, revision, options, userIdentity, nodeIdentity) {
|
|
867
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
868
|
+
core.Guards.integer(this.CLASS_NAME, "revision", revision);
|
|
595
869
|
try {
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
const vertexDocs = this.filterDocumentsFromVertex(vertex);
|
|
600
|
-
// Reduce the list to those with a matching id and code
|
|
601
|
-
const matchingDocIds = this.findMatchingDocs(vertexDocs, documentIdParts.documentId, documentIdParts.documentCode, false);
|
|
602
|
-
const removeAllRevisions = options?.removeAllRevisions ?? false;
|
|
603
|
-
const now = Date.now();
|
|
604
|
-
if (removeAllRevisions) {
|
|
605
|
-
for (const doc of matchingDocIds) {
|
|
606
|
-
doc.dateDeleted = new Date(now).toISOString();
|
|
607
|
-
}
|
|
870
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId, { includeDeleted: true });
|
|
871
|
+
if (core.Is.empty(documentVertex.resources)) {
|
|
872
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
608
873
|
}
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
matchingRevision.dateDeleted = new Date(now).toISOString();
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", identifier);
|
|
616
|
-
}
|
|
874
|
+
documentVertex.resources = documentVertex.resources.filter(d => d.resourceObject?.documentRevision === revision);
|
|
875
|
+
if (documentVertex.resources.length === 0) {
|
|
876
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", revision.toString());
|
|
617
877
|
}
|
|
618
|
-
|
|
878
|
+
// Populate the document and revisions with the options set
|
|
879
|
+
const docList = await this.getDocumentsFromVertex(documentVertex, options, undefined, undefined, userIdentity, nodeIdentity);
|
|
880
|
+
return dataJsonLd.JsonLdProcessor.compact(docList.itemListElement[0], docList.itemListElement[0]["@context"]);
|
|
619
881
|
}
|
|
620
882
|
catch (error) {
|
|
621
883
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
622
884
|
throw error;
|
|
623
885
|
}
|
|
624
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
886
|
+
throw new core.GeneralError(this.CLASS_NAME, "getRevisionFailed", undefined, error);
|
|
625
887
|
}
|
|
626
888
|
}
|
|
627
889
|
/**
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
* @param
|
|
631
|
-
* @param
|
|
632
|
-
* @param options.includeMostRecentRevisions Include the most recent 5 revisions, use the individual get to retrieve more.
|
|
633
|
-
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
634
|
-
* @param cursor The cursor to get the next chunk of documents.
|
|
890
|
+
* Remove an auditable item graph vertex using it's id.
|
|
891
|
+
* The document dateDeleted will be set, but can still be queried with the includeRemoved flag.
|
|
892
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
893
|
+
* @param revision The revision of the document to remove.
|
|
635
894
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
636
895
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
637
|
-
* @returns
|
|
896
|
+
* @returns Nothing.
|
|
638
897
|
*/
|
|
639
|
-
async
|
|
640
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
898
|
+
async removeRevision(auditableItemGraphDocumentId, revision, userIdentity, nodeIdentity) {
|
|
899
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
900
|
+
core.Guards.number(this.CLASS_NAME, "revision", revision);
|
|
641
901
|
try {
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
const documentIdGroups = {};
|
|
653
|
-
let docGroupIds = [];
|
|
654
|
-
for (const doc of matchingDocIds) {
|
|
655
|
-
const docId = `${doc.documentId}:${doc.documentCode}`;
|
|
656
|
-
if (!docGroupIds.includes(docId)) {
|
|
657
|
-
docGroupIds.push(docId);
|
|
658
|
-
}
|
|
659
|
-
documentIdGroups[docId] ??= [];
|
|
660
|
-
documentIdGroups[docId].push(doc);
|
|
661
|
-
}
|
|
662
|
-
let nextDocCursor;
|
|
663
|
-
if (docGroupIds.length > docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE) {
|
|
664
|
-
nextDocCursor = (docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE).toString();
|
|
665
|
-
}
|
|
666
|
-
docGroupIds = docGroupIds.slice(docCursor, docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE);
|
|
667
|
-
const finalDocs = [];
|
|
668
|
-
for (const docId of docGroupIds) {
|
|
669
|
-
finalDocs.push(await this.getDocumentAndRevisions(documentIdGroups[docId], docId, {
|
|
670
|
-
includeAttestation: false,
|
|
671
|
-
includeBlobStorageData: false,
|
|
672
|
-
includeBlobStorageMetadata: false,
|
|
673
|
-
includeRemoved,
|
|
674
|
-
maxRevisionCount: includeMostRecentRevisions ? 5 : 0
|
|
675
|
-
}, 0, userIdentity, nodeIdentity));
|
|
676
|
-
}
|
|
677
|
-
const docList = {
|
|
678
|
-
"@context": [
|
|
679
|
-
documentManagementModels.DocumentTypes.ContextRoot,
|
|
680
|
-
documentManagementModels.DocumentTypes.ContextRootCommon,
|
|
681
|
-
standardsSchemaOrg.SchemaOrgTypes.ContextRoot
|
|
682
|
-
],
|
|
683
|
-
type: documentManagementModels.DocumentTypes.DocumentList,
|
|
684
|
-
documents: finalDocs,
|
|
685
|
-
cursor: nextDocCursor
|
|
686
|
-
};
|
|
687
|
-
return dataJsonLd.JsonLdProcessor.compact(docList, docList["@context"]);
|
|
902
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId);
|
|
903
|
+
if (core.Is.empty(documentVertex.resources)) {
|
|
904
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
905
|
+
}
|
|
906
|
+
const docRevisionIndex = documentVertex.resources.findIndex(d => d.resourceObject?.documentRevision === revision);
|
|
907
|
+
if (docRevisionIndex === -1) {
|
|
908
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", revision.toString());
|
|
909
|
+
}
|
|
910
|
+
documentVertex.resources.splice(docRevisionIndex, 1);
|
|
911
|
+
await this._auditableItemGraphComponent.update(documentVertex, userIdentity, nodeIdentity);
|
|
688
912
|
}
|
|
689
913
|
catch (error) {
|
|
690
914
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
691
915
|
throw error;
|
|
692
916
|
}
|
|
693
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
917
|
+
throw new core.GeneralError(this.CLASS_NAME, "removeRevisionFailed", undefined, error);
|
|
694
918
|
}
|
|
695
919
|
}
|
|
696
920
|
/**
|
|
697
|
-
*
|
|
698
|
-
* @param documentId The document
|
|
699
|
-
* @
|
|
700
|
-
* @
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
/**
|
|
706
|
-
* Decode the document id.
|
|
707
|
-
* @param documentId The document identifier.
|
|
708
|
-
* @returns The decoded identifier.
|
|
709
|
-
* @internal
|
|
921
|
+
* Find all the document with a specific id.
|
|
922
|
+
* @param documentId The document id to find in the graph.
|
|
923
|
+
* @param cursor The cursor to get the next chunk of documents.
|
|
924
|
+
* @param pageSize The page size to get the next chunk of documents.
|
|
925
|
+
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
926
|
+
* @param nodeIdentity The node identity to use for vault operations.
|
|
927
|
+
* @returns The graph vertices that contain documents referencing the specified document id.
|
|
710
928
|
*/
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
929
|
+
async query(documentId, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
930
|
+
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
931
|
+
try {
|
|
932
|
+
return this._auditableItemGraphComponent.query({
|
|
933
|
+
id: documentId,
|
|
934
|
+
idMode: "both",
|
|
935
|
+
resourceTypes: [documentManagementModels.DocumentTypes.Document]
|
|
936
|
+
}, undefined, undefined, undefined, ["id", "dateCreated", "dateModified", "aliases", "annotationObject", "resources", "edges"], cursor, pageSize);
|
|
937
|
+
}
|
|
938
|
+
catch (error) {
|
|
939
|
+
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
940
|
+
throw error;
|
|
941
|
+
}
|
|
942
|
+
throw new core.GeneralError(this.CLASS_NAME, "queryFailed", undefined, error);
|
|
718
943
|
}
|
|
719
|
-
return { documentId: parts.join(":"), documentRevision: revision };
|
|
720
|
-
}
|
|
721
|
-
/**
|
|
722
|
-
* Create a full identifier for a document.
|
|
723
|
-
* @param documentCode The document code.
|
|
724
|
-
* @param documentId The document identifier.
|
|
725
|
-
* @param documentRevision The document revision.
|
|
726
|
-
* @returns The full identifier.
|
|
727
|
-
* @internal
|
|
728
|
-
*/
|
|
729
|
-
createIdentifier(documentCode, documentId, documentRevision) {
|
|
730
|
-
const docCode = this.parseDocumentCode(documentCode);
|
|
731
|
-
return `documents:${docCode}:${this.encodeDocumentIdentifier(documentId, documentRevision)}`;
|
|
732
944
|
}
|
|
733
945
|
/**
|
|
734
|
-
*
|
|
735
|
-
* @param
|
|
736
|
-
* @
|
|
946
|
+
* Update the edges of the document vertex.
|
|
947
|
+
* @param documentVertex The document vertex to update.
|
|
948
|
+
* @param auditableItemGraphEdges The list of edges to use.
|
|
949
|
+
* @returns True if the edges were updated.
|
|
737
950
|
* @internal
|
|
738
951
|
*/
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
const
|
|
742
|
-
if (
|
|
743
|
-
|
|
952
|
+
updateEdges(documentVertex, auditableItemGraphEdges) {
|
|
953
|
+
let changed = false;
|
|
954
|
+
const existingEdgeIds = documentVertex.edges?.map(e => e.id) ?? [];
|
|
955
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
956
|
+
for (const aigEdge of auditableItemGraphEdges) {
|
|
957
|
+
const existingIndex = existingEdgeIds.indexOf(aigEdge.id);
|
|
958
|
+
if (existingIndex !== -1) {
|
|
959
|
+
// If the edge already exists then we don't need to add it again
|
|
960
|
+
// We just need to remove it from the list of existing ids
|
|
961
|
+
// any remaining after this loop will be need to be removed
|
|
962
|
+
existingEdgeIds.splice(existingIndex, 1);
|
|
963
|
+
}
|
|
964
|
+
else {
|
|
965
|
+
const vertexEdge = {
|
|
966
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
967
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Edge,
|
|
968
|
+
id: aigEdge.id,
|
|
969
|
+
edgeRelationships: ["document"]
|
|
970
|
+
};
|
|
971
|
+
documentVertex.edges ??= [];
|
|
972
|
+
documentVertex.edges?.push(vertexEdge);
|
|
973
|
+
changed = true;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
// Anything left in the existingEdgeIds array means they need to be removed
|
|
977
|
+
if (existingEdgeIds.length > 0 && core.Is.array(documentVertex.edges)) {
|
|
978
|
+
for (const existingEdgeId of existingEdgeIds) {
|
|
979
|
+
const existingIndex = documentVertex.edges.findIndex(e => e.id === existingEdgeId);
|
|
980
|
+
if (existingIndex !== -1) {
|
|
981
|
+
documentVertex.edges.splice(existingIndex, 1);
|
|
982
|
+
changed = true;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
744
986
|
}
|
|
745
|
-
|
|
746
|
-
const { documentId, documentRevision } = this.decodeDocumentIdentifier(urn.namespaceSpecific(1));
|
|
747
|
-
return { documentCode, documentId, documentRevision };
|
|
987
|
+
return changed;
|
|
748
988
|
}
|
|
749
989
|
/**
|
|
750
|
-
*
|
|
751
|
-
* @param
|
|
752
|
-
* @
|
|
990
|
+
* Update the edges.
|
|
991
|
+
* @param connectedVertices The connected vertices for the edges.
|
|
992
|
+
* @param auditableItemGraphDocumentId The document id to use.
|
|
993
|
+
* @param documentVertex The document vertex to update.
|
|
994
|
+
* @param auditableItemGraphEdges The list of edges to use.
|
|
995
|
+
* @param documentId The document identifier.
|
|
996
|
+
* @param documentIdFormat The format of the document identifier.
|
|
997
|
+
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
998
|
+
* @param nodeIdentity The node identity to use for vault operations.
|
|
753
999
|
* @internal
|
|
754
1000
|
*/
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
1001
|
+
async updateConnectedEdges(connectedVertices, auditableItemGraphDocumentId, existingEdgeIds, auditableItemGraphEdges, documentId, documentIdFormat, userIdentity, nodeIdentity) {
|
|
1002
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
1003
|
+
for (const aigEdge of auditableItemGraphEdges) {
|
|
1004
|
+
const connected = connectedVertices[aigEdge.id];
|
|
1005
|
+
if (!core.Is.empty(connected)) {
|
|
1006
|
+
let updatedConnected = false;
|
|
1007
|
+
const existingIndex = existingEdgeIds.indexOf(aigEdge.id);
|
|
1008
|
+
if (existingIndex !== -1) {
|
|
1009
|
+
// If the edge already exists we remove it from the list of existing ids
|
|
1010
|
+
// any remaining after this loop will be need to be disconnected
|
|
1011
|
+
existingEdgeIds.splice(existingIndex, 1);
|
|
1012
|
+
}
|
|
1013
|
+
// Add the edge with the document vertex id if it doesn't already exist
|
|
1014
|
+
const hasEdge = connected.edges?.some(e => e.id === auditableItemGraphDocumentId);
|
|
1015
|
+
if (!hasEdge) {
|
|
1016
|
+
const vertexEdge = {
|
|
1017
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
1018
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Edge,
|
|
1019
|
+
id: auditableItemGraphDocumentId,
|
|
1020
|
+
edgeRelationships: ["document"]
|
|
1021
|
+
};
|
|
1022
|
+
connected.edges ??= [];
|
|
1023
|
+
connected.edges?.push(vertexEdge);
|
|
1024
|
+
updatedConnected = true;
|
|
1025
|
+
}
|
|
1026
|
+
// Add alias with the document id if option flag is set and it doesn't already exist
|
|
1027
|
+
if (aigEdge.addAlias) {
|
|
1028
|
+
const alias = connected.aliases?.find(a => a.id === documentId);
|
|
1029
|
+
if (core.Is.empty(alias)) {
|
|
1030
|
+
// No existing alias, so create one
|
|
1031
|
+
const vertexAlias = {
|
|
1032
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
1033
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
1034
|
+
id: documentId,
|
|
1035
|
+
aliasFormat: documentIdFormat,
|
|
1036
|
+
annotationObject: aigEdge.aliasAnnotationObject
|
|
1037
|
+
};
|
|
1038
|
+
connected.aliases ??= [];
|
|
1039
|
+
connected.aliases?.push(vertexAlias);
|
|
1040
|
+
updatedConnected = true;
|
|
1041
|
+
}
|
|
1042
|
+
else if (!core.ObjectHelper.equal(alias.annotationObject, aigEdge.aliasAnnotationObject) ||
|
|
1043
|
+
documentIdFormat !== alias.aliasFormat) {
|
|
1044
|
+
// The alias already exists, but the format or annotation object has changed
|
|
1045
|
+
alias.annotationObject = aigEdge.aliasAnnotationObject;
|
|
1046
|
+
alias.aliasFormat = documentIdFormat;
|
|
1047
|
+
updatedConnected = true;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
if (updatedConnected) {
|
|
1051
|
+
await this._auditableItemGraphComponent.update(connected, userIdentity, nodeIdentity);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
760
1055
|
}
|
|
761
|
-
|
|
762
|
-
if (
|
|
763
|
-
|
|
1056
|
+
// Anything left in the existingEdgeIds array means they need to be removed
|
|
1057
|
+
if (existingEdgeIds.length > 0) {
|
|
1058
|
+
for (const existingEdgeId of existingEdgeIds) {
|
|
1059
|
+
const connected = connectedVertices[existingEdgeId];
|
|
1060
|
+
if (!core.Is.empty(connected)) {
|
|
1061
|
+
let updatedConnected = false;
|
|
1062
|
+
// Remove the edge from the connected vertex
|
|
1063
|
+
if (core.Is.arrayValue(connected.edges)) {
|
|
1064
|
+
const existingIndex = connected.edges.findIndex(e => e.id === auditableItemGraphDocumentId);
|
|
1065
|
+
if (existingIndex !== -1) {
|
|
1066
|
+
connected.edges.splice(existingIndex, 1);
|
|
1067
|
+
updatedConnected = true;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
// Remove the alias from the connected vertex
|
|
1071
|
+
if (core.Is.arrayValue(connected.aliases)) {
|
|
1072
|
+
const existingIndex = connected.aliases.findIndex(e => e.id === documentId);
|
|
1073
|
+
if (existingIndex !== -1) {
|
|
1074
|
+
connected.aliases.splice(existingIndex, 1);
|
|
1075
|
+
updatedConnected = true;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
if (updatedConnected) {
|
|
1079
|
+
await this._auditableItemGraphComponent.update(connected, userIdentity, nodeIdentity);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
764
1083
|
}
|
|
765
|
-
return docCode;
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Get the documents from a vertex.
|
|
769
|
-
* @param vertex The vertex to get the documents from.
|
|
770
|
-
* @returns The documents.
|
|
771
|
-
* @internal
|
|
772
|
-
*/
|
|
773
|
-
filterDocumentsFromVertex(vertex) {
|
|
774
|
-
return (vertex.resources
|
|
775
|
-
?.filter(resource => core.ObjectHelper.extractProperty(resource.resourceObject, ["@type", "type"], false) ===
|
|
776
|
-
documentManagementModels.DocumentTypes.Document)
|
|
777
|
-
.map(resource => resource.resourceObject) ?? []);
|
|
778
|
-
}
|
|
779
|
-
/**
|
|
780
|
-
* Find matching documents in the list of existing documents.
|
|
781
|
-
* @param documents The documents to search.
|
|
782
|
-
* @param documentId The document id.
|
|
783
|
-
* @param documentCode The document code.
|
|
784
|
-
* @param includeRemoved Include deleted documents.
|
|
785
|
-
* @returns The matching documents.
|
|
786
|
-
* @internal
|
|
787
|
-
*/
|
|
788
|
-
findMatchingDocs(documents, documentId, documentCode, includeRemoved) {
|
|
789
|
-
return documents
|
|
790
|
-
.filter(d => d.documentId === documentId &&
|
|
791
|
-
d.documentCode === documentCode &&
|
|
792
|
-
(includeRemoved || core.Is.empty(d.dateDeleted)))
|
|
793
|
-
.sort((a, b) => b.documentRevision - a.documentRevision);
|
|
794
1084
|
}
|
|
795
1085
|
/**
|
|
796
1086
|
* Generate a hash for the blob data.
|
|
@@ -803,64 +1093,145 @@ class DocumentManagementService {
|
|
|
803
1093
|
}
|
|
804
1094
|
/**
|
|
805
1095
|
* Get the documents from the auditable item graph vertex.
|
|
806
|
-
* @param
|
|
807
|
-
* @param identifier The full document identifier.
|
|
1096
|
+
* @param documentVertex The vertex containing the documents.
|
|
808
1097
|
* @param options Additional options for the get operation.
|
|
809
1098
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
810
1099
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
811
1100
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
812
|
-
* @param options.
|
|
813
|
-
* @param options.
|
|
814
|
-
* @param
|
|
1101
|
+
* @param options.extractRuleGroupId If provided will extract data from the document using the specified rule group id.
|
|
1102
|
+
* @param options.extractMimeType By default extraction will auto detect the mime type of the document, this can be used to override the detection.
|
|
1103
|
+
* @param cursor The cursor to get the next chunk of revisions.
|
|
1104
|
+
* @param pageSize Page size of items to return, defaults to 1 so only most recent is returned.
|
|
815
1105
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
816
1106
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
817
1107
|
* @returns The finalised list of documents.
|
|
818
1108
|
* @internal
|
|
819
1109
|
*/
|
|
820
|
-
async
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
1110
|
+
async getDocumentsFromVertex(documentVertex, options, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
1111
|
+
const docList = {
|
|
1112
|
+
"@context": [
|
|
1113
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot,
|
|
1114
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
1115
|
+
documentManagementModels.DocumentContexts.ContextRootCommon
|
|
1116
|
+
],
|
|
1117
|
+
type: standardsSchemaOrg.SchemaOrgTypes.ItemList,
|
|
1118
|
+
[standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: []
|
|
1119
|
+
};
|
|
1120
|
+
if (core.Is.arrayValue(documentVertex.resources)) {
|
|
1121
|
+
// Sort by newest revision first
|
|
1122
|
+
documentVertex.resources.sort((a, b) => (core.Coerce.number(b.resourceObject?.documentRevision) ?? 0) -
|
|
1123
|
+
(core.Coerce.number(a.resourceObject?.documentRevision) ?? 0));
|
|
1124
|
+
const startIndex = core.Coerce.integer(cursor) ?? 0;
|
|
1125
|
+
const endIndex = Math.min(startIndex + (pageSize ?? 1), documentVertex.resources.length);
|
|
1126
|
+
const slicedResources = documentVertex.resources.slice(startIndex, endIndex);
|
|
1127
|
+
docList[standardsSchemaOrg.SchemaOrgTypes.NextItem] =
|
|
1128
|
+
documentVertex.resources.length > endIndex ? (endIndex + 1).toString() : undefined;
|
|
1129
|
+
const includeBlobStorageMetadata = options?.includeBlobStorageMetadata ?? false;
|
|
1130
|
+
const includeBlobStorageData = options?.includeBlobStorageData ?? false;
|
|
1131
|
+
const includeAttestation = options?.includeAttestation ?? false;
|
|
1132
|
+
const extractData = core.Is.stringValue(options?.extractRuleGroupId);
|
|
1133
|
+
for (let i = 0; i < slicedResources.length; i++) {
|
|
1134
|
+
const document = slicedResources[i].resourceObject;
|
|
1135
|
+
if (core.Is.object(document)) {
|
|
1136
|
+
document.dateDeleted = slicedResources[i].dateDeleted;
|
|
1137
|
+
docList[standardsSchemaOrg.SchemaOrgTypes.ItemListElement].push(document);
|
|
1138
|
+
const blobRequired = includeBlobStorageMetadata || includeBlobStorageData;
|
|
1139
|
+
if (blobRequired || extractData) {
|
|
1140
|
+
const blobEntry = await this._blobStorageComponent.get(document.blobStorageId, {
|
|
1141
|
+
includeContent: includeBlobStorageData || extractData
|
|
1142
|
+
}, userIdentity, nodeIdentity);
|
|
1143
|
+
if (blobRequired) {
|
|
1144
|
+
document.blobStorageEntry = blobEntry;
|
|
1145
|
+
if (!docList["@context"].includes(blobStorageModels.BlobStorageContexts.ContextRoot)) {
|
|
1146
|
+
docList["@context"].push(blobStorageModels.BlobStorageContexts.ContextRoot);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (core.Is.stringValue(options?.extractRuleGroupId) && core.Is.stringValue(blobEntry.blob)) {
|
|
1150
|
+
const binaryBlob = core.Converter.base64ToBytes(blobEntry.blob);
|
|
1151
|
+
document.extractedData = await this._dataProcessingComponent.extract(options.extractRuleGroupId, binaryBlob, undefined, options?.extractMimeType);
|
|
1152
|
+
}
|
|
1153
|
+
// If we have the blob data due to extraction but we weren't asked for it
|
|
1154
|
+
// then we remove it from the document
|
|
1155
|
+
if (!blobRequired) {
|
|
1156
|
+
delete document.blobStorageEntry;
|
|
1157
|
+
}
|
|
1158
|
+
else if (!includeBlobStorageData) {
|
|
1159
|
+
delete document.blobStorageEntry?.blob;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
if (includeAttestation && core.Is.stringValue(document.attestationId)) {
|
|
1163
|
+
const attestationInformation = await this._attestationComponent.get(document.attestationId);
|
|
1164
|
+
document.attestationInformation = attestationInformation;
|
|
1165
|
+
if (!docList["@context"].includes(attestationModels.AttestationContexts.ContextRoot)) {
|
|
1166
|
+
docList["@context"].push(attestationModels.AttestationContexts.ContextRoot);
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
838
1171
|
}
|
|
839
|
-
if (
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
1172
|
+
if (core.Is.arrayValue(documentVertex.edges)) {
|
|
1173
|
+
docList.edges ??= [];
|
|
1174
|
+
for (const edge of documentVertex.edges) {
|
|
1175
|
+
if (core.Is.object(edge)) {
|
|
1176
|
+
docList.edges.push(edge.id);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
843
1179
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1180
|
+
return docList;
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Create an attestation for the document.
|
|
1184
|
+
* @param document The document to create the attestation for.
|
|
1185
|
+
* @param userIdentity The identity to perform the attestation operation with.
|
|
1186
|
+
* @param nodeIdentity The node identity to perform attestation operation with.
|
|
1187
|
+
* @returns The attestation identifier.
|
|
1188
|
+
*/
|
|
1189
|
+
async createAttestation(document, userIdentity, nodeIdentity) {
|
|
1190
|
+
const documentAttestation = {
|
|
1191
|
+
"@context": [
|
|
1192
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
1193
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
1194
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
1195
|
+
],
|
|
1196
|
+
type: documentManagementModels.DocumentTypes.DocumentAttestation,
|
|
1197
|
+
id: document.id,
|
|
1198
|
+
documentId: document.documentId,
|
|
1199
|
+
documentCode: document.documentCode,
|
|
1200
|
+
documentRevision: document.documentRevision,
|
|
1201
|
+
dateCreated: document.dateCreated,
|
|
1202
|
+
blobHash: document.blobHash
|
|
1203
|
+
};
|
|
1204
|
+
return this._attestationComponent.create(documentAttestation, undefined, userIdentity, nodeIdentity);
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* Create a document id from the document id and revision.
|
|
1208
|
+
* @param documentId The document id to create.
|
|
1209
|
+
* @param revision The revision of the document.
|
|
1210
|
+
* @returns The document id.
|
|
1211
|
+
* @internal
|
|
1212
|
+
*/
|
|
1213
|
+
createDocumentId(documentId, revision) {
|
|
1214
|
+
const documentIdHash = core.Converter.bytesToBase64Url(crypto.Sha256.sum256(core.Converter.utf8ToBytes(documentId)));
|
|
1215
|
+
return `document:${documentIdHash}:${revision}`;
|
|
847
1216
|
}
|
|
848
1217
|
}
|
|
849
1218
|
|
|
850
1219
|
const restEntryPoints = [
|
|
851
1220
|
{
|
|
852
|
-
name: "
|
|
853
|
-
defaultBaseRoute: "
|
|
1221
|
+
name: "document-management",
|
|
1222
|
+
defaultBaseRoute: "document-management",
|
|
854
1223
|
tags: tagsDocumentManagement,
|
|
855
1224
|
generateRoutes: generateRestRoutesDocumentManagement
|
|
856
1225
|
}
|
|
857
1226
|
];
|
|
858
1227
|
|
|
859
1228
|
exports.DocumentManagementService = DocumentManagementService;
|
|
1229
|
+
exports.documentManagementCreate = documentManagementCreate;
|
|
860
1230
|
exports.documentManagementGet = documentManagementGet;
|
|
1231
|
+
exports.documentManagementGetRevision = documentManagementGetRevision;
|
|
861
1232
|
exports.documentManagementQuery = documentManagementQuery;
|
|
862
1233
|
exports.documentManagementRemove = documentManagementRemove;
|
|
863
|
-
exports.
|
|
1234
|
+
exports.documentManagementUpdate = documentManagementUpdate;
|
|
864
1235
|
exports.generateRestRoutesDocumentManagement = generateRestRoutesDocumentManagement;
|
|
865
1236
|
exports.restEntryPoints = restEntryPoints;
|
|
866
1237
|
exports.tagsDocumentManagement = tagsDocumentManagement;
|