@webex/internal-plugin-ediscovery 2.59.2 → 2.59.3-next.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/src/ediscovery.js CHANGED
@@ -1,457 +1,457 @@
1
- /* eslint-disable prefer-template */
2
- /* eslint-disable no-useless-escape */
3
- /*!
4
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
5
- */
6
- import {waitForValue, WebexPlugin} from '@webex/webex-core';
7
- import {oneFlight} from '@webex/common';
8
-
9
- import {InvalidEmailAddressError} from './ediscovery-error';
10
-
11
- /**
12
- * Creates a unique oneflight key for a request from the reportId and options params
13
- * It is important that the offset params are included if present to ensure paged requests get back the correct data
14
- * @param {Object} reportId - A set of criteria for determining the focus of the search
15
- * @param {Object} options - optional parameters for this method
16
- * @returns {String} oneFlight key which is a composite of the request parameters
17
- */
18
- function createOneFlightKey(reportId, options) {
19
- let key = String(reportId);
20
-
21
- if (options) {
22
- if (options.offset) {
23
- key += String(options.offset);
24
- }
25
- if (options.size) {
26
- key += String(options.size);
27
- }
28
- if (options.types) {
29
- key += String(options.types);
30
- }
31
- }
32
-
33
- return key;
34
- }
35
-
36
- /**
37
- * @class EDiscovery is used by compliance officers to run compliance reports
38
- *
39
- */
40
- const EDiscovery = WebexPlugin.extend({
41
- namespace: 'EDiscovery',
42
-
43
- session: {
44
- contentContainerCache: {
45
- type: 'object',
46
- default() {
47
- return new Map();
48
- }
49
- }
50
- },
51
-
52
- @waitForValue('@')
53
- /**
54
- * Creates a compliance report with a specific set of search parameters
55
- * @param {Object} reportRequest - A set of criteria for determining the focus of the search
56
- * @param {Object} options - optional parameters for this method
57
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
58
- * @returns {Promise<ResponseEntity>} Http response containing the new report record
59
- */
60
- async createReport(reportRequest, options) {
61
- if (!reportRequest) {
62
- throw Error('Undefined parameter');
63
- }
64
-
65
- // use spread operator to set default options
66
- options = {...this.config.defaultOptions, ...options};
67
-
68
- const body = reportRequest;
69
-
70
- try {
71
- return await this.request({
72
- method: 'POST',
73
- service: 'ediscovery',
74
- resource: 'reports',
75
- timeout: options.timeoutMs,
76
- body
77
- });
78
- }
79
- catch (reason) {
80
- return this._handleReportRequestError(reason);
81
- }
82
- },
83
-
84
- /**
85
- * Checks the error from createReport and ensures the appropriate error is sent to the client
86
- * @param {Error} reason - Error response thrown by the request to createReport
87
- * @returns {Promise<Error>} Promise rejection containing the error
88
- */
89
- _handleReportRequestError(reason) {
90
- if (reason.body.errorCode === InvalidEmailAddressError.getErrorCode()) {
91
- try {
92
- const invalidEmails = JSON.parse(reason.body.message);
93
-
94
- if (Array.isArray(invalidEmails) && invalidEmails.length) {
95
- const invalidEmailAddressError = new InvalidEmailAddressError(invalidEmails);
96
-
97
- return Promise.reject(invalidEmailAddressError);
98
- }
99
-
100
- this.logger.warn('InvalidEmailAddress error received but the list could not be parsed to the correct format.');
101
- }
102
- catch (error) {
103
- // assume syntax error and continue
104
- this.logger.error('InvalidEmailAddress error received but an error occured while parsing the emails.');
105
- }
106
- }
107
-
108
- return Promise.reject(reason);
109
- },
110
-
111
- @waitForValue('@')
112
- /**
113
- * Retrieves information relating to a specified report
114
- * @param {UUID} reportId - Id of the report being requested
115
- * @param {Object} options - optional parameters for this method
116
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
117
- * @returns {Promise<ResponseEntity<ReportRecord>>} Http response containing the specified report record
118
- */
119
- async getReport(reportId, options) {
120
- if (!reportId) {
121
- throw Error('Undefined parameter');
122
- }
123
-
124
- // use spread operator to set default options
125
- options = {...this.config.defaultOptions, ...options};
126
-
127
- return this.request({
128
- method: 'GET',
129
- service: 'ediscovery',
130
- resource: `reports/${reportId}`,
131
- timeout: options.timeoutMs
132
- });
133
- },
134
-
135
- @waitForValue('@')
136
- /**
137
- * Retrieves all the compliance officers reports
138
- * @param {Object} options - optional parameters for this method
139
- * @param {number} options.offset - start position from which to retrieve records
140
- * @param {number} options.size - the number of records to retrieve
141
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
142
- * @returns {Promise<ResponseEntity<Array<ReportRecord>>>} Http Response containing a list of report records
143
- */
144
- async getReports(options) {
145
- // use spread operator to set default options
146
- options = {...this.config.defaultOptions, ...options};
147
-
148
- return this.request({
149
- method: 'GET',
150
- service: 'ediscovery',
151
- resource: 'reports',
152
- qs: {offset: options.offset, size: options.size},
153
- timeout: options.timeoutMs
154
- });
155
- },
156
-
157
- @waitForValue('@')
158
- /**
159
- * Deletes a specified report
160
- * @param {UUID} reportId - Id of the report being requested for deletion
161
- * @param {Object} options - optional parameters for this method
162
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
163
- * @returns {Promise<ResponseEntity>} HttpResponse indicating if delete was successful
164
- */
165
- async deleteReport(reportId, options) {
166
- if (!reportId) {
167
- throw Error('Undefined parameter');
168
- }
169
-
170
- // use spread operator to set default options
171
- options = {...this.config.defaultOptions, ...options};
172
-
173
- return this.request({
174
- method: 'DELETE',
175
- service: 'ediscovery',
176
- resource: `reports/${reportId}`,
177
- timeout: options.timeoutMs
178
- });
179
- },
180
-
181
- @waitForValue('@')
182
- /**
183
- * Restarts a completed or cancelled report so that it begins again from scratch
184
- * @param {UUID} reportId - Id of the report being requested
185
- * @param {Object} options - optional parameters for this method
186
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
187
- * @returns {Promise<ResponseEntity<ReportRecord>>} Http response containing the report record
188
- */
189
- async restartReport(reportId, options) {
190
- if (!reportId) {
191
- throw Error('Undefined parameter');
192
- }
193
-
194
- // use spread operator to set default options
195
- options = {...this.config.defaultOptions, ...options};
196
-
197
- return this.request({
198
- method: 'PUT',
199
- service: 'ediscovery',
200
- resource: `reports/${reportId}`,
201
- timeout: options.timeoutMs
202
- });
203
- },
204
-
205
- @waitForValue('@')
206
- @oneFlight({keyFactory: (reportId, options) => createOneFlightKey(reportId, options)})
207
- /**
208
- * Retrieves content associated with a report
209
- * @param {UUID|string} reportId - UUID or url of the report which contains the content
210
- * @param {Object} options - optional parameters for this method
211
- * @param {number} options.offset - start position from which to retrieve records
212
- * @param {number} options.size - the number of records to retrieve
213
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
214
- * @returns {Promise<ResponseEntity<[Activity]>>} Http response containing the activities
215
- */
216
- async getContent(reportId, options) {
217
- if (!reportId) {
218
- throw Error('Undefined parameter');
219
- }
220
-
221
- // use spread operator to set default options
222
- options = {...this.config.defaultOptions, ...options};
223
-
224
- const [requestOptions] = this._createRequestOptions(reportId, '/contents');
225
-
226
- return this.request({
227
- method: 'GET',
228
- ...requestOptions,
229
- qs: {offset: options.offset, size: options.size},
230
- timeout: options.timeoutMs
231
- });
232
- },
233
-
234
- @waitForValue('@')
235
- @oneFlight({keyFactory: (reportId, options) => createOneFlightKey(reportId, options)})
236
- /**
237
- * Retrieves a list of content containers relevant to a specified report
238
- * @param {UUID|string} reportId - UUID or url of the report being requested
239
- * @param {Object} options - optional parameters for this method
240
- * @param {number} options.offset - start position from which to retrieve records
241
- * @param {number} options.size - the number of records to retrieve
242
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
243
- * @param {Set<Object>} options.types - Set of ContentContainerTypes to be retrieved
244
- * @returns {Promise<ResponseEntity<ContentContainer>>} Http response containing the content containers
245
- */
246
- async getContentContainer(reportId, options) {
247
- if (!reportId) {
248
- throw Error('Undefined parameter');
249
- }
250
-
251
- // use spread operator to set default options
252
- options = {...this.config.defaultOptions, ...options};
253
-
254
- const [requestOptions, reportUUID] = this._createRequestOptions(reportId, '/contents/container');
255
-
256
- const res = await this.request({
257
- method: 'GET',
258
- ...requestOptions,
259
- qs: {offset: options.offset, size: options.size},
260
- timeout: options.timeoutMs,
261
- types: options.types
262
- });
263
-
264
- await this._writeToContentContainerCache(reportUUID, res.body);
265
-
266
- return res;
267
- },
268
-
269
- @waitForValue('@')
270
- @oneFlight({keyFactory: (reportId, containerId) => String(reportId + containerId)})
271
- /**
272
- * Retrieves information for a specific content container relevant to a specified report
273
- * @param {UUID|string} reportId - UUID or url of the report being requested
274
- * @param {UUID} containerId - Id of the contenyt container being requested
275
- * @param {Object} options - optional parameters for this method
276
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
277
- * @returns {Promise<ResponseEntity<ContentContainer>>} Http response containing the specified content container
278
- */
279
- async getContentContainerByContainerId(reportId, containerId, options) {
280
- if (!reportId || !containerId) {
281
- throw Error('Undefined parameter');
282
- }
283
-
284
- // use spread operator to set default options
285
- options = {...this.config.defaultOptions, ...options};
286
-
287
- const [requestOptions, reportUUID] = this._createRequestOptions(reportId, `/contents/container/${containerId}`);
288
-
289
- // If this content container has already been cached then it can be retrieved from there instead of making a network call to ediscovery
290
- if (this.contentContainerCache.has(reportUUID) && this.contentContainerCache.get(reportUUID).has(containerId)) {
291
- return {body: this.contentContainerCache.get(reportUUID).get(containerId), statusCode: 200};
292
- }
293
-
294
- this.logger.warn(`Cache miss for container ${containerId} in contentContainerCache`);
295
-
296
- const res = await this.request({
297
- method: 'GET',
298
- ...requestOptions,
299
- qs: {offset: options.offset, size: options.size},
300
- timeout: options.timeoutMs
301
- });
302
-
303
- await this._writeToContentContainerCache(reportUUID, [res.body]);
304
-
305
- return res;
306
- },
307
-
308
- /**
309
- * The results of a getContentContainer or getContentContainerByContainerId request are written to the contentContainerCache
310
- * since information for a container is likely to be accessed very frequently when decrypting activities
311
- * @param {UUID} reportId - Id of the report which contains the relevant content summary
312
- * @param {Array<Object>} containers - List of the container objects to be written to the cache
313
- * @returns {Promise} - Promise resolution indicating operation is complete
314
- */
315
- _writeToContentContainerCache(reportId, containers) {
316
- if (!reportId || !containers || !containers.length) {
317
- return;
318
- }
319
-
320
- if (!this.contentContainerCache.has(reportId)) {
321
- this.contentContainerCache.set(reportId, new Map());
322
- }
323
-
324
- for (const container of containers) {
325
- if (container && container.containerId) {
326
- try {
327
- this.contentContainerCache.get(reportId).set(container.containerId, container);
328
- }
329
- catch (error) {
330
- this.logger.error(`Error adding ${container.containerId} to contentContainerCache: ${error}`);
331
- }
332
- }
333
- else {
334
- this.logger.error('Error adding undefined container to contentContainerCache');
335
- }
336
- }
337
- },
338
-
339
- /**
340
- * Wipe the cache used by eDiscovery to store the space summaries and content containers.
341
- * Good practice to clear it down when finished with a report to save RAM.
342
- * @returns {undefined}
343
- */
344
- clearCache() {
345
- this.contentContainerCache.clear();
346
- },
347
-
348
- /**
349
- * Retrieves a uuid string from a report url
350
- * @param {String} reportUrl - full destination address (including report id parameter) for the http request being sent
351
- * e.g. 'http://ediscovery-intb.wbx2.com/ediscovery/api/v1/reports/3b10e625-2bd5-4efa-b866-58d6c93c505c'
352
- * @returns {String} - uuid of the report
353
- */
354
- _getReportIdFromUrl(reportUrl) {
355
- if (reportUrl) {
356
- const uuids = reportUrl.match(/[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/);
357
-
358
- if (uuids && uuids.length > 0) {
359
- return uuids[0];
360
- }
361
- }
362
-
363
- return '';
364
- },
365
-
366
- _isUrl(string) {
367
- // Regex found from `https://ihateregex.io/expr/url`
368
- return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*)/g.test(string);
369
- },
370
-
371
- /**
372
- * Create the appropriate request options based on whether the reportId is a url or a uuid.
373
- * @param {UUID|string} reportId - May be either a url for the report or a uuid.
374
- * e.g. 'http://ediscovery-intb.wbx2.com/ediscovery/api/v1/reports/3b10e625-2bd5-4efa-b866-58d6c93c505c' or '3b10e625-2bd5-4efa-b866-58d6c93c505c'.
375
- * @param {String} resource - The resource on the remote server to request
376
- * @returns {[Options, uuid]} - The options to pass to `request` and the report uuid.
377
- */
378
- _createRequestOptions(reportId, resource) {
379
- let requestOptions;
380
- let reportUUID;
381
- const isUrl = this._isUrl(reportId);
382
-
383
- if (isUrl) {
384
- reportUUID = this._getReportIdFromUrl(reportId);
385
-
386
- if (!reportUUID) {
387
- throw Error('Report url does not contain a report id');
388
- }
389
-
390
- // Ensure the url is formatted to
391
- // https://ediscovery.intb1.ciscospark.com/ediscovery/api/v1/reports/16bf0d01-b1f7-483b-89a2-915144158fb9
392
- // index.js for example passes the url in as
393
- // https://ediscovery.intb1.ciscospark.com/ediscovery/api/v1/reports/16bf0d01-b1f7-483b-89a2-915144158fb9/contents
394
- const reportUrl = reportId.substring(0, reportId.lastIndexOf(reportUUID) + reportUUID.length);
395
-
396
- requestOptions = {
397
- url: reportUrl + resource
398
- };
399
- }
400
- else {
401
- requestOptions = {
402
- service: 'ediscovery',
403
- resource: `reports/${reportId}/${resource}`
404
- };
405
- reportUUID = reportId;
406
- }
407
-
408
- return [requestOptions, reportUUID];
409
- },
410
-
411
- @waitForValue('@')
412
- /**
413
- * Retrieves a config object from the service which can be used by the client for optimal performance, e.g. content page size
414
- * @param {Object} options - optional parameters for this method
415
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
416
- * @returns {Promise<Config>} Http response containing the config object
417
- */
418
- async getClientConfig(options) {
419
- // use spread operator to set default options
420
- options = {...this.config.defaultOptions, ...options};
421
-
422
- return this.request({
423
- method: 'GET',
424
- service: 'ediscovery',
425
- resource: 'reports/clientconfig',
426
- timeout: options.timeoutMs
427
- });
428
- },
429
-
430
- @waitForValue('@')
431
- /**
432
- * Submits an audit event to the eDiscovery service for admin use. Only expected to be used for
433
- * the getContentContainer API
434
- * @param {UUID} reportId - Id of the report to send an audit log for
435
- * @param {Object} options - optional parameters for this method
436
- * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
437
- * @returns {Promise<Config>} Http response containing the config object
438
- */
439
- async postAuditLog(reportId, options) {
440
- if (!reportId) {
441
- throw Error('No report ID specified');
442
- }
443
-
444
- // use spread operator to set default options
445
- options = {...this.config.defaultOptions, ...options};
446
-
447
- return this.request({
448
- method: 'POST',
449
- service: 'ediscovery',
450
- resource: `reports/${reportId}/audit/summary-download`,
451
- timeout: options.timeoutMs
452
- });
453
- }
454
-
455
- });
456
-
457
- export default EDiscovery;
1
+ /* eslint-disable prefer-template */
2
+ /* eslint-disable no-useless-escape */
3
+ /*!
4
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
5
+ */
6
+ import {waitForValue, WebexPlugin} from '@webex/webex-core';
7
+ import {oneFlight} from '@webex/common';
8
+
9
+ import {InvalidEmailAddressError} from './ediscovery-error';
10
+
11
+ /**
12
+ * Creates a unique oneflight key for a request from the reportId and options params
13
+ * It is important that the offset params are included if present to ensure paged requests get back the correct data
14
+ * @param {Object} reportId - A set of criteria for determining the focus of the search
15
+ * @param {Object} options - optional parameters for this method
16
+ * @returns {String} oneFlight key which is a composite of the request parameters
17
+ */
18
+ function createOneFlightKey(reportId, options) {
19
+ let key = String(reportId);
20
+
21
+ if (options) {
22
+ if (options.offset) {
23
+ key += String(options.offset);
24
+ }
25
+ if (options.size) {
26
+ key += String(options.size);
27
+ }
28
+ if (options.types) {
29
+ key += String(options.types);
30
+ }
31
+ }
32
+
33
+ return key;
34
+ }
35
+
36
+ /**
37
+ * @class EDiscovery is used by compliance officers to run compliance reports
38
+ *
39
+ */
40
+ const EDiscovery = WebexPlugin.extend({
41
+ namespace: 'EDiscovery',
42
+
43
+ session: {
44
+ contentContainerCache: {
45
+ type: 'object',
46
+ default() {
47
+ return new Map();
48
+ }
49
+ }
50
+ },
51
+
52
+ @waitForValue('@')
53
+ /**
54
+ * Creates a compliance report with a specific set of search parameters
55
+ * @param {Object} reportRequest - A set of criteria for determining the focus of the search
56
+ * @param {Object} options - optional parameters for this method
57
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
58
+ * @returns {Promise<ResponseEntity>} Http response containing the new report record
59
+ */
60
+ async createReport(reportRequest, options) {
61
+ if (!reportRequest) {
62
+ throw Error('Undefined parameter');
63
+ }
64
+
65
+ // use spread operator to set default options
66
+ options = {...this.config.defaultOptions, ...options};
67
+
68
+ const body = reportRequest;
69
+
70
+ try {
71
+ return await this.request({
72
+ method: 'POST',
73
+ service: 'ediscovery',
74
+ resource: 'reports',
75
+ timeout: options.timeoutMs,
76
+ body
77
+ });
78
+ }
79
+ catch (reason) {
80
+ return this._handleReportRequestError(reason);
81
+ }
82
+ },
83
+
84
+ /**
85
+ * Checks the error from createReport and ensures the appropriate error is sent to the client
86
+ * @param {Error} reason - Error response thrown by the request to createReport
87
+ * @returns {Promise<Error>} Promise rejection containing the error
88
+ */
89
+ _handleReportRequestError(reason) {
90
+ if (reason.body.errorCode === InvalidEmailAddressError.getErrorCode()) {
91
+ try {
92
+ const invalidEmails = JSON.parse(reason.body.message);
93
+
94
+ if (Array.isArray(invalidEmails) && invalidEmails.length) {
95
+ const invalidEmailAddressError = new InvalidEmailAddressError(invalidEmails);
96
+
97
+ return Promise.reject(invalidEmailAddressError);
98
+ }
99
+
100
+ this.logger.warn('InvalidEmailAddress error received but the list could not be parsed to the correct format.');
101
+ }
102
+ catch (error) {
103
+ // assume syntax error and continue
104
+ this.logger.error('InvalidEmailAddress error received but an error occured while parsing the emails.');
105
+ }
106
+ }
107
+
108
+ return Promise.reject(reason);
109
+ },
110
+
111
+ @waitForValue('@')
112
+ /**
113
+ * Retrieves information relating to a specified report
114
+ * @param {UUID} reportId - Id of the report being requested
115
+ * @param {Object} options - optional parameters for this method
116
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
117
+ * @returns {Promise<ResponseEntity<ReportRecord>>} Http response containing the specified report record
118
+ */
119
+ async getReport(reportId, options) {
120
+ if (!reportId) {
121
+ throw Error('Undefined parameter');
122
+ }
123
+
124
+ // use spread operator to set default options
125
+ options = {...this.config.defaultOptions, ...options};
126
+
127
+ return this.request({
128
+ method: 'GET',
129
+ service: 'ediscovery',
130
+ resource: `reports/${reportId}`,
131
+ timeout: options.timeoutMs
132
+ });
133
+ },
134
+
135
+ @waitForValue('@')
136
+ /**
137
+ * Retrieves all the compliance officers reports
138
+ * @param {Object} options - optional parameters for this method
139
+ * @param {number} options.offset - start position from which to retrieve records
140
+ * @param {number} options.size - the number of records to retrieve
141
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
142
+ * @returns {Promise<ResponseEntity<Array<ReportRecord>>>} Http Response containing a list of report records
143
+ */
144
+ async getReports(options) {
145
+ // use spread operator to set default options
146
+ options = {...this.config.defaultOptions, ...options};
147
+
148
+ return this.request({
149
+ method: 'GET',
150
+ service: 'ediscovery',
151
+ resource: 'reports',
152
+ qs: {offset: options.offset, size: options.size},
153
+ timeout: options.timeoutMs
154
+ });
155
+ },
156
+
157
+ @waitForValue('@')
158
+ /**
159
+ * Deletes a specified report
160
+ * @param {UUID} reportId - Id of the report being requested for deletion
161
+ * @param {Object} options - optional parameters for this method
162
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
163
+ * @returns {Promise<ResponseEntity>} HttpResponse indicating if delete was successful
164
+ */
165
+ async deleteReport(reportId, options) {
166
+ if (!reportId) {
167
+ throw Error('Undefined parameter');
168
+ }
169
+
170
+ // use spread operator to set default options
171
+ options = {...this.config.defaultOptions, ...options};
172
+
173
+ return this.request({
174
+ method: 'DELETE',
175
+ service: 'ediscovery',
176
+ resource: `reports/${reportId}`,
177
+ timeout: options.timeoutMs
178
+ });
179
+ },
180
+
181
+ @waitForValue('@')
182
+ /**
183
+ * Restarts a completed or cancelled report so that it begins again from scratch
184
+ * @param {UUID} reportId - Id of the report being requested
185
+ * @param {Object} options - optional parameters for this method
186
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
187
+ * @returns {Promise<ResponseEntity<ReportRecord>>} Http response containing the report record
188
+ */
189
+ async restartReport(reportId, options) {
190
+ if (!reportId) {
191
+ throw Error('Undefined parameter');
192
+ }
193
+
194
+ // use spread operator to set default options
195
+ options = {...this.config.defaultOptions, ...options};
196
+
197
+ return this.request({
198
+ method: 'PUT',
199
+ service: 'ediscovery',
200
+ resource: `reports/${reportId}`,
201
+ timeout: options.timeoutMs
202
+ });
203
+ },
204
+
205
+ @waitForValue('@')
206
+ @oneFlight({keyFactory: (reportId, options) => createOneFlightKey(reportId, options)})
207
+ /**
208
+ * Retrieves content associated with a report
209
+ * @param {UUID|string} reportId - UUID or url of the report which contains the content
210
+ * @param {Object} options - optional parameters for this method
211
+ * @param {number} options.offset - start position from which to retrieve records
212
+ * @param {number} options.size - the number of records to retrieve
213
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
214
+ * @returns {Promise<ResponseEntity<[Activity]>>} Http response containing the activities
215
+ */
216
+ async getContent(reportId, options) {
217
+ if (!reportId) {
218
+ throw Error('Undefined parameter');
219
+ }
220
+
221
+ // use spread operator to set default options
222
+ options = {...this.config.defaultOptions, ...options};
223
+
224
+ const [requestOptions] = this._createRequestOptions(reportId, '/contents');
225
+
226
+ return this.request({
227
+ method: 'GET',
228
+ ...requestOptions,
229
+ qs: {offset: options.offset, size: options.size},
230
+ timeout: options.timeoutMs
231
+ });
232
+ },
233
+
234
+ @waitForValue('@')
235
+ @oneFlight({keyFactory: (reportId, options) => createOneFlightKey(reportId, options)})
236
+ /**
237
+ * Retrieves a list of content containers relevant to a specified report
238
+ * @param {UUID|string} reportId - UUID or url of the report being requested
239
+ * @param {Object} options - optional parameters for this method
240
+ * @param {number} options.offset - start position from which to retrieve records
241
+ * @param {number} options.size - the number of records to retrieve
242
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
243
+ * @param {Set<Object>} options.types - Set of ContentContainerTypes to be retrieved
244
+ * @returns {Promise<ResponseEntity<ContentContainer>>} Http response containing the content containers
245
+ */
246
+ async getContentContainer(reportId, options) {
247
+ if (!reportId) {
248
+ throw Error('Undefined parameter');
249
+ }
250
+
251
+ // use spread operator to set default options
252
+ options = {...this.config.defaultOptions, ...options};
253
+
254
+ const [requestOptions, reportUUID] = this._createRequestOptions(reportId, '/contents/container');
255
+
256
+ const res = await this.request({
257
+ method: 'GET',
258
+ ...requestOptions,
259
+ qs: {offset: options.offset, size: options.size},
260
+ timeout: options.timeoutMs,
261
+ types: options.types
262
+ });
263
+
264
+ await this._writeToContentContainerCache(reportUUID, res.body);
265
+
266
+ return res;
267
+ },
268
+
269
+ @waitForValue('@')
270
+ @oneFlight({keyFactory: (reportId, containerId) => String(reportId + containerId)})
271
+ /**
272
+ * Retrieves information for a specific content container relevant to a specified report
273
+ * @param {UUID|string} reportId - UUID or url of the report being requested
274
+ * @param {UUID} containerId - Id of the contenyt container being requested
275
+ * @param {Object} options - optional parameters for this method
276
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
277
+ * @returns {Promise<ResponseEntity<ContentContainer>>} Http response containing the specified content container
278
+ */
279
+ async getContentContainerByContainerId(reportId, containerId, options) {
280
+ if (!reportId || !containerId) {
281
+ throw Error('Undefined parameter');
282
+ }
283
+
284
+ // use spread operator to set default options
285
+ options = {...this.config.defaultOptions, ...options};
286
+
287
+ const [requestOptions, reportUUID] = this._createRequestOptions(reportId, `/contents/container/${containerId}`);
288
+
289
+ // If this content container has already been cached then it can be retrieved from there instead of making a network call to ediscovery
290
+ if (this.contentContainerCache.has(reportUUID) && this.contentContainerCache.get(reportUUID).has(containerId)) {
291
+ return {body: this.contentContainerCache.get(reportUUID).get(containerId), statusCode: 200};
292
+ }
293
+
294
+ this.logger.warn(`Cache miss for container ${containerId} in contentContainerCache`);
295
+
296
+ const res = await this.request({
297
+ method: 'GET',
298
+ ...requestOptions,
299
+ qs: {offset: options.offset, size: options.size},
300
+ timeout: options.timeoutMs
301
+ });
302
+
303
+ await this._writeToContentContainerCache(reportUUID, [res.body]);
304
+
305
+ return res;
306
+ },
307
+
308
+ /**
309
+ * The results of a getContentContainer or getContentContainerByContainerId request are written to the contentContainerCache
310
+ * since information for a container is likely to be accessed very frequently when decrypting activities
311
+ * @param {UUID} reportId - Id of the report which contains the relevant content summary
312
+ * @param {Array<Object>} containers - List of the container objects to be written to the cache
313
+ * @returns {Promise} - Promise resolution indicating operation is complete
314
+ */
315
+ _writeToContentContainerCache(reportId, containers) {
316
+ if (!reportId || !containers || !containers.length) {
317
+ return;
318
+ }
319
+
320
+ if (!this.contentContainerCache.has(reportId)) {
321
+ this.contentContainerCache.set(reportId, new Map());
322
+ }
323
+
324
+ for (const container of containers) {
325
+ if (container && container.containerId) {
326
+ try {
327
+ this.contentContainerCache.get(reportId).set(container.containerId, container);
328
+ }
329
+ catch (error) {
330
+ this.logger.error(`Error adding ${container.containerId} to contentContainerCache: ${error}`);
331
+ }
332
+ }
333
+ else {
334
+ this.logger.error('Error adding undefined container to contentContainerCache');
335
+ }
336
+ }
337
+ },
338
+
339
+ /**
340
+ * Wipe the cache used by eDiscovery to store the space summaries and content containers.
341
+ * Good practice to clear it down when finished with a report to save RAM.
342
+ * @returns {undefined}
343
+ */
344
+ clearCache() {
345
+ this.contentContainerCache.clear();
346
+ },
347
+
348
+ /**
349
+ * Retrieves a uuid string from a report url
350
+ * @param {String} reportUrl - full destination address (including report id parameter) for the http request being sent
351
+ * e.g. 'http://ediscovery-intb.wbx2.com/ediscovery/api/v1/reports/3b10e625-2bd5-4efa-b866-58d6c93c505c'
352
+ * @returns {String} - uuid of the report
353
+ */
354
+ _getReportIdFromUrl(reportUrl) {
355
+ if (reportUrl) {
356
+ const uuids = reportUrl.match(/[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}/);
357
+
358
+ if (uuids && uuids.length > 0) {
359
+ return uuids[0];
360
+ }
361
+ }
362
+
363
+ return '';
364
+ },
365
+
366
+ _isUrl(string) {
367
+ // Regex found from `https://ihateregex.io/expr/url`
368
+ return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&\/\/=]*)/g.test(string);
369
+ },
370
+
371
+ /**
372
+ * Create the appropriate request options based on whether the reportId is a url or a uuid.
373
+ * @param {UUID|string} reportId - May be either a url for the report or a uuid.
374
+ * e.g. 'http://ediscovery-intb.wbx2.com/ediscovery/api/v1/reports/3b10e625-2bd5-4efa-b866-58d6c93c505c' or '3b10e625-2bd5-4efa-b866-58d6c93c505c'.
375
+ * @param {String} resource - The resource on the remote server to request
376
+ * @returns {[Options, uuid]} - The options to pass to `request` and the report uuid.
377
+ */
378
+ _createRequestOptions(reportId, resource) {
379
+ let requestOptions;
380
+ let reportUUID;
381
+ const isUrl = this._isUrl(reportId);
382
+
383
+ if (isUrl) {
384
+ reportUUID = this._getReportIdFromUrl(reportId);
385
+
386
+ if (!reportUUID) {
387
+ throw Error('Report url does not contain a report id');
388
+ }
389
+
390
+ // Ensure the url is formatted to
391
+ // https://ediscovery.intb1.ciscospark.com/ediscovery/api/v1/reports/16bf0d01-b1f7-483b-89a2-915144158fb9
392
+ // index.js for example passes the url in as
393
+ // https://ediscovery.intb1.ciscospark.com/ediscovery/api/v1/reports/16bf0d01-b1f7-483b-89a2-915144158fb9/contents
394
+ const reportUrl = reportId.substring(0, reportId.lastIndexOf(reportUUID) + reportUUID.length);
395
+
396
+ requestOptions = {
397
+ url: reportUrl + resource
398
+ };
399
+ }
400
+ else {
401
+ requestOptions = {
402
+ service: 'ediscovery',
403
+ resource: `reports/${reportId}/${resource}`
404
+ };
405
+ reportUUID = reportId;
406
+ }
407
+
408
+ return [requestOptions, reportUUID];
409
+ },
410
+
411
+ @waitForValue('@')
412
+ /**
413
+ * Retrieves a config object from the service which can be used by the client for optimal performance, e.g. content page size
414
+ * @param {Object} options - optional parameters for this method
415
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
416
+ * @returns {Promise<Config>} Http response containing the config object
417
+ */
418
+ async getClientConfig(options) {
419
+ // use spread operator to set default options
420
+ options = {...this.config.defaultOptions, ...options};
421
+
422
+ return this.request({
423
+ method: 'GET',
424
+ service: 'ediscovery',
425
+ resource: 'reports/clientconfig',
426
+ timeout: options.timeoutMs
427
+ });
428
+ },
429
+
430
+ @waitForValue('@')
431
+ /**
432
+ * Submits an audit event to the eDiscovery service for admin use. Only expected to be used for
433
+ * the getContentContainer API
434
+ * @param {UUID} reportId - Id of the report to send an audit log for
435
+ * @param {Object} options - optional parameters for this method
436
+ * @param {number} options.timeoutMs - connection timeout in milliseconds, defaults to 30s
437
+ * @returns {Promise<Config>} Http response containing the config object
438
+ */
439
+ async postAuditLog(reportId, options) {
440
+ if (!reportId) {
441
+ throw Error('No report ID specified');
442
+ }
443
+
444
+ // use spread operator to set default options
445
+ options = {...this.config.defaultOptions, ...options};
446
+
447
+ return this.request({
448
+ method: 'POST',
449
+ service: 'ediscovery',
450
+ resource: `reports/${reportId}/audit/summary-download`,
451
+ timeout: options.timeoutMs
452
+ });
453
+ }
454
+
455
+ });
456
+
457
+ export default EDiscovery;