@twin.org/document-management-service 0.0.1-next.8 → 0.0.1
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 +728 -428
- package/dist/esm/index.mjs +728 -430
- package/dist/types/documentManagementRoutes.d.ts +20 -4
- package/dist/types/documentManagementService.d.ts +71 -36
- package/dist/types/models/IDocumentManagementStorageServiceConstructorOptions.d.ts +5 -0
- package/docs/changelog.md +195 -0
- package/docs/open-api/spec.json +609 -1470
- package/docs/reference/classes/DocumentManagementService.md +179 -63
- 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 +73 -15
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,14 +65,56 @@ 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"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
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"
|
|
79
102
|
}
|
|
80
103
|
}
|
|
81
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
|
+
}
|
|
82
118
|
]
|
|
83
119
|
}
|
|
84
120
|
]
|
|
@@ -88,7 +124,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
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
|
}
|
|
@@ -110,6 +145,120 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
110
145
|
examples: [
|
|
111
146
|
{
|
|
112
147
|
id: "DocumentManagementGetResponseExample",
|
|
148
|
+
response: {
|
|
149
|
+
body: {
|
|
150
|
+
"@context": [
|
|
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",
|
|
113
262
|
response: {
|
|
114
263
|
body: {
|
|
115
264
|
"@context": [
|
|
@@ -118,11 +267,11 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
118
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",
|
|
@@ -139,11 +288,11 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
139
288
|
]
|
|
140
289
|
},
|
|
141
290
|
{
|
|
142
|
-
type: "
|
|
291
|
+
type: "IDocumentManagementGetRevisionResponse",
|
|
143
292
|
mimeType: web.MimeTypes.JsonLd,
|
|
144
293
|
examples: [
|
|
145
294
|
{
|
|
146
|
-
id: "
|
|
295
|
+
id: "DocumentManagementGetRevisionResponseExample",
|
|
147
296
|
response: {
|
|
148
297
|
body: {
|
|
149
298
|
"@context": [
|
|
@@ -152,11 +301,11 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
152
301
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
153
302
|
],
|
|
154
303
|
type: documentManagementModels.DocumentTypes.Document,
|
|
155
|
-
id: "
|
|
304
|
+
id: "2721000:0",
|
|
156
305
|
documentId: "2721000",
|
|
157
306
|
documentIdFormat: "bol",
|
|
158
307
|
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
159
|
-
documentRevision:
|
|
308
|
+
documentRevision: 1,
|
|
160
309
|
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
161
310
|
blobHash: "sha256:123456",
|
|
162
311
|
dateCreated: "2024-01-01T00:00:00Z",
|
|
@@ -177,12 +326,12 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
177
326
|
}
|
|
178
327
|
]
|
|
179
328
|
};
|
|
180
|
-
const
|
|
329
|
+
const documentManagementRemoveRevisionRoute = {
|
|
181
330
|
operationId: "DocumentManagementRemove",
|
|
182
331
|
summary: "Remove an document from an auditable item graph vertex",
|
|
183
332
|
tag: tagsDocumentManagement[0].name,
|
|
184
333
|
method: "DELETE",
|
|
185
|
-
path: `${baseRouteName}/:
|
|
334
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId/:revision`,
|
|
186
335
|
handler: async (httpRequestContext, request) => documentManagementRemove(httpRequestContext, componentName, request),
|
|
187
336
|
requestType: {
|
|
188
337
|
type: "IDocumentManagementRemoveRequest",
|
|
@@ -191,8 +340,8 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
191
340
|
id: "DocumentManagementRemoveRequestExample",
|
|
192
341
|
request: {
|
|
193
342
|
pathParams: {
|
|
194
|
-
|
|
195
|
-
|
|
343
|
+
auditableItemGraphDocumentId: "aig:1234",
|
|
344
|
+
revision: "1"
|
|
196
345
|
}
|
|
197
346
|
}
|
|
198
347
|
}
|
|
@@ -212,7 +361,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
212
361
|
summary: "Query the items from an auditable item graph vertex",
|
|
213
362
|
tag: tagsDocumentManagement[0].name,
|
|
214
363
|
method: "GET",
|
|
215
|
-
path: `${baseRouteName}
|
|
364
|
+
path: `${baseRouteName}/`,
|
|
216
365
|
handler: async (httpRequestContext, request) => documentManagementQuery(httpRequestContext, componentName, request),
|
|
217
366
|
requestType: {
|
|
218
367
|
type: "IDocumentManagementQueryRequest",
|
|
@@ -220,8 +369,8 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
220
369
|
{
|
|
221
370
|
id: "DocumentManagementQueryRequestExample",
|
|
222
371
|
request: {
|
|
223
|
-
|
|
224
|
-
|
|
372
|
+
query: {
|
|
373
|
+
documentId: "2721000"
|
|
225
374
|
}
|
|
226
375
|
}
|
|
227
376
|
}
|
|
@@ -235,71 +384,54 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
235
384
|
id: "DocumentManagementQueryResponseExample",
|
|
236
385
|
response: {
|
|
237
386
|
body: {
|
|
238
|
-
"@context": [
|
|
239
|
-
type:
|
|
240
|
-
|
|
387
|
+
"@context": [standardsSchemaOrg.SchemaOrgContexts.ContextRoot, auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot],
|
|
388
|
+
type: [standardsSchemaOrg.SchemaOrgTypes.ItemList, auditableItemGraphModels.AuditableItemGraphTypes.VertexList],
|
|
389
|
+
[standardsSchemaOrg.SchemaOrgTypes.ItemListElement]: [
|
|
241
390
|
{
|
|
242
391
|
"@context": [
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
392
|
+
auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
393
|
+
auditableItemGraphModels.AuditableItemGraphContexts.ContextRootCommon
|
|
246
394
|
],
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
"@context": "https://schema.org",
|
|
258
|
-
"@type": "DigitalDocument",
|
|
259
|
-
name: "myfile.pdf"
|
|
260
|
-
},
|
|
261
|
-
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
262
|
-
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
263
|
-
}
|
|
264
|
-
]
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
]
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
type: "IDocumentManagementQueryResponse",
|
|
272
|
-
mimeType: web.MimeTypes.JsonLd,
|
|
273
|
-
examples: [
|
|
274
|
-
{
|
|
275
|
-
id: "DocumentManagementListResponseJsonLdExample",
|
|
276
|
-
response: {
|
|
277
|
-
body: {
|
|
278
|
-
"@context": [documentManagementModels.DocumentContexts.ContextRoot, documentManagementModels.DocumentContexts.ContextRootCommon],
|
|
279
|
-
type: documentManagementModels.DocumentTypes.DocumentList,
|
|
280
|
-
documents: [
|
|
281
|
-
{
|
|
282
|
-
"@context": [
|
|
283
|
-
documentManagementModels.DocumentContexts.ContextRoot,
|
|
284
|
-
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
285
|
-
standardsSchemaOrg.SchemaOrgContexts.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
|
+
}
|
|
286
405
|
],
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
+
]
|
|
303
435
|
}
|
|
304
436
|
]
|
|
305
437
|
}
|
|
@@ -310,29 +442,29 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
310
442
|
]
|
|
311
443
|
};
|
|
312
444
|
return [
|
|
313
|
-
|
|
445
|
+
documentManagementCreateRoute,
|
|
446
|
+
documentManagementUpdateRoute,
|
|
314
447
|
documentManagementGetRoute,
|
|
315
|
-
|
|
448
|
+
documentManagementGetRevisionRoute,
|
|
449
|
+
documentManagementRemoveRevisionRoute,
|
|
316
450
|
documentManagementQueryRoute
|
|
317
451
|
];
|
|
318
452
|
}
|
|
319
453
|
/**
|
|
320
|
-
*
|
|
454
|
+
* Create a document as an auditable item graph vertex.
|
|
321
455
|
* @param httpRequestContext The request context for the API.
|
|
322
456
|
* @param componentName The name of the component to use in the routes.
|
|
323
457
|
* @param request The request.
|
|
324
458
|
* @returns The response object with additional http response properties.
|
|
325
459
|
*/
|
|
326
|
-
async function
|
|
460
|
+
async function documentManagementCreate(httpRequestContext, componentName, request) {
|
|
327
461
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
328
|
-
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
329
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphId", request.pathParams.auditableItemGraphId);
|
|
330
462
|
core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
|
|
331
463
|
core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
|
|
332
464
|
const component = core.ComponentFactory.get(componentName);
|
|
333
|
-
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, {
|
|
334
466
|
createAttestation: request.body.createAttestation,
|
|
335
|
-
|
|
467
|
+
addAlias: request.body.addAlias,
|
|
336
468
|
aliasAnnotationObject: request.body.aliasAnnotationObject
|
|
337
469
|
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
338
470
|
return {
|
|
@@ -352,17 +484,17 @@ async function documentManagementSet(httpRequestContext, componentName, request)
|
|
|
352
484
|
async function documentManagementGet(httpRequestContext, componentName, request) {
|
|
353
485
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
354
486
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
355
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.
|
|
356
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.documentId", request.pathParams.documentId);
|
|
487
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
357
488
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
358
489
|
const component = core.ComponentFactory.get(componentName);
|
|
359
|
-
const result = await component.get(request.pathParams.
|
|
490
|
+
const result = await component.get(request.pathParams.auditableItemGraphDocumentId, {
|
|
360
491
|
includeBlobStorageMetadata: core.Coerce.boolean(request.query?.includeBlobStorageMetadata),
|
|
361
492
|
includeBlobStorageData: core.Coerce.boolean(request.query?.includeBlobStorageData),
|
|
362
493
|
includeAttestation: core.Coerce.boolean(request.query?.includeAttestation),
|
|
363
494
|
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved),
|
|
364
|
-
|
|
365
|
-
|
|
495
|
+
extractRuleGroupId: request.query?.extractRuleGroupId,
|
|
496
|
+
extractMimeType: request.query?.extractMimeType
|
|
497
|
+
}, request.query?.cursor, core.Coerce.integer(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
366
498
|
return {
|
|
367
499
|
headers: {
|
|
368
500
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -370,6 +502,52 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
370
502
|
body: result
|
|
371
503
|
};
|
|
372
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);
|
|
527
|
+
return {
|
|
528
|
+
headers: {
|
|
529
|
+
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
530
|
+
},
|
|
531
|
+
body: result
|
|
532
|
+
};
|
|
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
|
+
}
|
|
373
551
|
/**
|
|
374
552
|
* Remove the document from the auditable item graph vertex.
|
|
375
553
|
* @param httpRequestContext The request context for the API.
|
|
@@ -380,12 +558,11 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
380
558
|
async function documentManagementRemove(httpRequestContext, componentName, request) {
|
|
381
559
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
382
560
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
383
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.
|
|
384
|
-
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);
|
|
385
564
|
const component = core.ComponentFactory.get(componentName);
|
|
386
|
-
await component.
|
|
387
|
-
removeAllRevisions: request.query?.removeAllRevisions
|
|
388
|
-
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
565
|
+
await component.removeRevision(request.pathParams.auditableItemGraphDocumentId, revision, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
389
566
|
return {
|
|
390
567
|
statusCode: web.HttpStatusCode.noContent
|
|
391
568
|
};
|
|
@@ -399,14 +576,11 @@ async function documentManagementRemove(httpRequestContext, componentName, reque
|
|
|
399
576
|
*/
|
|
400
577
|
async function documentManagementQuery(httpRequestContext, componentName, request) {
|
|
401
578
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
402
|
-
core.Guards.object(ROUTES_SOURCE, "request.
|
|
403
|
-
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);
|
|
404
581
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
405
582
|
const component = core.ComponentFactory.get(componentName);
|
|
406
|
-
const result = await component.query(request.
|
|
407
|
-
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved),
|
|
408
|
-
includeMostRecentRevisions: core.Coerce.boolean(request.query?.includeMostRecentRevisions)
|
|
409
|
-
}, 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);
|
|
410
584
|
return {
|
|
411
585
|
headers: {
|
|
412
586
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -423,11 +597,6 @@ class DocumentManagementService {
|
|
|
423
597
|
* The namespace supported by the document management service.
|
|
424
598
|
*/
|
|
425
599
|
static NAMESPACE = "documents";
|
|
426
|
-
/**
|
|
427
|
-
* Default Page Size for cursor.
|
|
428
|
-
* @internal
|
|
429
|
-
*/
|
|
430
|
-
static _DEFAULT_PAGE_SIZE = 20;
|
|
431
600
|
/**
|
|
432
601
|
* Runtime name for the class.
|
|
433
602
|
*/
|
|
@@ -447,6 +616,11 @@ class DocumentManagementService {
|
|
|
447
616
|
* @internal
|
|
448
617
|
*/
|
|
449
618
|
_attestationComponent;
|
|
619
|
+
/**
|
|
620
|
+
* The connector for the data processing.
|
|
621
|
+
* @internal
|
|
622
|
+
*/
|
|
623
|
+
_dataProcessingComponent;
|
|
450
624
|
/**
|
|
451
625
|
* Create a new instance of DocumentManagementService.
|
|
452
626
|
* @param options The options for the service.
|
|
@@ -455,169 +629,218 @@ class DocumentManagementService {
|
|
|
455
629
|
this._auditableItemGraphComponent = core.ComponentFactory.get(options?.auditableItemGraphComponentType ?? "auditable-item-graph");
|
|
456
630
|
this._blobStorageComponent = core.ComponentFactory.get(options?.blobStorageComponentType ?? "blob-storage");
|
|
457
631
|
this._attestationComponent = core.ComponentFactory.get(options?.attestationComponentType ?? "attestation");
|
|
632
|
+
this._dataProcessingComponent = core.ComponentFactory.get(options?.dataProcessingComponentType ?? "data-processing");
|
|
458
633
|
standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
|
|
459
634
|
}
|
|
460
635
|
/**
|
|
461
|
-
* Store a document
|
|
636
|
+
* Store a document as an auditable item graph vertex and add its content to blob storage.
|
|
462
637
|
* If the document id already exists and the blob data is different a new revision will be created.
|
|
463
638
|
* For any other changes the current revision will be updated.
|
|
464
|
-
* @param auditableItemGraphId The auditable item graph vertex id to create the document on.
|
|
465
639
|
* @param documentId The document id to create.
|
|
466
640
|
* @param documentIdFormat The format of the document identifier.
|
|
467
641
|
* @param documentCode The code for the document type.
|
|
468
|
-
* @param blob The data to create the document.
|
|
642
|
+
* @param blob The data to create the document with.
|
|
469
643
|
* @param annotationObject Additional information to associate with the document.
|
|
644
|
+
* @param auditableItemGraphEdges The auditable item graph vertices to connect the document to.
|
|
470
645
|
* @param options Additional options for the set operation.
|
|
471
646
|
* @param options.createAttestation Flag to create an attestation for the document, defaults to false.
|
|
472
|
-
* @param options.
|
|
473
|
-
* @param options.aliasAnnotationObject
|
|
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.
|
|
474
649
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
475
650
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
476
|
-
* @returns The
|
|
651
|
+
* @returns The auditable item graph vertex created for the document including its revision.
|
|
477
652
|
*/
|
|
478
|
-
async
|
|
479
|
-
core.Guards.stringValue(this.CLASS_NAME, "auditableItemGraphId", auditableItemGraphId);
|
|
653
|
+
async create(documentId, documentIdFormat, documentCode, blob, annotationObject, auditableItemGraphEdges, options, userIdentity, nodeIdentity) {
|
|
480
654
|
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
481
655
|
core.Guards.arrayOneOf(this.CLASS_NAME, "documentCode", documentCode, Object.values(standardsUnece.UneceDocumentCodes));
|
|
482
656
|
core.Guards.uint8Array(this.CLASS_NAME, "blob", blob);
|
|
483
657
|
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
484
658
|
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
485
659
|
try {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (found) {
|
|
492
|
-
found.annotationObject = options?.aliasAnnotationObject ?? found.annotationObject;
|
|
493
|
-
found.aliasFormat = documentIdFormat ?? found.aliasFormat;
|
|
494
|
-
}
|
|
495
|
-
else {
|
|
496
|
-
vertex.aliases.push({
|
|
497
|
-
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
498
|
-
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
499
|
-
id: documentId,
|
|
500
|
-
aliasFormat: documentIdFormat,
|
|
501
|
-
annotationObject: options?.aliasAnnotationObject
|
|
502
|
-
});
|
|
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);
|
|
503
665
|
}
|
|
504
666
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
// Calculate the hash for the blob.
|
|
517
|
-
const blobHash = this.generateBlobHash(blob);
|
|
518
|
-
// Is the blob data the same as the current revision ?
|
|
519
|
-
if (currentRevision?.blobHash === blobHash) {
|
|
520
|
-
// Blob data matches so no need to create a new revision
|
|
521
|
-
// We update the current object if the annotation or createAttestation flag has changed.
|
|
522
|
-
let updated = false;
|
|
523
|
-
if (!core.ObjectHelper.equal(currentRevision.annotationObject, annotationObject, false)) {
|
|
524
|
-
currentRevision.annotationObject = annotationObject;
|
|
525
|
-
updated = true;
|
|
526
|
-
}
|
|
527
|
-
if (createAttestation && core.Is.empty(currentRevision.attestationId)) {
|
|
528
|
-
currentRevision.attestationId = await this.createAttestation(currentRevision, userIdentity, nodeIdentity);
|
|
529
|
-
updated = true;
|
|
530
|
-
}
|
|
531
|
-
if (updated) {
|
|
532
|
-
currentRevision.dateModified = new Date(Date.now()).toISOString();
|
|
533
|
-
await this._auditableItemGraphComponent.update(vertex, userIdentity, nodeIdentity);
|
|
534
|
-
}
|
|
535
|
-
return currentRevision.id;
|
|
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
|
+
});
|
|
536
677
|
}
|
|
537
|
-
//
|
|
678
|
+
// Add the blob to blob storage
|
|
538
679
|
const blobStorageId = await this._blobStorageComponent.create(core.Converter.bytesToBase64(blob), undefined, undefined, undefined, undefined, userIdentity, nodeIdentity);
|
|
539
|
-
const
|
|
540
|
-
// We are creating a new document, if there is already docs with the same id and code we use the list length
|
|
541
|
-
// to determine the next revision number.
|
|
542
|
-
const document = {
|
|
680
|
+
const currentRevision = {
|
|
543
681
|
"@context": [
|
|
544
682
|
documentManagementModels.DocumentContexts.ContextRoot,
|
|
545
683
|
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
546
684
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
547
685
|
],
|
|
548
686
|
type: documentManagementModels.DocumentTypes.Document,
|
|
549
|
-
id: this.
|
|
687
|
+
id: this.createDocumentId(documentId, 0),
|
|
550
688
|
documentId,
|
|
551
689
|
documentIdFormat,
|
|
552
690
|
documentCode,
|
|
553
|
-
documentRevision,
|
|
554
|
-
blobStorageId,
|
|
555
|
-
blobHash,
|
|
691
|
+
documentRevision: 0,
|
|
556
692
|
annotationObject,
|
|
693
|
+
blobHash: this.generateBlobHash(blob),
|
|
694
|
+
blobStorageId,
|
|
557
695
|
dateCreated: new Date(Date.now()).toISOString(),
|
|
558
696
|
nodeIdentity,
|
|
559
697
|
userIdentity
|
|
560
698
|
};
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
document.attestationId = await this.createAttestation(document, userIdentity, nodeIdentity);
|
|
699
|
+
if (options?.createAttestation ?? false) {
|
|
700
|
+
currentRevision.attestationId = await this.createAttestation(currentRevision, userIdentity, nodeIdentity);
|
|
564
701
|
}
|
|
565
|
-
// Add the new revision in to the
|
|
566
|
-
|
|
702
|
+
// Add the new revision in to the vertex
|
|
703
|
+
documentVertex.resources ??= [];
|
|
704
|
+
documentVertex.resources.push({
|
|
567
705
|
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
568
706
|
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
569
|
-
resourceObject:
|
|
707
|
+
resourceObject: currentRevision
|
|
570
708
|
});
|
|
571
|
-
|
|
572
|
-
|
|
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;
|
|
573
716
|
}
|
|
574
717
|
catch (error) {
|
|
575
718
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
576
719
|
throw error;
|
|
577
720
|
}
|
|
578
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
721
|
+
throw new core.GeneralError(this.CLASS_NAME, "createFailed", undefined, error);
|
|
579
722
|
}
|
|
580
723
|
}
|
|
581
724
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
*
|
|
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.
|
|
585
824
|
* @param options Additional options for the get operation.
|
|
586
825
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
587
826
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
588
827
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
589
828
|
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
590
|
-
* @param options.
|
|
591
|
-
* @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.
|
|
592
833
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
593
834
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
594
835
|
* @returns The documents and revisions if requested, ordered by revision descending, cursor is set if there are more document revisions.
|
|
595
836
|
*/
|
|
596
|
-
async get(
|
|
597
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
598
|
-
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);
|
|
599
839
|
try {
|
|
600
|
-
const
|
|
601
|
-
const includeBlobStorageData = options?.includeBlobStorageData ?? false;
|
|
602
|
-
const includeAttestation = options?.includeAttestation ?? false;
|
|
603
|
-
const includeRemoved = options?.includeRemoved ?? false;
|
|
604
|
-
const revCursor = Math.max(core.Coerce.integer(revisionCursor) ?? 0, 0);
|
|
605
|
-
const maxRevisionCount = Math.max(core.Coerce.integer(options?.maxRevisionCount) ?? 0);
|
|
606
|
-
const documentIdParts = this.parseDocumentId(identifier);
|
|
607
|
-
const vertex = await this._auditableItemGraphComponent.get(auditableItemGraphId);
|
|
608
|
-
// Get all the docs from the AIG vertex
|
|
609
|
-
const vertexDocs = this.filterDocumentsFromVertex(vertex);
|
|
610
|
-
// Reduce the list to those with a matching id and code
|
|
611
|
-
const matchingDocIds = this.findMatchingDocs(vertexDocs, documentIdParts.documentId, documentIdParts.documentCode, includeRemoved);
|
|
840
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId, { includeDeleted: options?.includeRemoved });
|
|
612
841
|
// Populate the document and revisions with the options set
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
includeBlobStorageData,
|
|
616
|
-
includeAttestation,
|
|
617
|
-
includeRemoved,
|
|
618
|
-
maxRevisionCount
|
|
619
|
-
}, revCursor, userIdentity, nodeIdentity);
|
|
620
|
-
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"]);
|
|
621
844
|
}
|
|
622
845
|
catch (error) {
|
|
623
846
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
@@ -627,218 +850,237 @@ class DocumentManagementService {
|
|
|
627
850
|
}
|
|
628
851
|
}
|
|
629
852
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
632
|
-
* @param
|
|
633
|
-
* @param
|
|
634
|
-
* @param options
|
|
635
|
-
* @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.
|
|
636
862
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
637
863
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
638
|
-
* @returns
|
|
864
|
+
* @returns The documents and revisions if requested, ordered by revision descending, cursor is set if there are more document revisions.
|
|
639
865
|
*/
|
|
640
|
-
async
|
|
641
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
642
|
-
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);
|
|
643
869
|
try {
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
const vertexDocs = this.filterDocumentsFromVertex(vertex);
|
|
648
|
-
// Reduce the list to those with a matching id and code
|
|
649
|
-
const matchingDocIds = this.findMatchingDocs(vertexDocs, documentIdParts.documentId, documentIdParts.documentCode, false);
|
|
650
|
-
const removeAllRevisions = options?.removeAllRevisions ?? false;
|
|
651
|
-
const now = Date.now();
|
|
652
|
-
if (removeAllRevisions) {
|
|
653
|
-
for (const doc of matchingDocIds) {
|
|
654
|
-
doc.dateDeleted = new Date(now).toISOString();
|
|
655
|
-
}
|
|
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");
|
|
656
873
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
matchingRevision.dateDeleted = new Date(now).toISOString();
|
|
661
|
-
}
|
|
662
|
-
else {
|
|
663
|
-
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", identifier);
|
|
664
|
-
}
|
|
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());
|
|
665
877
|
}
|
|
666
|
-
|
|
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"]);
|
|
667
881
|
}
|
|
668
882
|
catch (error) {
|
|
669
883
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
670
884
|
throw error;
|
|
671
885
|
}
|
|
672
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
886
|
+
throw new core.GeneralError(this.CLASS_NAME, "getRevisionFailed", undefined, error);
|
|
673
887
|
}
|
|
674
888
|
}
|
|
675
889
|
/**
|
|
676
|
-
*
|
|
677
|
-
*
|
|
678
|
-
* @param
|
|
679
|
-
* @param
|
|
680
|
-
* @param options.includeMostRecentRevisions Include the most recent 5 revisions, use the individual get to retrieve more.
|
|
681
|
-
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
682
|
-
* @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.
|
|
683
894
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
684
895
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
685
|
-
* @returns
|
|
896
|
+
* @returns Nothing.
|
|
686
897
|
*/
|
|
687
|
-
async
|
|
688
|
-
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);
|
|
689
901
|
try {
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
const documentIdGroups = {};
|
|
701
|
-
let docGroupIds = [];
|
|
702
|
-
for (const doc of matchingDocIds) {
|
|
703
|
-
const docId = `${doc.documentId}:${doc.documentCode}`;
|
|
704
|
-
if (!docGroupIds.includes(docId)) {
|
|
705
|
-
docGroupIds.push(docId);
|
|
706
|
-
}
|
|
707
|
-
documentIdGroups[docId] ??= [];
|
|
708
|
-
documentIdGroups[docId].push(doc);
|
|
709
|
-
}
|
|
710
|
-
let nextDocCursor;
|
|
711
|
-
if (docGroupIds.length > docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE) {
|
|
712
|
-
nextDocCursor = (docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE).toString();
|
|
713
|
-
}
|
|
714
|
-
docGroupIds = docGroupIds.slice(docCursor, docCursor + DocumentManagementService._DEFAULT_PAGE_SIZE);
|
|
715
|
-
const finalDocs = [];
|
|
716
|
-
for (const docId of docGroupIds) {
|
|
717
|
-
finalDocs.push(await this.getDocumentAndRevisions(documentIdGroups[docId], docId, {
|
|
718
|
-
includeAttestation: false,
|
|
719
|
-
includeBlobStorageData: false,
|
|
720
|
-
includeBlobStorageMetadata: false,
|
|
721
|
-
includeRemoved,
|
|
722
|
-
maxRevisionCount: includeMostRecentRevisions ? 5 : 0
|
|
723
|
-
}, 0, userIdentity, nodeIdentity));
|
|
724
|
-
}
|
|
725
|
-
const docList = {
|
|
726
|
-
"@context": [
|
|
727
|
-
documentManagementModels.DocumentContexts.ContextRoot,
|
|
728
|
-
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
729
|
-
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
730
|
-
],
|
|
731
|
-
type: documentManagementModels.DocumentTypes.DocumentList,
|
|
732
|
-
documents: finalDocs,
|
|
733
|
-
cursor: nextDocCursor
|
|
734
|
-
};
|
|
735
|
-
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);
|
|
736
912
|
}
|
|
737
913
|
catch (error) {
|
|
738
914
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
739
915
|
throw error;
|
|
740
916
|
}
|
|
741
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
917
|
+
throw new core.GeneralError(this.CLASS_NAME, "removeRevisionFailed", undefined, error);
|
|
742
918
|
}
|
|
743
919
|
}
|
|
744
920
|
/**
|
|
745
|
-
*
|
|
746
|
-
* @param documentId The document
|
|
747
|
-
* @
|
|
748
|
-
* @
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Decode the document id.
|
|
755
|
-
* @param documentId The document identifier.
|
|
756
|
-
* @returns The decoded identifier.
|
|
757
|
-
* @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.
|
|
758
928
|
*/
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
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);
|
|
766
943
|
}
|
|
767
|
-
return { documentId: parts.join(":"), documentRevision: revision };
|
|
768
|
-
}
|
|
769
|
-
/**
|
|
770
|
-
* Create a full identifier for a document.
|
|
771
|
-
* @param documentCode The document code.
|
|
772
|
-
* @param documentId The document identifier.
|
|
773
|
-
* @param documentRevision The document revision.
|
|
774
|
-
* @returns The full identifier.
|
|
775
|
-
* @internal
|
|
776
|
-
*/
|
|
777
|
-
createIdentifier(documentCode, documentId, documentRevision) {
|
|
778
|
-
const docCode = this.parseDocumentCode(documentCode);
|
|
779
|
-
return `documents:${docCode}:${this.encodeDocumentIdentifier(documentId, documentRevision)}`;
|
|
780
944
|
}
|
|
781
945
|
/**
|
|
782
|
-
*
|
|
783
|
-
* @param
|
|
784
|
-
* @
|
|
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.
|
|
785
950
|
* @internal
|
|
786
951
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
const
|
|
790
|
-
if (
|
|
791
|
-
|
|
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
|
+
}
|
|
792
986
|
}
|
|
793
|
-
|
|
794
|
-
const { documentId, documentRevision } = this.decodeDocumentIdentifier(urn.namespaceSpecific(1));
|
|
795
|
-
return { documentCode, documentId, documentRevision };
|
|
987
|
+
return changed;
|
|
796
988
|
}
|
|
797
989
|
/**
|
|
798
|
-
*
|
|
799
|
-
* @param
|
|
800
|
-
* @
|
|
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.
|
|
801
999
|
* @internal
|
|
802
1000
|
*/
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
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
|
+
}
|
|
808
1055
|
}
|
|
809
|
-
|
|
810
|
-
if (
|
|
811
|
-
|
|
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
|
+
}
|
|
812
1083
|
}
|
|
813
|
-
return docCode;
|
|
814
|
-
}
|
|
815
|
-
/**
|
|
816
|
-
* Get the documents from a vertex.
|
|
817
|
-
* @param vertex The vertex to get the documents from.
|
|
818
|
-
* @returns The documents.
|
|
819
|
-
* @internal
|
|
820
|
-
*/
|
|
821
|
-
filterDocumentsFromVertex(vertex) {
|
|
822
|
-
return (vertex.resources
|
|
823
|
-
?.filter(resource => core.ObjectHelper.extractProperty(resource.resourceObject, ["@type", "type"], false) ===
|
|
824
|
-
documentManagementModels.DocumentTypes.Document)
|
|
825
|
-
.map(resource => resource.resourceObject) ?? []);
|
|
826
|
-
}
|
|
827
|
-
/**
|
|
828
|
-
* Find matching documents in the list of existing documents.
|
|
829
|
-
* @param documents The documents to search.
|
|
830
|
-
* @param documentId The document id.
|
|
831
|
-
* @param documentCode The document code.
|
|
832
|
-
* @param includeRemoved Include deleted documents.
|
|
833
|
-
* @returns The matching documents.
|
|
834
|
-
* @internal
|
|
835
|
-
*/
|
|
836
|
-
findMatchingDocs(documents, documentId, documentCode, includeRemoved) {
|
|
837
|
-
return documents
|
|
838
|
-
.filter(d => d.documentId === documentId &&
|
|
839
|
-
d.documentCode === documentCode &&
|
|
840
|
-
(includeRemoved || core.Is.empty(d.dateDeleted)))
|
|
841
|
-
.sort((a, b) => b.documentRevision - a.documentRevision);
|
|
842
1084
|
}
|
|
843
1085
|
/**
|
|
844
1086
|
* Generate a hash for the blob data.
|
|
@@ -851,47 +1093,91 @@ class DocumentManagementService {
|
|
|
851
1093
|
}
|
|
852
1094
|
/**
|
|
853
1095
|
* Get the documents from the auditable item graph vertex.
|
|
854
|
-
* @param
|
|
855
|
-
* @param identifier The full document identifier.
|
|
1096
|
+
* @param documentVertex The vertex containing the documents.
|
|
856
1097
|
* @param options Additional options for the get operation.
|
|
857
1098
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
858
1099
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
859
1100
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
860
|
-
* @param options.
|
|
861
|
-
* @param options.
|
|
862
|
-
* @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.
|
|
863
1105
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
864
1106
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
865
1107
|
* @returns The finalised list of documents.
|
|
866
1108
|
* @internal
|
|
867
1109
|
*/
|
|
868
|
-
async
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
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
|
+
}
|
|
886
1171
|
}
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
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
|
+
}
|
|
891
1179
|
}
|
|
892
|
-
|
|
893
|
-
document.revisionCursor = nextRevisionCursor;
|
|
894
|
-
return document;
|
|
1180
|
+
return docList;
|
|
895
1181
|
}
|
|
896
1182
|
/**
|
|
897
1183
|
* Create an attestation for the document.
|
|
@@ -908,6 +1194,7 @@ class DocumentManagementService {
|
|
|
908
1194
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
909
1195
|
],
|
|
910
1196
|
type: documentManagementModels.DocumentTypes.DocumentAttestation,
|
|
1197
|
+
id: document.id,
|
|
911
1198
|
documentId: document.documentId,
|
|
912
1199
|
documentCode: document.documentCode,
|
|
913
1200
|
documentRevision: document.documentRevision,
|
|
@@ -916,22 +1203,35 @@ class DocumentManagementService {
|
|
|
916
1203
|
};
|
|
917
1204
|
return this._attestationComponent.create(documentAttestation, undefined, userIdentity, nodeIdentity);
|
|
918
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}`;
|
|
1216
|
+
}
|
|
919
1217
|
}
|
|
920
1218
|
|
|
921
1219
|
const restEntryPoints = [
|
|
922
1220
|
{
|
|
923
|
-
name: "
|
|
924
|
-
defaultBaseRoute: "
|
|
1221
|
+
name: "document-management",
|
|
1222
|
+
defaultBaseRoute: "document-management",
|
|
925
1223
|
tags: tagsDocumentManagement,
|
|
926
1224
|
generateRoutes: generateRestRoutesDocumentManagement
|
|
927
1225
|
}
|
|
928
1226
|
];
|
|
929
1227
|
|
|
930
1228
|
exports.DocumentManagementService = DocumentManagementService;
|
|
1229
|
+
exports.documentManagementCreate = documentManagementCreate;
|
|
931
1230
|
exports.documentManagementGet = documentManagementGet;
|
|
1231
|
+
exports.documentManagementGetRevision = documentManagementGetRevision;
|
|
932
1232
|
exports.documentManagementQuery = documentManagementQuery;
|
|
933
1233
|
exports.documentManagementRemove = documentManagementRemove;
|
|
934
|
-
exports.
|
|
1234
|
+
exports.documentManagementUpdate = documentManagementUpdate;
|
|
935
1235
|
exports.generateRestRoutesDocumentManagement = generateRestRoutesDocumentManagement;
|
|
936
1236
|
exports.restEntryPoints = restEntryPoints;
|
|
937
1237
|
exports.tagsDocumentManagement = tagsDocumentManagement;
|