@twin.org/document-management-service 0.0.1-next.7 → 0.0.1-next.9
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 +574 -463
- package/dist/esm/index.mjs +574 -464
- package/dist/types/documentManagementRoutes.d.ts +12 -4
- package/dist/types/documentManagementService.d.ts +47 -37
- package/docs/changelog.md +28 -0
- package/docs/open-api/spec.json +248 -203
- package/docs/reference/classes/DocumentManagementService.md +106 -80
- package/docs/reference/functions/{documentManagementSet.md → documentManagementCreate.md} +4 -4
- package/docs/reference/functions/documentManagementUpdate.md +31 -0
- package/docs/reference/index.md +2 -1
- package/locales/en.json +5 -5
- package/package.json +2 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var apiModels = require('@twin.org/api-models');
|
|
4
3
|
var core = require('@twin.org/core');
|
|
5
4
|
var documentManagementModels = require('@twin.org/document-management-models');
|
|
6
5
|
var standardsSchemaOrg = require('@twin.org/standards-schema-org');
|
|
@@ -12,8 +11,6 @@ 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,22 +77,29 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
83
77
|
}
|
|
84
78
|
]
|
|
85
79
|
};
|
|
86
|
-
const
|
|
87
|
-
operationId: "
|
|
88
|
-
summary: "
|
|
80
|
+
const documentManagementUpdateRoute = {
|
|
81
|
+
operationId: "DocumentManagementUpdate",
|
|
82
|
+
summary: "Update a document in an auditable item graph vertex and add its content to blob storage.",
|
|
89
83
|
tag: tagsDocumentManagement[0].name,
|
|
90
|
-
method: "
|
|
91
|
-
path: `${baseRouteName}/:
|
|
92
|
-
handler: async (httpRequestContext, request) =>
|
|
84
|
+
method: "PUT",
|
|
85
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId`,
|
|
86
|
+
handler: async (httpRequestContext, request) => documentManagementUpdate(httpRequestContext, componentName, request),
|
|
93
87
|
requestType: {
|
|
94
|
-
type: "
|
|
88
|
+
type: "IDocumentManagementUpdateRequest",
|
|
95
89
|
examples: [
|
|
96
90
|
{
|
|
97
|
-
id: "
|
|
91
|
+
id: "DocumentManagementUpdateRequestExample",
|
|
98
92
|
request: {
|
|
99
93
|
pathParams: {
|
|
100
|
-
|
|
101
|
-
|
|
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
|
+
}
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
}
|
|
@@ -106,122 +107,33 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
106
107
|
},
|
|
107
108
|
responseType: [
|
|
108
109
|
{
|
|
109
|
-
type: "
|
|
110
|
+
type: "INoContentResponse",
|
|
110
111
|
examples: [
|
|
111
112
|
{
|
|
112
|
-
id: "
|
|
113
|
+
id: "DocumentManagementCreateResponseExample",
|
|
113
114
|
response: {
|
|
114
|
-
|
|
115
|
-
"@context": [
|
|
116
|
-
documentManagementModels.DocumentContexts.ContextRoot,
|
|
117
|
-
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
118
|
-
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
119
|
-
],
|
|
120
|
-
type: documentManagementModels.DocumentTypes.Document,
|
|
121
|
-
id: "documents:705:2721000:rev-0",
|
|
122
|
-
documentId: "2721000",
|
|
123
|
-
documentIdFormat: "bol",
|
|
124
|
-
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
125
|
-
documentRevision: 0,
|
|
126
|
-
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
127
|
-
blobHash: "sha256:123456",
|
|
128
|
-
dateCreated: "2024-01-01T00:00:00Z",
|
|
129
|
-
annotationObject: {
|
|
130
|
-
"@context": "https://schema.org",
|
|
131
|
-
"@type": "DigitalDocument",
|
|
132
|
-
name: "myfile.pdf"
|
|
133
|
-
},
|
|
134
|
-
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
135
|
-
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
136
|
-
}
|
|
115
|
+
statusCode: web.HttpStatusCode.noContent
|
|
137
116
|
}
|
|
138
117
|
}
|
|
139
118
|
]
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
type: "IDocumentManagementGetResponse",
|
|
143
|
-
mimeType: web.MimeTypes.JsonLd,
|
|
144
|
-
examples: [
|
|
145
|
-
{
|
|
146
|
-
id: "DocumentManagementGetResponseExample",
|
|
147
|
-
response: {
|
|
148
|
-
body: {
|
|
149
|
-
"@context": [
|
|
150
|
-
documentManagementModels.DocumentContexts.ContextRoot,
|
|
151
|
-
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
152
|
-
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
153
|
-
],
|
|
154
|
-
type: documentManagementModels.DocumentTypes.Document,
|
|
155
|
-
id: "documents:705:2721000:rev-0",
|
|
156
|
-
documentId: "2721000",
|
|
157
|
-
documentIdFormat: "bol",
|
|
158
|
-
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
159
|
-
documentRevision: 0,
|
|
160
|
-
blobStorageId: "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
161
|
-
blobHash: "sha256:123456",
|
|
162
|
-
dateCreated: "2024-01-01T00:00:00Z",
|
|
163
|
-
annotationObject: {
|
|
164
|
-
"@context": "https://schema.org",
|
|
165
|
-
"@type": "DigitalDocument",
|
|
166
|
-
name: "myfile.pdf"
|
|
167
|
-
},
|
|
168
|
-
nodeIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
169
|
-
userIdentity: "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
]
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
type: "INotFoundResponse"
|
|
177
119
|
}
|
|
178
120
|
]
|
|
179
121
|
};
|
|
180
|
-
const
|
|
181
|
-
operationId: "
|
|
182
|
-
summary: "
|
|
183
|
-
tag: tagsDocumentManagement[0].name,
|
|
184
|
-
method: "DELETE",
|
|
185
|
-
path: `${baseRouteName}/:auditableItemGraphId/:documentId`,
|
|
186
|
-
handler: async (httpRequestContext, request) => documentManagementRemove(httpRequestContext, componentName, request),
|
|
187
|
-
requestType: {
|
|
188
|
-
type: "IDocumentManagementRemoveRequest",
|
|
189
|
-
examples: [
|
|
190
|
-
{
|
|
191
|
-
id: "DocumentManagementRemoveRequestExample",
|
|
192
|
-
request: {
|
|
193
|
-
pathParams: {
|
|
194
|
-
auditableItemGraphId: "aig:1234",
|
|
195
|
-
documentId: "documents:123456:705:2721000"
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
},
|
|
201
|
-
responseType: [
|
|
202
|
-
{
|
|
203
|
-
type: "INoContentResponse"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
type: "INotFoundResponse"
|
|
207
|
-
}
|
|
208
|
-
]
|
|
209
|
-
};
|
|
210
|
-
const documentManagementQueryRoute = {
|
|
211
|
-
operationId: "DocumentManagementQuery",
|
|
212
|
-
summary: "Query the items from an auditable item graph vertex",
|
|
122
|
+
const documentManagementGetRoute = {
|
|
123
|
+
operationId: "DocumentManagementGet",
|
|
124
|
+
summary: "Get the data for a document from document management",
|
|
213
125
|
tag: tagsDocumentManagement[0].name,
|
|
214
126
|
method: "GET",
|
|
215
|
-
path: `${baseRouteName}/:
|
|
216
|
-
handler: async (httpRequestContext, request) =>
|
|
127
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId`,
|
|
128
|
+
handler: async (httpRequestContext, request) => documentManagementGet(httpRequestContext, componentName, request),
|
|
217
129
|
requestType: {
|
|
218
|
-
type: "
|
|
130
|
+
type: "IDocumentManagementGetRequest",
|
|
219
131
|
examples: [
|
|
220
132
|
{
|
|
221
|
-
id: "
|
|
133
|
+
id: "DocumentManagementGetRequestExample",
|
|
222
134
|
request: {
|
|
223
135
|
pathParams: {
|
|
224
|
-
|
|
136
|
+
auditableItemGraphDocumentId: "aig:123456"
|
|
225
137
|
}
|
|
226
138
|
}
|
|
227
139
|
}
|
|
@@ -229,10 +141,10 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
229
141
|
},
|
|
230
142
|
responseType: [
|
|
231
143
|
{
|
|
232
|
-
type: "
|
|
144
|
+
type: "IDocumentManagementGetResponse",
|
|
233
145
|
examples: [
|
|
234
146
|
{
|
|
235
|
-
id: "
|
|
147
|
+
id: "DocumentManagementGetResponseExample",
|
|
236
148
|
response: {
|
|
237
149
|
body: {
|
|
238
150
|
"@context": [documentManagementModels.DocumentContexts.ContextRoot, documentManagementModels.DocumentContexts.ContextRootCommon],
|
|
@@ -245,7 +157,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
245
157
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
246
158
|
],
|
|
247
159
|
type: documentManagementModels.DocumentTypes.Document,
|
|
248
|
-
id: "
|
|
160
|
+
id: "2721000:0",
|
|
249
161
|
documentId: "2721000",
|
|
250
162
|
documentIdFormat: "bol",
|
|
251
163
|
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
@@ -268,11 +180,11 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
268
180
|
]
|
|
269
181
|
},
|
|
270
182
|
{
|
|
271
|
-
type: "
|
|
183
|
+
type: "IDocumentManagementGetResponse",
|
|
272
184
|
mimeType: web.MimeTypes.JsonLd,
|
|
273
185
|
examples: [
|
|
274
186
|
{
|
|
275
|
-
id: "
|
|
187
|
+
id: "DocumentManagementGetResponseExample",
|
|
276
188
|
response: {
|
|
277
189
|
body: {
|
|
278
190
|
"@context": [documentManagementModels.DocumentContexts.ContextRoot, documentManagementModels.DocumentContexts.ContextRootCommon],
|
|
@@ -285,7 +197,7 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
285
197
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
286
198
|
],
|
|
287
199
|
type: documentManagementModels.DocumentTypes.Document,
|
|
288
|
-
id: "
|
|
200
|
+
id: "2721000:0",
|
|
289
201
|
documentId: "2721000",
|
|
290
202
|
documentIdFormat: "bol",
|
|
291
203
|
documentCode: standardsUnece.UneceDocumentCodes.BillOfLading,
|
|
@@ -306,33 +218,173 @@ function generateRestRoutesDocumentManagement(baseRouteName, componentName) {
|
|
|
306
218
|
}
|
|
307
219
|
}
|
|
308
220
|
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
type: "INotFoundResponse"
|
|
224
|
+
}
|
|
225
|
+
]
|
|
226
|
+
};
|
|
227
|
+
const documentManagementRemoveRoute = {
|
|
228
|
+
operationId: "DocumentManagementRemove",
|
|
229
|
+
summary: "Remove an document from an auditable item graph vertex",
|
|
230
|
+
tag: tagsDocumentManagement[0].name,
|
|
231
|
+
method: "DELETE",
|
|
232
|
+
path: `${baseRouteName}/:auditableItemGraphDocumentId/:revision`,
|
|
233
|
+
handler: async (httpRequestContext, request) => documentManagementRemove(httpRequestContext, componentName, request),
|
|
234
|
+
requestType: {
|
|
235
|
+
type: "IDocumentManagementRemoveRequest",
|
|
236
|
+
examples: [
|
|
237
|
+
{
|
|
238
|
+
id: "DocumentManagementRemoveRequestExample",
|
|
239
|
+
request: {
|
|
240
|
+
pathParams: {
|
|
241
|
+
auditableItemGraphDocumentId: "aig:1234",
|
|
242
|
+
revision: "1"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
},
|
|
248
|
+
responseType: [
|
|
249
|
+
{
|
|
250
|
+
type: "INoContentResponse"
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
type: "INotFoundResponse"
|
|
309
254
|
}
|
|
310
255
|
]
|
|
311
256
|
};
|
|
257
|
+
const documentManagementQueryRoute = {
|
|
258
|
+
operationId: "DocumentManagementQuery",
|
|
259
|
+
summary: "Query the items from an auditable item graph vertex",
|
|
260
|
+
tag: tagsDocumentManagement[0].name,
|
|
261
|
+
method: "GET",
|
|
262
|
+
path: `${baseRouteName}/`,
|
|
263
|
+
handler: async (httpRequestContext, request) => documentManagementQuery(httpRequestContext, componentName, request),
|
|
264
|
+
requestType: {
|
|
265
|
+
type: "IDocumentManagementQueryRequest",
|
|
266
|
+
examples: [
|
|
267
|
+
{
|
|
268
|
+
id: "DocumentManagementQueryRequestExample",
|
|
269
|
+
request: {
|
|
270
|
+
query: {
|
|
271
|
+
documentId: "2721000"
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
responseType: [
|
|
278
|
+
// {
|
|
279
|
+
// type: nameof<IDocumentManagementQueryResponse>(),
|
|
280
|
+
// examples: [
|
|
281
|
+
// {
|
|
282
|
+
// id: "DocumentManagementQueryResponseExample",
|
|
283
|
+
// response: {
|
|
284
|
+
// body: {
|
|
285
|
+
// "@context": [DocumentContexts.ContextRoot, DocumentContexts.ContextRootCommon],
|
|
286
|
+
// type: DocumentTypes.DocumentList,
|
|
287
|
+
// documents: [
|
|
288
|
+
// {
|
|
289
|
+
// "@context": [
|
|
290
|
+
// DocumentContexts.ContextRoot,
|
|
291
|
+
// DocumentContexts.ContextRootCommon,
|
|
292
|
+
// SchemaOrgContexts.ContextRoot
|
|
293
|
+
// ],
|
|
294
|
+
// type: DocumentTypes.Document,
|
|
295
|
+
// id: "2721000:0",
|
|
296
|
+
// documentId: "2721000",
|
|
297
|
+
// documentIdFormat: "bol",
|
|
298
|
+
// documentCode: UneceDocumentCodes.BillOfLading,
|
|
299
|
+
// documentRevision: 0,
|
|
300
|
+
// blobStorageId:
|
|
301
|
+
// "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
302
|
+
// blobHash: "sha256:123456",
|
|
303
|
+
// dateCreated: "2024-01-01T00:00:00Z",
|
|
304
|
+
// annotationObject: {
|
|
305
|
+
// "@context": "https://schema.org",
|
|
306
|
+
// "@type": "DigitalDocument",
|
|
307
|
+
// name: "myfile.pdf"
|
|
308
|
+
// },
|
|
309
|
+
// nodeIdentity:
|
|
310
|
+
// "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
311
|
+
// userIdentity:
|
|
312
|
+
// "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
313
|
+
// }
|
|
314
|
+
// ]
|
|
315
|
+
// }
|
|
316
|
+
// }
|
|
317
|
+
// }
|
|
318
|
+
// ]
|
|
319
|
+
// },
|
|
320
|
+
// {
|
|
321
|
+
// type: nameof<IDocumentManagementQueryResponse>(),
|
|
322
|
+
// mimeType: MimeTypes.JsonLd,
|
|
323
|
+
// examples: [
|
|
324
|
+
// {
|
|
325
|
+
// id: "DocumentManagementListResponseJsonLdExample",
|
|
326
|
+
// response: {
|
|
327
|
+
// body: {
|
|
328
|
+
// "@context": [DocumentContexts.ContextRoot, DocumentContexts.ContextRootCommon],
|
|
329
|
+
// type: DocumentTypes.DocumentList,
|
|
330
|
+
// documents: [
|
|
331
|
+
// {
|
|
332
|
+
// "@context": [
|
|
333
|
+
// DocumentContexts.ContextRoot,
|
|
334
|
+
// DocumentContexts.ContextRootCommon,
|
|
335
|
+
// SchemaOrgContexts.ContextRoot
|
|
336
|
+
// ],
|
|
337
|
+
// type: DocumentTypes.Document,
|
|
338
|
+
// id: "2721000:0",
|
|
339
|
+
// documentId: "2721000",
|
|
340
|
+
// documentIdFormat: "bol",
|
|
341
|
+
// documentCode: UneceDocumentCodes.BillOfLading,
|
|
342
|
+
// documentRevision: 0,
|
|
343
|
+
// blobStorageId:
|
|
344
|
+
// "blob-memory:c57d94b088f4c6d2cb32ded014813d0c786aa00134c8ee22f84b1e2545602a70",
|
|
345
|
+
// blobHash: "sha256:123456",
|
|
346
|
+
// dateCreated: "2024-01-01T00:00:00Z",
|
|
347
|
+
// annotationObject: {
|
|
348
|
+
// "@context": "https://schema.org",
|
|
349
|
+
// "@type": "DigitalDocument",
|
|
350
|
+
// name: "myfile.pdf"
|
|
351
|
+
// },
|
|
352
|
+
// nodeIdentity:
|
|
353
|
+
// "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363",
|
|
354
|
+
// userIdentity:
|
|
355
|
+
// "did:entity-storage:0x6363636363636363636363636363636363636363636363636363636363636363"
|
|
356
|
+
// }
|
|
357
|
+
// ]
|
|
358
|
+
// }
|
|
359
|
+
// }
|
|
360
|
+
// }
|
|
361
|
+
// ]
|
|
362
|
+
// }
|
|
363
|
+
]
|
|
364
|
+
};
|
|
312
365
|
return [
|
|
313
|
-
|
|
366
|
+
documentManagementCreateRoute,
|
|
367
|
+
documentManagementUpdateRoute,
|
|
314
368
|
documentManagementGetRoute,
|
|
315
369
|
documentManagementRemoveRoute,
|
|
316
370
|
documentManagementQueryRoute
|
|
317
371
|
];
|
|
318
372
|
}
|
|
319
373
|
/**
|
|
320
|
-
*
|
|
374
|
+
* Create a document as an auditable item graph vertex.
|
|
321
375
|
* @param httpRequestContext The request context for the API.
|
|
322
376
|
* @param componentName The name of the component to use in the routes.
|
|
323
377
|
* @param request The request.
|
|
324
378
|
* @returns The response object with additional http response properties.
|
|
325
379
|
*/
|
|
326
|
-
async function
|
|
380
|
+
async function documentManagementCreate(httpRequestContext, componentName, request) {
|
|
327
381
|
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
382
|
core.Guards.object(ROUTES_SOURCE, "request.body", request.body);
|
|
331
383
|
core.Guards.stringBase64(ROUTES_SOURCE, "request.body.blob", request.body.blob);
|
|
332
384
|
const component = core.ComponentFactory.get(componentName);
|
|
333
|
-
const id = await component.
|
|
385
|
+
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
386
|
createAttestation: request.body.createAttestation,
|
|
335
|
-
|
|
387
|
+
addAlias: request.body.addAlias,
|
|
336
388
|
aliasAnnotationObject: request.body.aliasAnnotationObject
|
|
337
389
|
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
338
390
|
return {
|
|
@@ -352,17 +404,15 @@ async function documentManagementSet(httpRequestContext, componentName, request)
|
|
|
352
404
|
async function documentManagementGet(httpRequestContext, componentName, request) {
|
|
353
405
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
354
406
|
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);
|
|
407
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
357
408
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
358
409
|
const component = core.ComponentFactory.get(componentName);
|
|
359
|
-
const result = await component.get(request.pathParams.
|
|
410
|
+
const result = await component.get(request.pathParams.auditableItemGraphDocumentId, {
|
|
360
411
|
includeBlobStorageMetadata: core.Coerce.boolean(request.query?.includeBlobStorageMetadata),
|
|
361
412
|
includeBlobStorageData: core.Coerce.boolean(request.query?.includeBlobStorageData),
|
|
362
413
|
includeAttestation: core.Coerce.boolean(request.query?.includeAttestation),
|
|
363
|
-
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved)
|
|
364
|
-
|
|
365
|
-
}, request.query?.revisionCursor, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
414
|
+
includeRemoved: core.Coerce.boolean(request.query?.includeRemoved)
|
|
415
|
+
}, request.query?.cursor, core.Coerce.integer(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
366
416
|
return {
|
|
367
417
|
headers: {
|
|
368
418
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -370,6 +420,23 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
370
420
|
body: result
|
|
371
421
|
};
|
|
372
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* UPdate the document from the auditable item graph vertex.
|
|
425
|
+
* @param httpRequestContext The request context for the API.
|
|
426
|
+
* @param componentName The name of the component to use in the routes.
|
|
427
|
+
* @param request The request.
|
|
428
|
+
* @returns The response object with additional http response properties.
|
|
429
|
+
*/
|
|
430
|
+
async function documentManagementUpdate(httpRequestContext, componentName, request) {
|
|
431
|
+
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
432
|
+
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
433
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
434
|
+
const component = core.ComponentFactory.get(componentName);
|
|
435
|
+
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);
|
|
436
|
+
return {
|
|
437
|
+
statusCode: web.HttpStatusCode.noContent
|
|
438
|
+
};
|
|
439
|
+
}
|
|
373
440
|
/**
|
|
374
441
|
* Remove the document from the auditable item graph vertex.
|
|
375
442
|
* @param httpRequestContext The request context for the API.
|
|
@@ -380,12 +447,11 @@ async function documentManagementGet(httpRequestContext, componentName, request)
|
|
|
380
447
|
async function documentManagementRemove(httpRequestContext, componentName, request) {
|
|
381
448
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
382
449
|
core.Guards.object(ROUTES_SOURCE, "request.pathParams", request.pathParams);
|
|
383
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.
|
|
384
|
-
core.
|
|
450
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.pathParams.auditableItemGraphDocumentId", request.pathParams.auditableItemGraphDocumentId);
|
|
451
|
+
const revision = core.Coerce.number(request.pathParams.revision);
|
|
452
|
+
core.Guards.integer(ROUTES_SOURCE, "request.pathParams.revision", revision);
|
|
385
453
|
const component = core.ComponentFactory.get(componentName);
|
|
386
|
-
await component.
|
|
387
|
-
removeAllRevisions: request.query?.removeAllRevisions
|
|
388
|
-
}, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
454
|
+
await component.removeRevision(request.pathParams.auditableItemGraphDocumentId, revision, httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
389
455
|
return {
|
|
390
456
|
statusCode: web.HttpStatusCode.noContent
|
|
391
457
|
};
|
|
@@ -399,14 +465,11 @@ async function documentManagementRemove(httpRequestContext, componentName, reque
|
|
|
399
465
|
*/
|
|
400
466
|
async function documentManagementQuery(httpRequestContext, componentName, request) {
|
|
401
467
|
core.Guards.object(ROUTES_SOURCE, "request", request);
|
|
402
|
-
core.Guards.object(ROUTES_SOURCE, "request.
|
|
403
|
-
core.Guards.stringValue(ROUTES_SOURCE, "request.
|
|
468
|
+
core.Guards.object(ROUTES_SOURCE, "request.query", request.query);
|
|
469
|
+
core.Guards.stringValue(ROUTES_SOURCE, "request.query.documentId", request.query.documentId);
|
|
404
470
|
const mimeType = request.headers?.[web.HeaderTypes.Accept] === web.MimeTypes.JsonLd ? "jsonld" : "json";
|
|
405
471
|
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);
|
|
472
|
+
const result = await component.query(request.query.documentId, request.query?.cursor, core.Coerce.integer(request.query?.pageSize), httpRequestContext.userIdentity, httpRequestContext.nodeIdentity);
|
|
410
473
|
return {
|
|
411
474
|
headers: {
|
|
412
475
|
[web.HeaderTypes.ContentType]: mimeType === "json" ? web.MimeTypes.Json : web.MimeTypes.JsonLd
|
|
@@ -423,11 +486,6 @@ class DocumentManagementService {
|
|
|
423
486
|
* The namespace supported by the document management service.
|
|
424
487
|
*/
|
|
425
488
|
static NAMESPACE = "documents";
|
|
426
|
-
/**
|
|
427
|
-
* Default Page Size for cursor.
|
|
428
|
-
* @internal
|
|
429
|
-
*/
|
|
430
|
-
static _DEFAULT_PAGE_SIZE = 20;
|
|
431
489
|
/**
|
|
432
490
|
* Runtime name for the class.
|
|
433
491
|
*/
|
|
@@ -458,166 +516,211 @@ class DocumentManagementService {
|
|
|
458
516
|
standardsSchemaOrg.SchemaOrgDataTypes.registerRedirects();
|
|
459
517
|
}
|
|
460
518
|
/**
|
|
461
|
-
* Store a document
|
|
519
|
+
* Store a document as an auditable item graph vertex and add its content to blob storage.
|
|
462
520
|
* If the document id already exists and the blob data is different a new revision will be created.
|
|
463
521
|
* 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
522
|
* @param documentId The document id to create.
|
|
466
523
|
* @param documentIdFormat The format of the document identifier.
|
|
467
524
|
* @param documentCode The code for the document type.
|
|
468
|
-
* @param blob The data to create the document.
|
|
525
|
+
* @param blob The data to create the document with.
|
|
469
526
|
* @param annotationObject Additional information to associate with the document.
|
|
527
|
+
* @param auditableItemGraphEdges The auditable item graph vertices to connect the document to.
|
|
470
528
|
* @param options Additional options for the set operation.
|
|
471
529
|
* @param options.createAttestation Flag to create an attestation for the document, defaults to false.
|
|
472
|
-
* @param options.
|
|
473
|
-
* @param options.aliasAnnotationObject
|
|
530
|
+
* @param options.addAlias Flag to add the document id as an alias to the aig vertex, defaults to true.
|
|
531
|
+
* @param options.aliasAnnotationObject Annotation object for the alias.
|
|
474
532
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
475
533
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
476
|
-
* @returns The
|
|
534
|
+
* @returns The auditable item graph vertex created for the document including its revision.
|
|
477
535
|
*/
|
|
478
|
-
async
|
|
479
|
-
core.Guards.stringValue(this.CLASS_NAME, "auditableItemGraphId", auditableItemGraphId);
|
|
536
|
+
async create(documentId, documentIdFormat, documentCode, blob, annotationObject, auditableItemGraphEdges, options, userIdentity, nodeIdentity) {
|
|
480
537
|
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
481
538
|
core.Guards.arrayOneOf(this.CLASS_NAME, "documentCode", documentCode, Object.values(standardsUnece.UneceDocumentCodes));
|
|
482
539
|
core.Guards.uint8Array(this.CLASS_NAME, "blob", blob);
|
|
483
540
|
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
484
541
|
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
485
542
|
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
|
-
});
|
|
543
|
+
// Get the connected vertices first, if one fails we abort the create
|
|
544
|
+
const connectedVertices = {};
|
|
545
|
+
if (core.Is.arrayValue(auditableItemGraphEdges)) {
|
|
546
|
+
for (const edge of auditableItemGraphEdges) {
|
|
547
|
+
connectedVertices[edge.id] = await this._auditableItemGraphComponent.get(edge.id);
|
|
503
548
|
}
|
|
504
549
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
550
|
+
const documentVertex = {};
|
|
551
|
+
if (options?.addAlias ?? true) {
|
|
552
|
+
documentVertex.aliases ??= [];
|
|
553
|
+
documentVertex.aliases.push({
|
|
554
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
555
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
556
|
+
id: documentId,
|
|
557
|
+
aliasFormat: documentIdFormat,
|
|
558
|
+
annotationObject: options?.aliasAnnotationObject
|
|
559
|
+
});
|
|
515
560
|
}
|
|
516
|
-
//
|
|
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;
|
|
536
|
-
}
|
|
537
|
-
// Nothing matches the current blob hash so upload it to blob storage
|
|
561
|
+
// Add the blob to blob storage
|
|
538
562
|
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 = {
|
|
563
|
+
const currentRevision = {
|
|
543
564
|
"@context": [
|
|
544
565
|
documentManagementModels.DocumentContexts.ContextRoot,
|
|
545
566
|
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
546
567
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
547
568
|
],
|
|
548
569
|
type: documentManagementModels.DocumentTypes.Document,
|
|
549
|
-
id:
|
|
570
|
+
id: `${documentId}:0`,
|
|
550
571
|
documentId,
|
|
551
572
|
documentIdFormat,
|
|
552
573
|
documentCode,
|
|
553
|
-
documentRevision,
|
|
554
|
-
blobStorageId,
|
|
555
|
-
blobHash,
|
|
574
|
+
documentRevision: 0,
|
|
556
575
|
annotationObject,
|
|
576
|
+
blobHash: this.generateBlobHash(blob),
|
|
577
|
+
blobStorageId,
|
|
557
578
|
dateCreated: new Date(Date.now()).toISOString(),
|
|
558
579
|
nodeIdentity,
|
|
559
580
|
userIdentity
|
|
560
581
|
};
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
document.attestationId = await this.createAttestation(document, userIdentity, nodeIdentity);
|
|
582
|
+
if (options?.createAttestation ?? false) {
|
|
583
|
+
currentRevision.attestationId = await this.createAttestation(currentRevision, userIdentity, nodeIdentity);
|
|
564
584
|
}
|
|
565
|
-
// Add the new revision in to the
|
|
566
|
-
|
|
585
|
+
// Add the new revision in to the vertex
|
|
586
|
+
documentVertex.resources ??= [];
|
|
587
|
+
documentVertex.resources.push({
|
|
567
588
|
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
568
589
|
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
569
|
-
resourceObject:
|
|
590
|
+
resourceObject: currentRevision
|
|
570
591
|
});
|
|
571
|
-
|
|
572
|
-
|
|
592
|
+
// Add the edges from the document to the items
|
|
593
|
+
this.updateEdges(documentVertex, auditableItemGraphEdges);
|
|
594
|
+
// And create the vertex
|
|
595
|
+
const vertexId = await this._auditableItemGraphComponent.create(documentVertex, userIdentity, nodeIdentity);
|
|
596
|
+
// Now add the edges to the connected vertices
|
|
597
|
+
await this.updateConnectedEdges(connectedVertices, vertexId, [], auditableItemGraphEdges, documentId, documentIdFormat, userIdentity, nodeIdentity);
|
|
598
|
+
return vertexId;
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
throw new core.GeneralError(this.CLASS_NAME, "createFailed", undefined, error);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Update a document as an auditable item graph vertex and add its content to blob storage.
|
|
609
|
+
* If the blob data is different a new revision will be created.
|
|
610
|
+
* For any other changes the current revision will be updated.
|
|
611
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
612
|
+
* @param blob The data to update the document with.
|
|
613
|
+
* @param annotationObject Additional information to associate with the document.
|
|
614
|
+
* @param auditableItemGraphEdges The auditable item graph vertices to connect the document to, if undefined retains current connections.
|
|
615
|
+
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
616
|
+
* @param nodeIdentity The node identity to use for vault operations.
|
|
617
|
+
* @returns Nothing.
|
|
618
|
+
*/
|
|
619
|
+
async update(auditableItemGraphDocumentId, blob, annotationObject, auditableItemGraphEdges, userIdentity, nodeIdentity) {
|
|
620
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
621
|
+
core.Guards.stringValue(this.CLASS_NAME, "userIdentity", userIdentity);
|
|
622
|
+
core.Guards.stringValue(this.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
623
|
+
try {
|
|
624
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId);
|
|
625
|
+
if (core.Is.empty(documentVertex.resources)) {
|
|
626
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
627
|
+
}
|
|
628
|
+
const documents = await this.getDocumentsFromVertex(documentVertex);
|
|
629
|
+
const latestRevision = documents.documents[0];
|
|
630
|
+
if (core.Is.empty(latestRevision)) {
|
|
631
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
632
|
+
}
|
|
633
|
+
// If auditableItemGraphEdges is undefined we are not updating the edges
|
|
634
|
+
// an empty array can be passed to remove all edges
|
|
635
|
+
const connectedVertices = {};
|
|
636
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
637
|
+
// Get the updated connected vertices first, if one fails we abort the update
|
|
638
|
+
for (const edge of auditableItemGraphEdges) {
|
|
639
|
+
connectedVertices[edge.id] = await this._auditableItemGraphComponent.get(edge.id);
|
|
640
|
+
}
|
|
641
|
+
// Also get the current edges in case some need disconnecting
|
|
642
|
+
if (core.Is.arrayValue(documents.edges)) {
|
|
643
|
+
for (const edgeId of documents.edges) {
|
|
644
|
+
// If we haven't retrieved the edge then it must be one that needs removing
|
|
645
|
+
if (core.Is.empty(connectedVertices[edgeId])) {
|
|
646
|
+
connectedVertices[edgeId] = await this._auditableItemGraphComponent.get(edgeId);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
let updatedVertex = false;
|
|
652
|
+
// If the blob is set and its hash has changed then we create a new revision
|
|
653
|
+
if (core.Is.uint8Array(blob)) {
|
|
654
|
+
const newBlobHash = this.generateBlobHash(blob);
|
|
655
|
+
if (latestRevision.blobHash !== newBlobHash) {
|
|
656
|
+
// Add the blob to blob storage
|
|
657
|
+
const blobStorageId = await this._blobStorageComponent.create(core.Converter.bytesToBase64(blob), undefined, undefined, undefined, undefined, userIdentity, nodeIdentity);
|
|
658
|
+
const newRevision = core.ObjectHelper.clone(latestRevision);
|
|
659
|
+
newRevision.documentRevision++;
|
|
660
|
+
newRevision.id = `${newRevision.documentId}:${newRevision.documentRevision}`;
|
|
661
|
+
newRevision.blobHash = newBlobHash;
|
|
662
|
+
newRevision.blobStorageId = blobStorageId;
|
|
663
|
+
newRevision.annotationObject = annotationObject;
|
|
664
|
+
if (core.Is.stringValue(latestRevision.attestationId)) {
|
|
665
|
+
newRevision.attestationId = await this.createAttestation(newRevision, userIdentity, nodeIdentity);
|
|
666
|
+
}
|
|
667
|
+
documentVertex.resources.push({
|
|
668
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
669
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Resource,
|
|
670
|
+
resourceObject: newRevision
|
|
671
|
+
});
|
|
672
|
+
updatedVertex = true;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
// If the blob wasn't updated but the annotation object has then update the current revision
|
|
676
|
+
// instead of creating a new one
|
|
677
|
+
if (!updatedVertex &&
|
|
678
|
+
!core.ObjectHelper.equal(latestRevision.annotationObject, annotationObject)) {
|
|
679
|
+
updatedVertex = true;
|
|
680
|
+
latestRevision.annotationObject = annotationObject;
|
|
681
|
+
latestRevision.dateModified = new Date(Date.now()).toISOString();
|
|
682
|
+
}
|
|
683
|
+
const existingEdgeIds = documentVertex.edges?.map(e => e.id) ?? [];
|
|
684
|
+
// Update the edges from the document to the items
|
|
685
|
+
const edgesUpdated = this.updateEdges(documentVertex, auditableItemGraphEdges);
|
|
686
|
+
if (edgesUpdated) {
|
|
687
|
+
updatedVertex = true;
|
|
688
|
+
}
|
|
689
|
+
if (updatedVertex) {
|
|
690
|
+
await this._auditableItemGraphComponent.update(documentVertex, userIdentity, nodeIdentity);
|
|
691
|
+
}
|
|
692
|
+
if (edgesUpdated) {
|
|
693
|
+
await this.updateConnectedEdges(connectedVertices, auditableItemGraphDocumentId, existingEdgeIds, auditableItemGraphEdges, latestRevision.documentId, latestRevision.documentIdFormat, userIdentity, nodeIdentity);
|
|
694
|
+
}
|
|
573
695
|
}
|
|
574
696
|
catch (error) {
|
|
575
697
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
576
698
|
throw error;
|
|
577
699
|
}
|
|
578
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
700
|
+
throw new core.GeneralError(this.CLASS_NAME, "updateFailed", undefined, error);
|
|
579
701
|
}
|
|
580
702
|
}
|
|
581
703
|
/**
|
|
582
|
-
* Get a
|
|
583
|
-
* @param
|
|
584
|
-
* @param identifier The identifier of the document to get.
|
|
704
|
+
* Get a document using it's auditable item graph vertex id and optional revision.
|
|
705
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
585
706
|
* @param options Additional options for the get operation.
|
|
586
707
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
587
708
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
588
709
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
589
710
|
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
590
|
-
* @param
|
|
591
|
-
* @param
|
|
711
|
+
* @param cursor The cursor to get the next chunk of revisions.
|
|
712
|
+
* @param pageSize Page size of items to return, defaults to 1 so only most recent is returned.
|
|
592
713
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
593
714
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
594
715
|
* @returns The documents and revisions if requested, ordered by revision descending, cursor is set if there are more document revisions.
|
|
595
716
|
*/
|
|
596
|
-
async get(
|
|
597
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
598
|
-
core.Urn.guard(this.CLASS_NAME, "identifier", identifier);
|
|
717
|
+
async get(auditableItemGraphDocumentId, options, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
718
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
599
719
|
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);
|
|
720
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId, { includeDeleted: options?.includeRemoved });
|
|
612
721
|
// 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"]);
|
|
722
|
+
const documents = await this.getDocumentsFromVertex(documentVertex, options, cursor, pageSize, userIdentity, nodeIdentity);
|
|
723
|
+
return dataJsonLd.JsonLdProcessor.compact(documents, documents["@context"]);
|
|
621
724
|
}
|
|
622
725
|
catch (error) {
|
|
623
726
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
@@ -627,112 +730,53 @@ class DocumentManagementService {
|
|
|
627
730
|
}
|
|
628
731
|
}
|
|
629
732
|
/**
|
|
630
|
-
* Remove
|
|
631
|
-
* The
|
|
632
|
-
* @param
|
|
633
|
-
* @param
|
|
634
|
-
* @param options Additional options for the remove operation.
|
|
635
|
-
* @param options.removeAllRevisions Flag to remove all revisions of the document, defaults to false.
|
|
733
|
+
* Remove an auditable item graph vertex using it's id.
|
|
734
|
+
* The document dateDeleted will be set, but can still be queried with the includeRemoved flag.
|
|
735
|
+
* @param auditableItemGraphDocumentId The auditable item graph vertex id which contains the document.
|
|
736
|
+
* @param revision The revision of the document to remove.
|
|
636
737
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
637
738
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
638
739
|
* @returns Nothing.
|
|
639
740
|
*/
|
|
640
|
-
async
|
|
641
|
-
core.Urn.guard(this.CLASS_NAME, "
|
|
642
|
-
core.
|
|
741
|
+
async removeRevision(auditableItemGraphDocumentId, revision, userIdentity, nodeIdentity) {
|
|
742
|
+
core.Urn.guard(this.CLASS_NAME, "auditableItemGraphDocumentId", auditableItemGraphDocumentId);
|
|
743
|
+
core.Guards.number(this.CLASS_NAME, "revision", revision);
|
|
643
744
|
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
|
-
}
|
|
745
|
+
const documentVertex = await this._auditableItemGraphComponent.get(auditableItemGraphDocumentId);
|
|
746
|
+
if (core.Is.empty(documentVertex.resources)) {
|
|
747
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNone");
|
|
656
748
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
matchingRevision.dateDeleted = new Date(now).toISOString();
|
|
661
|
-
}
|
|
662
|
-
else {
|
|
663
|
-
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", identifier);
|
|
664
|
-
}
|
|
749
|
+
const docRevisionIndex = documentVertex.resources.findIndex(d => d.resourceObject?.documentRevision === revision);
|
|
750
|
+
if (docRevisionIndex === -1) {
|
|
751
|
+
throw new core.NotFoundError(this.CLASS_NAME, "documentRevisionNotFound", revision.toString());
|
|
665
752
|
}
|
|
666
|
-
|
|
753
|
+
documentVertex.resources.splice(docRevisionIndex, 1);
|
|
754
|
+
await this._auditableItemGraphComponent.update(documentVertex, userIdentity, nodeIdentity);
|
|
667
755
|
}
|
|
668
756
|
catch (error) {
|
|
669
757
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
670
758
|
throw error;
|
|
671
759
|
}
|
|
672
|
-
throw new core.GeneralError(this.CLASS_NAME, "
|
|
760
|
+
throw new core.GeneralError(this.CLASS_NAME, "removeRevisionFailed", undefined, error);
|
|
673
761
|
}
|
|
674
762
|
}
|
|
675
763
|
/**
|
|
676
|
-
*
|
|
677
|
-
* @param
|
|
678
|
-
* @param documentCodes The document codes to query for, if undefined gets all document codes.
|
|
679
|
-
* @param options Additional options for the query operation.
|
|
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.
|
|
764
|
+
* Find all the document with a specific id.
|
|
765
|
+
* @param documentId The document id to find in the graph.
|
|
682
766
|
* @param cursor The cursor to get the next chunk of documents.
|
|
767
|
+
* @param pageSize The page size to get the next chunk of documents.
|
|
683
768
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
684
769
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
685
|
-
* @returns The
|
|
770
|
+
* @returns The graph vertices that contain documents referencing the specified document id.
|
|
686
771
|
*/
|
|
687
|
-
async query(
|
|
688
|
-
core.
|
|
772
|
+
async query(documentId, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
773
|
+
core.Guards.stringValue(this.CLASS_NAME, "documentId", documentId);
|
|
689
774
|
try {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const vertexDocs = this.filterDocumentsFromVertex(vertex);
|
|
696
|
-
let matchingDocIds = vertexDocs;
|
|
697
|
-
if (core.Is.arrayValue(documentCodes)) {
|
|
698
|
-
matchingDocIds = vertexDocs.filter(d => documentCodes.includes(d.documentCode));
|
|
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"]);
|
|
775
|
+
return this._auditableItemGraphComponent.query({
|
|
776
|
+
id: documentId,
|
|
777
|
+
idMode: "both",
|
|
778
|
+
resourceTypes: [documentManagementModels.DocumentTypes.Document]
|
|
779
|
+
}, undefined, undefined, undefined, ["id", "dateCreated", "dateModified", "aliases", "annotationObject", "resources", "edges"], cursor, pageSize);
|
|
736
780
|
}
|
|
737
781
|
catch (error) {
|
|
738
782
|
if (core.BaseError.someErrorName(error, "NotFoundError")) {
|
|
@@ -742,103 +786,144 @@ class DocumentManagementService {
|
|
|
742
786
|
}
|
|
743
787
|
}
|
|
744
788
|
/**
|
|
745
|
-
*
|
|
746
|
-
* @param
|
|
747
|
-
* @
|
|
789
|
+
* Update the edges of the document vertex.
|
|
790
|
+
* @param documentVertex The document vertex to update.
|
|
791
|
+
* @param auditableItemGraphEdges The list of edges to use.
|
|
792
|
+
* @returns True if the edges were updated.
|
|
748
793
|
* @internal
|
|
749
794
|
*/
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
795
|
+
updateEdges(documentVertex, auditableItemGraphEdges) {
|
|
796
|
+
let changed = false;
|
|
797
|
+
const existingEdgeIds = documentVertex.edges?.map(e => e.id) ?? [];
|
|
798
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
799
|
+
for (const aigEdge of auditableItemGraphEdges) {
|
|
800
|
+
const existingIndex = existingEdgeIds.indexOf(aigEdge.id);
|
|
801
|
+
if (existingIndex !== -1) {
|
|
802
|
+
// If the edge already exists then we don't need to add it again
|
|
803
|
+
// We just need to remove it from the list of existing ids
|
|
804
|
+
// any remaining after this loop will be need to be removed
|
|
805
|
+
existingEdgeIds.splice(existingIndex, 1);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
const vertexEdge = {
|
|
809
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
810
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Edge,
|
|
811
|
+
id: aigEdge.id,
|
|
812
|
+
edgeRelationships: ["document"]
|
|
813
|
+
};
|
|
814
|
+
documentVertex.edges ??= [];
|
|
815
|
+
documentVertex.edges?.push(vertexEdge);
|
|
816
|
+
changed = true;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
// Anything left in the existingEdgeIds array means they need to be removed
|
|
820
|
+
if (existingEdgeIds.length > 0 && core.Is.array(documentVertex.edges)) {
|
|
821
|
+
for (const existingEdgeId of existingEdgeIds) {
|
|
822
|
+
const existingIndex = documentVertex.edges.findIndex(e => e.id === existingEdgeId);
|
|
823
|
+
if (existingIndex !== -1) {
|
|
824
|
+
documentVertex.edges.splice(existingIndex, 1);
|
|
825
|
+
changed = true;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
766
829
|
}
|
|
767
|
-
return
|
|
830
|
+
return changed;
|
|
768
831
|
}
|
|
769
832
|
/**
|
|
770
|
-
*
|
|
771
|
-
* @param
|
|
833
|
+
* Update the edges.
|
|
834
|
+
* @param connectedVertices The connected vertices for the edges.
|
|
835
|
+
* @param auditableItemGraphDocumentId The document id to use.
|
|
836
|
+
* @param documentVertex The document vertex to update.
|
|
837
|
+
* @param auditableItemGraphEdges The list of edges to use.
|
|
772
838
|
* @param documentId The document identifier.
|
|
773
|
-
* @param
|
|
774
|
-
* @
|
|
775
|
-
* @
|
|
776
|
-
*/
|
|
777
|
-
createIdentifier(documentCode, documentId, documentRevision) {
|
|
778
|
-
const docCode = this.parseDocumentCode(documentCode);
|
|
779
|
-
return `documents:${docCode}:${this.encodeDocumentIdentifier(documentId, documentRevision)}`;
|
|
780
|
-
}
|
|
781
|
-
/**
|
|
782
|
-
* Parse the document identifier from the full identifier.
|
|
783
|
-
* @param identifier The full identifier to parse.
|
|
784
|
-
* @returns The document identifier.
|
|
785
|
-
* @internal
|
|
786
|
-
*/
|
|
787
|
-
parseDocumentId(identifier) {
|
|
788
|
-
const urn = core.Urn.fromValidString(identifier);
|
|
789
|
-
const remainingParts = urn.namespaceSpecificParts();
|
|
790
|
-
if (remainingParts.length < 2) {
|
|
791
|
-
throw new core.GeneralError(this.CLASS_NAME, "invalidDocumentId", { identifier });
|
|
792
|
-
}
|
|
793
|
-
const documentCode = `unece:DocumentCodeList#${remainingParts[0]}`;
|
|
794
|
-
const { documentId, documentRevision } = this.decodeDocumentIdentifier(urn.namespaceSpecific(1));
|
|
795
|
-
return { documentCode, documentId, documentRevision };
|
|
796
|
-
}
|
|
797
|
-
/**
|
|
798
|
-
* Parse the document code from the full identifier.
|
|
799
|
-
* @param documentCode The document code to parse.
|
|
800
|
-
* @returns The document code.
|
|
839
|
+
* @param documentIdFormat The format of the document identifier.
|
|
840
|
+
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
841
|
+
* @param nodeIdentity The node identity to use for vault operations.
|
|
801
842
|
* @internal
|
|
802
843
|
*/
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
844
|
+
async updateConnectedEdges(connectedVertices, auditableItemGraphDocumentId, existingEdgeIds, auditableItemGraphEdges, documentId, documentIdFormat, userIdentity, nodeIdentity) {
|
|
845
|
+
if (core.Is.array(auditableItemGraphEdges)) {
|
|
846
|
+
for (const aigEdge of auditableItemGraphEdges) {
|
|
847
|
+
const connected = connectedVertices[aigEdge.id];
|
|
848
|
+
if (!core.Is.empty(connected)) {
|
|
849
|
+
let updatedConnected = false;
|
|
850
|
+
const existingIndex = existingEdgeIds.indexOf(aigEdge.id);
|
|
851
|
+
if (existingIndex !== -1) {
|
|
852
|
+
// If the edge already exists we remove it from the list of existing ids
|
|
853
|
+
// any remaining after this loop will be need to be disconnected
|
|
854
|
+
existingEdgeIds.splice(existingIndex, 1);
|
|
855
|
+
}
|
|
856
|
+
// Add the edge with the document vertex id if it doesn't already exist
|
|
857
|
+
const hasEdge = connected.edges?.some(e => e.id === auditableItemGraphDocumentId);
|
|
858
|
+
if (!hasEdge) {
|
|
859
|
+
const vertexEdge = {
|
|
860
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
861
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Edge,
|
|
862
|
+
id: auditableItemGraphDocumentId,
|
|
863
|
+
edgeRelationships: ["document"]
|
|
864
|
+
};
|
|
865
|
+
connected.edges ??= [];
|
|
866
|
+
connected.edges?.push(vertexEdge);
|
|
867
|
+
updatedConnected = true;
|
|
868
|
+
}
|
|
869
|
+
// Add alias with the document id if option flag is set and it doesn't already exist
|
|
870
|
+
if (aigEdge.addAlias) {
|
|
871
|
+
const alias = connected.aliases?.find(a => a.id === documentId);
|
|
872
|
+
if (core.Is.empty(alias)) {
|
|
873
|
+
// No existing alias, so create one
|
|
874
|
+
const vertexAlias = {
|
|
875
|
+
"@context": auditableItemGraphModels.AuditableItemGraphContexts.ContextRoot,
|
|
876
|
+
type: auditableItemGraphModels.AuditableItemGraphTypes.Alias,
|
|
877
|
+
id: documentId,
|
|
878
|
+
aliasFormat: documentIdFormat,
|
|
879
|
+
annotationObject: aigEdge.aliasAnnotationObject
|
|
880
|
+
};
|
|
881
|
+
connected.aliases ??= [];
|
|
882
|
+
connected.aliases?.push(vertexAlias);
|
|
883
|
+
updatedConnected = true;
|
|
884
|
+
}
|
|
885
|
+
else if (!core.ObjectHelper.equal(alias.annotationObject, aigEdge.aliasAnnotationObject) ||
|
|
886
|
+
documentIdFormat !== alias.aliasFormat) {
|
|
887
|
+
// The alias already exists, but the format or annotation object has changed
|
|
888
|
+
alias.annotationObject = aigEdge.aliasAnnotationObject;
|
|
889
|
+
alias.aliasFormat = documentIdFormat;
|
|
890
|
+
updatedConnected = true;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (updatedConnected) {
|
|
894
|
+
await this._auditableItemGraphComponent.update(connected, userIdentity, nodeIdentity);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
808
898
|
}
|
|
809
|
-
|
|
810
|
-
if (
|
|
811
|
-
|
|
899
|
+
// Anything left in the existingEdgeIds array means they need to be removed
|
|
900
|
+
if (existingEdgeIds.length > 0) {
|
|
901
|
+
for (const existingEdgeId of existingEdgeIds) {
|
|
902
|
+
const connected = connectedVertices[existingEdgeId];
|
|
903
|
+
if (!core.Is.empty(connected)) {
|
|
904
|
+
let updatedConnected = false;
|
|
905
|
+
// Remove the edge from the connected vertex
|
|
906
|
+
if (core.Is.arrayValue(connected.edges)) {
|
|
907
|
+
const existingIndex = connected.edges.findIndex(e => e.id === auditableItemGraphDocumentId);
|
|
908
|
+
if (existingIndex !== -1) {
|
|
909
|
+
connected.edges.splice(existingIndex, 1);
|
|
910
|
+
updatedConnected = true;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
// Remove the alias from the connected vertex
|
|
914
|
+
if (core.Is.arrayValue(connected.aliases)) {
|
|
915
|
+
const existingIndex = connected.aliases.findIndex(e => e.id === documentId);
|
|
916
|
+
if (existingIndex !== -1) {
|
|
917
|
+
connected.aliases.splice(existingIndex, 1);
|
|
918
|
+
updatedConnected = true;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
if (updatedConnected) {
|
|
922
|
+
await this._auditableItemGraphComponent.update(connected, userIdentity, nodeIdentity);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
}
|
|
812
926
|
}
|
|
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
927
|
}
|
|
843
928
|
/**
|
|
844
929
|
* Generate a hash for the blob data.
|
|
@@ -851,47 +936,71 @@ class DocumentManagementService {
|
|
|
851
936
|
}
|
|
852
937
|
/**
|
|
853
938
|
* Get the documents from the auditable item graph vertex.
|
|
854
|
-
* @param
|
|
855
|
-
* @param identifier The full document identifier.
|
|
939
|
+
* @param documentVertex The vertex containing the documents.
|
|
856
940
|
* @param options Additional options for the get operation.
|
|
857
941
|
* @param options.includeBlobStorageMetadata Flag to include the blob storage metadata for the document, defaults to false.
|
|
858
942
|
* @param options.includeBlobStorageData Flag to include the blob storage data for the document, defaults to false.
|
|
859
943
|
* @param options.includeAttestation Flag to include the attestation information for the document, defaults to false.
|
|
860
944
|
* @param options.includeRemoved Flag to include deleted documents, defaults to false.
|
|
861
|
-
* @param
|
|
862
|
-
* @param
|
|
945
|
+
* @param cursor The cursor to get the next chunk of revisions.
|
|
946
|
+
* @param pageSize Page size of items to return, defaults to 1 so only most recent is returned.
|
|
863
947
|
* @param userIdentity The identity to perform the auditable item graph operation with.
|
|
864
948
|
* @param nodeIdentity The node identity to use for vault operations.
|
|
865
949
|
* @returns The finalised list of documents.
|
|
866
950
|
* @internal
|
|
867
951
|
*/
|
|
868
|
-
async
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
952
|
+
async getDocumentsFromVertex(documentVertex, options, cursor, pageSize, userIdentity, nodeIdentity) {
|
|
953
|
+
const docList = {
|
|
954
|
+
"@context": [
|
|
955
|
+
documentManagementModels.DocumentContexts.ContextRoot,
|
|
956
|
+
documentManagementModels.DocumentContexts.ContextRootCommon,
|
|
957
|
+
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
958
|
+
],
|
|
959
|
+
type: documentManagementModels.DocumentTypes.DocumentList,
|
|
960
|
+
documents: []
|
|
961
|
+
};
|
|
962
|
+
if (core.Is.arrayValue(documentVertex.resources)) {
|
|
963
|
+
// Sort by newest revision first
|
|
964
|
+
documentVertex.resources.sort((a, b) => (core.Coerce.number(b.resourceObject?.documentRevision) ?? 0) -
|
|
965
|
+
(core.Coerce.number(a.resourceObject?.documentRevision) ?? 0));
|
|
966
|
+
const startIndex = core.Coerce.integer(cursor) ?? 0;
|
|
967
|
+
const endIndex = Math.min(startIndex + (pageSize ?? 1), documentVertex.resources.length);
|
|
968
|
+
const slicedResources = documentVertex.resources.slice(startIndex, endIndex);
|
|
969
|
+
docList.cursor =
|
|
970
|
+
documentVertex.resources.length > endIndex ? (endIndex + 1).toString() : undefined;
|
|
971
|
+
const includeBlobStorageMetadata = options?.includeBlobStorageMetadata ?? false;
|
|
972
|
+
const includeBlobStorageData = options?.includeBlobStorageData ?? false;
|
|
973
|
+
const includeAttestation = options?.includeAttestation ?? false;
|
|
974
|
+
for (let i = 0; i < slicedResources.length; i++) {
|
|
975
|
+
const document = slicedResources[i].resourceObject;
|
|
976
|
+
if (core.Is.object(document)) {
|
|
977
|
+
docList.documents.push(document);
|
|
978
|
+
if (includeBlobStorageMetadata || includeBlobStorageData) {
|
|
979
|
+
const blobEntry = await this._blobStorageComponent.get(document.blobStorageId, includeBlobStorageData, userIdentity, nodeIdentity);
|
|
980
|
+
document.blobStorageEntry = blobEntry;
|
|
981
|
+
if (!docList["@context"].includes(blobStorageModels.BlobStorageContexts.ContextRoot)) {
|
|
982
|
+
docList["@context"].push(blobStorageModels.BlobStorageContexts.ContextRoot);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
if (includeAttestation && core.Is.stringValue(document.attestationId)) {
|
|
986
|
+
const attestationInformation = await this._attestationComponent.get(document.attestationId);
|
|
987
|
+
document.attestationInformation = attestationInformation;
|
|
988
|
+
if (!docList["@context"].includes(attestationModels.AttestationContexts.ContextRoot)) {
|
|
989
|
+
docList["@context"].push(attestationModels.AttestationContexts.ContextRoot);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
886
994
|
}
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
995
|
+
if (core.Is.arrayValue(documentVertex.edges)) {
|
|
996
|
+
docList.edges ??= [];
|
|
997
|
+
for (const edge of documentVertex.edges) {
|
|
998
|
+
if (core.Is.object(edge)) {
|
|
999
|
+
docList.edges.push(edge.id);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
891
1002
|
}
|
|
892
|
-
|
|
893
|
-
document.revisionCursor = nextRevisionCursor;
|
|
894
|
-
return document;
|
|
1003
|
+
return docList;
|
|
895
1004
|
}
|
|
896
1005
|
/**
|
|
897
1006
|
* Create an attestation for the document.
|
|
@@ -908,6 +1017,7 @@ class DocumentManagementService {
|
|
|
908
1017
|
standardsSchemaOrg.SchemaOrgContexts.ContextRoot
|
|
909
1018
|
],
|
|
910
1019
|
type: documentManagementModels.DocumentTypes.DocumentAttestation,
|
|
1020
|
+
id: document.id,
|
|
911
1021
|
documentId: document.documentId,
|
|
912
1022
|
documentCode: document.documentCode,
|
|
913
1023
|
documentRevision: document.documentRevision,
|
|
@@ -928,10 +1038,11 @@ const restEntryPoints = [
|
|
|
928
1038
|
];
|
|
929
1039
|
|
|
930
1040
|
exports.DocumentManagementService = DocumentManagementService;
|
|
1041
|
+
exports.documentManagementCreate = documentManagementCreate;
|
|
931
1042
|
exports.documentManagementGet = documentManagementGet;
|
|
932
1043
|
exports.documentManagementQuery = documentManagementQuery;
|
|
933
1044
|
exports.documentManagementRemove = documentManagementRemove;
|
|
934
|
-
exports.
|
|
1045
|
+
exports.documentManagementUpdate = documentManagementUpdate;
|
|
935
1046
|
exports.generateRestRoutesDocumentManagement = generateRestRoutesDocumentManagement;
|
|
936
1047
|
exports.restEntryPoints = restEntryPoints;
|
|
937
1048
|
exports.tagsDocumentManagement = tagsDocumentManagement;
|