@webex/internal-plugin-conversation 2.36.1 → 2.37.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/README.md +1 -3
- package/dist/activities.js +8 -69
- package/dist/activities.js.map +1 -1
- package/dist/activity-thread-ordering.js +19 -79
- package/dist/activity-thread-ordering.js.map +1 -1
- package/dist/config.js +1 -7
- package/dist/config.js.map +1 -1
- package/dist/constants.js +4 -5
- package/dist/constants.js.map +1 -1
- package/dist/conversation.js +764 -1196
- package/dist/conversation.js.map +1 -1
- package/dist/convo-error.js +0 -23
- package/dist/convo-error.js.map +1 -1
- package/dist/decryption-transforms.js +35 -98
- package/dist/decryption-transforms.js.map +1 -1
- package/dist/encryption-transforms.js +11 -48
- package/dist/encryption-transforms.js.map +1 -1
- package/dist/index.js +7 -50
- package/dist/index.js.map +1 -1
- package/dist/share-activity.js +39 -105
- package/dist/share-activity.js.map +1 -1
- package/dist/to-array.js +9 -11
- package/dist/to-array.js.map +1 -1
- package/package.json +15 -15
- package/src/activities.js +10 -7
- package/src/activity-thread-ordering.js +27 -30
- package/src/activity-threading.md +68 -49
- package/src/config.js +5 -5
- package/src/conversation.js +604 -587
- package/src/decryption-transforms.js +103 -62
- package/src/encryption-transforms.js +103 -83
- package/src/index.js +82 -66
- package/src/share-activity.js +63 -54
- package/src/to-array.js +2 -2
- package/test/integration/spec/create.js +184 -118
- package/test/integration/spec/encryption.js +250 -186
- package/test/integration/spec/get.js +761 -513
- package/test/integration/spec/mercury.js +37 -27
- package/test/integration/spec/share.js +292 -229
- package/test/integration/spec/verbs.js +628 -441
- package/test/unit/spec/conversation.js +224 -163
- package/test/unit/spec/decrypt-transforms.js +112 -131
- package/test/unit/spec/encryption-transforms.js +24 -18
- package/test/unit/spec/share-activity.js +37 -40
package/src/conversation.js
CHANGED
|
@@ -9,14 +9,28 @@ import hmacSHA256 from 'crypto-js/hmac-sha256';
|
|
|
9
9
|
import hex from 'crypto-js/enc-hex';
|
|
10
10
|
import {proxyEvents, tap} from '@webex/common';
|
|
11
11
|
import {Page, WebexPlugin} from '@webex/webex-core';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
cloneDeep,
|
|
14
|
+
cloneDeepWith,
|
|
15
|
+
defaults,
|
|
16
|
+
isArray,
|
|
17
|
+
isObject,
|
|
18
|
+
isString,
|
|
19
|
+
last,
|
|
20
|
+
map,
|
|
21
|
+
merge,
|
|
22
|
+
omit,
|
|
23
|
+
pick,
|
|
24
|
+
uniq,
|
|
25
|
+
} from 'lodash';
|
|
13
26
|
import {readExifData} from '@webex/helper-image';
|
|
14
27
|
import uuid from 'uuid';
|
|
15
28
|
|
|
16
29
|
import {InvalidUserCreation} from './convo-error';
|
|
17
30
|
import ShareActivity from './share-activity';
|
|
18
31
|
import {
|
|
19
|
-
minBatchSize,
|
|
32
|
+
minBatchSize,
|
|
33
|
+
defaultMinDisplayableActivities,
|
|
20
34
|
getLoopCounterFailsafe,
|
|
21
35
|
batchSizeIncrementCount,
|
|
22
36
|
getActivityObjectsFromMap,
|
|
@@ -24,7 +38,7 @@ import {
|
|
|
24
38
|
noMoreActivitiesManager,
|
|
25
39
|
getQuery,
|
|
26
40
|
rootActivityManager,
|
|
27
|
-
activityManager
|
|
41
|
+
activityManager,
|
|
28
42
|
} from './activity-thread-ordering';
|
|
29
43
|
import {
|
|
30
44
|
ACTIVITY_TYPES,
|
|
@@ -36,23 +50,25 @@ import {
|
|
|
36
50
|
createReplyActivity,
|
|
37
51
|
createEditActivity,
|
|
38
52
|
createReplyEditActivity,
|
|
39
|
-
OLDER,
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
OLDER,
|
|
54
|
+
MID,
|
|
55
|
+
INITIAL,
|
|
56
|
+
NEWER,
|
|
57
|
+
getPublishedDate,
|
|
58
|
+
sortActivitiesByPublishedDate,
|
|
59
|
+
sanitizeActivity,
|
|
42
60
|
} from './activities';
|
|
43
61
|
import {
|
|
44
62
|
DEFAULT_CLUSTER,
|
|
45
63
|
DEFAULT_CLUSTER_SERVICE,
|
|
46
64
|
ENCRYPTION_KEY_URL_MISMATCH,
|
|
47
65
|
KEY_ALREADY_ROTATED,
|
|
48
|
-
KEY_ROTATION_REQUIRED
|
|
66
|
+
KEY_ROTATION_REQUIRED,
|
|
49
67
|
} from './constants';
|
|
50
68
|
|
|
51
|
-
|
|
52
69
|
const CLUSTER_SERVICE = process.env.WEBEX_CONVERSATION_CLUSTER_SERVICE || DEFAULT_CLUSTER_SERVICE;
|
|
53
70
|
const DEFAULT_CLUSTER_IDENTIFIER =
|
|
54
|
-
process.env.WEBEX_CONVERSATION_DEFAULT_CLUSTER ||
|
|
55
|
-
`${DEFAULT_CLUSTER}:${CLUSTER_SERVICE}`;
|
|
71
|
+
process.env.WEBEX_CONVERSATION_DEFAULT_CLUSTER || `${DEFAULT_CLUSTER}:${CLUSTER_SERVICE}`;
|
|
56
72
|
|
|
57
73
|
const idToUrl = new Map();
|
|
58
74
|
|
|
@@ -62,7 +78,7 @@ const getConvoLimit = (options = {}) => {
|
|
|
62
78
|
if (options.conversationsLimit) {
|
|
63
79
|
limit = {
|
|
64
80
|
value: options.conversationsLimit,
|
|
65
|
-
name: 'conversationsLimit'
|
|
81
|
+
name: 'conversationsLimit',
|
|
66
82
|
};
|
|
67
83
|
}
|
|
68
84
|
|
|
@@ -79,8 +95,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
79
95
|
* @returns {String} url of the conversation
|
|
80
96
|
*/
|
|
81
97
|
getUrlFromClusterId({cluster = 'us', id} = {}) {
|
|
82
|
-
let clusterId =
|
|
83
|
-
cluster === 'us' ? DEFAULT_CLUSTER_IDENTIFIER : cluster;
|
|
98
|
+
let clusterId = cluster === 'us' ? DEFAULT_CLUSTER_IDENTIFIER : cluster;
|
|
84
99
|
|
|
85
100
|
// Determine if cluster has service name (non-US clusters from hydra do not)
|
|
86
101
|
if (clusterId.split(':').length < 4) {
|
|
@@ -88,8 +103,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
88
103
|
clusterId = `${cluster}:${CLUSTER_SERVICE}`;
|
|
89
104
|
}
|
|
90
105
|
|
|
91
|
-
const {url} = this.webex.internal.services
|
|
92
|
-
.getServiceFromClusterId({clusterId}) || {};
|
|
106
|
+
const {url} = this.webex.internal.services.getServiceFromClusterId({clusterId}) || {};
|
|
93
107
|
|
|
94
108
|
if (!url) {
|
|
95
109
|
throw Error(`Could not find service for cluster [${cluster}]`);
|
|
@@ -106,7 +120,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
106
120
|
*/
|
|
107
121
|
acknowledge(conversation, object, activity) {
|
|
108
122
|
const url = this.getConvoUrl(conversation);
|
|
109
|
-
const convoWithUrl =
|
|
123
|
+
const convoWithUrl = {...conversation, url};
|
|
110
124
|
|
|
111
125
|
if (!isObject(object)) {
|
|
112
126
|
return Promise.reject(new Error('`object` must be an object'));
|
|
@@ -118,10 +132,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
118
132
|
object: {
|
|
119
133
|
objectType: 'activity',
|
|
120
134
|
id: object.id,
|
|
121
|
-
url: object.url
|
|
122
|
-
}
|
|
123
|
-
})
|
|
124
|
-
.then((a) => this.submit(a));
|
|
135
|
+
url: object.url,
|
|
136
|
+
},
|
|
137
|
+
}).then((a) => this.submit(a));
|
|
125
138
|
},
|
|
126
139
|
|
|
127
140
|
/**
|
|
@@ -135,26 +148,24 @@ const Conversation = WebexPlugin.extend({
|
|
|
135
148
|
*/
|
|
136
149
|
add(conversation, participant, activity) {
|
|
137
150
|
const url = this.getConvoUrl(conversation);
|
|
138
|
-
const convoWithUrl =
|
|
151
|
+
const convoWithUrl = {...conversation, url};
|
|
139
152
|
|
|
140
|
-
return this.webex.internal.user.asUUID(participant, {create: true})
|
|
141
|
-
|
|
153
|
+
return this.webex.internal.user.asUUID(participant, {create: true}).then((id) =>
|
|
154
|
+
this.prepare(activity, {
|
|
142
155
|
verb: 'add',
|
|
143
156
|
target: this.prepareConversation(convoWithUrl),
|
|
144
157
|
object: {
|
|
145
158
|
id,
|
|
146
|
-
objectType: 'person'
|
|
159
|
+
objectType: 'person',
|
|
147
160
|
},
|
|
148
161
|
kmsMessage: {
|
|
149
162
|
method: 'create',
|
|
150
163
|
uri: '/authorizations',
|
|
151
164
|
resourceUri: '<KRO>',
|
|
152
|
-
userIds: [
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
})
|
|
157
|
-
.then((a) => this.submit(a)));
|
|
165
|
+
userIds: [id],
|
|
166
|
+
},
|
|
167
|
+
}).then((a) => this.submit(a))
|
|
168
|
+
);
|
|
158
169
|
},
|
|
159
170
|
|
|
160
171
|
/**
|
|
@@ -181,11 +192,16 @@ const Conversation = WebexPlugin.extend({
|
|
|
181
192
|
return Promise.reject(new Error('`params.participants` is required'));
|
|
182
193
|
}
|
|
183
194
|
|
|
184
|
-
return Promise.all(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
return Promise.all(
|
|
196
|
+
params.participants.map((participant) =>
|
|
197
|
+
this.webex.internal.user
|
|
198
|
+
.asUUID(participant, {create: true})
|
|
199
|
+
// eslint-disable-next-line arrow-body-style
|
|
200
|
+
.catch((err) => {
|
|
201
|
+
return options.allowPartialCreation ? undefined : Promise.reject(err);
|
|
202
|
+
})
|
|
203
|
+
)
|
|
204
|
+
)
|
|
189
205
|
.then((participants) => {
|
|
190
206
|
participants.unshift(this.webex.internal.device.userId);
|
|
191
207
|
participants = uniq(participants);
|
|
@@ -216,12 +232,11 @@ const Conversation = WebexPlugin.extend({
|
|
|
216
232
|
return c;
|
|
217
233
|
}
|
|
218
234
|
|
|
219
|
-
return this.webex.internal.conversation.share(c, params.files)
|
|
220
|
-
.
|
|
221
|
-
c.activities.items.push(a);
|
|
235
|
+
return this.webex.internal.conversation.share(c, params.files).then((a) => {
|
|
236
|
+
c.activities.items.push(a);
|
|
222
237
|
|
|
223
|
-
|
|
224
|
-
|
|
238
|
+
return c;
|
|
239
|
+
});
|
|
225
240
|
});
|
|
226
241
|
},
|
|
227
242
|
|
|
@@ -236,7 +251,8 @@ const Conversation = WebexPlugin.extend({
|
|
|
236
251
|
// not using webex.internal.encryption.getKey() because the JWK it returns does not have a 'k'
|
|
237
252
|
// property. we need jwk.k to correctly generate the HMAC
|
|
238
253
|
|
|
239
|
-
return this.webex.internal.encryption.unboundedStorage
|
|
254
|
+
return this.webex.internal.encryption.unboundedStorage
|
|
255
|
+
.get(parent.encryptionKeyUrl)
|
|
240
256
|
.then((keyString) => {
|
|
241
257
|
const key = JSON.parse(keyString);
|
|
242
258
|
// when we stringify this object, keys must be in this order to generate same HMAC as
|
|
@@ -278,7 +294,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
278
294
|
*/
|
|
279
295
|
sendReaction(conversation, reactionPayload) {
|
|
280
296
|
const url = this.getConvoUrl(conversation);
|
|
281
|
-
const convoWithUrl =
|
|
297
|
+
const convoWithUrl = {...conversation, url};
|
|
282
298
|
|
|
283
299
|
if (!isObject(reactionPayload)) {
|
|
284
300
|
return Promise.reject(new Error('`object` must be an object'));
|
|
@@ -286,9 +302,8 @@ const Conversation = WebexPlugin.extend({
|
|
|
286
302
|
|
|
287
303
|
return this.prepare(reactionPayload, {
|
|
288
304
|
target: this.prepareConversation(convoWithUrl),
|
|
289
|
-
object: pick(reactionPayload, 'id', 'url', 'objectType')
|
|
290
|
-
})
|
|
291
|
-
.then((act) => this.submit(act));
|
|
305
|
+
object: pick(reactionPayload, 'id', 'url', 'objectType'),
|
|
306
|
+
}).then((act) => this.submit(act));
|
|
292
307
|
},
|
|
293
308
|
|
|
294
309
|
/**
|
|
@@ -302,14 +317,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
302
317
|
actor: {objectType: 'person', id: this.webex.internal.device.userId},
|
|
303
318
|
object: {
|
|
304
319
|
id: reactionId,
|
|
305
|
-
objectType: 'activity'
|
|
320
|
+
objectType: 'activity',
|
|
306
321
|
},
|
|
307
322
|
objectType: 'activity',
|
|
308
323
|
target: {
|
|
309
324
|
id: conversation.id,
|
|
310
|
-
objectType: 'conversation'
|
|
325
|
+
objectType: 'conversation',
|
|
311
326
|
},
|
|
312
|
-
verb: 'delete'
|
|
327
|
+
verb: 'delete',
|
|
313
328
|
};
|
|
314
329
|
|
|
315
330
|
return this.sendReaction(conversation, deleteReactionPayload);
|
|
@@ -328,26 +343,25 @@ const Conversation = WebexPlugin.extend({
|
|
|
328
343
|
actor: {objectType: 'person', id: this.webex.internal.device.userId},
|
|
329
344
|
target: {
|
|
330
345
|
id: conversation.id,
|
|
331
|
-
objectType: 'conversation'
|
|
346
|
+
objectType: 'conversation',
|
|
332
347
|
},
|
|
333
348
|
verb: 'add',
|
|
334
349
|
objectType: 'activity',
|
|
335
350
|
parent: {
|
|
336
351
|
type: 'reaction',
|
|
337
|
-
id: activity.id
|
|
352
|
+
id: activity.id,
|
|
338
353
|
},
|
|
339
354
|
object: {
|
|
340
355
|
objectType: 'reaction2',
|
|
341
356
|
displayName,
|
|
342
|
-
hmac
|
|
343
|
-
}
|
|
357
|
+
hmac,
|
|
358
|
+
},
|
|
344
359
|
};
|
|
345
360
|
|
|
346
361
|
return this.sendReaction(conversation, addReactionPayload);
|
|
347
362
|
});
|
|
348
363
|
},
|
|
349
364
|
|
|
350
|
-
|
|
351
365
|
/**
|
|
352
366
|
* delete content
|
|
353
367
|
* @param {Object} conversation
|
|
@@ -357,7 +371,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
357
371
|
*/
|
|
358
372
|
delete(conversation, object, activity) {
|
|
359
373
|
const url = this.getConvoUrl(conversation);
|
|
360
|
-
const convoWithUrl =
|
|
374
|
+
const convoWithUrl = {...conversation, url};
|
|
361
375
|
|
|
362
376
|
if (!isObject(object)) {
|
|
363
377
|
return Promise.reject(new Error('`object` must be an object'));
|
|
@@ -375,12 +389,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
375
389
|
request.target.kmsResourceObjectUrl = object.object.kmsResourceObjectUrl;
|
|
376
390
|
request.kmsMessage = {
|
|
377
391
|
method: 'delete',
|
|
378
|
-
uri: `<KRO>/authorizations?${querystring.stringify({
|
|
392
|
+
uri: `<KRO>/authorizations?${querystring.stringify({
|
|
393
|
+
authId: convoWithUrl.kmsResourceObjectUrl,
|
|
394
|
+
})}`,
|
|
379
395
|
};
|
|
380
396
|
}
|
|
381
397
|
|
|
382
|
-
return this.prepare(activity, request)
|
|
383
|
-
.then((a) => this.submit(a));
|
|
398
|
+
return this.prepare(activity, request).then((a) => this.submit(a));
|
|
384
399
|
},
|
|
385
400
|
|
|
386
401
|
/**
|
|
@@ -400,11 +415,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
400
415
|
|
|
401
416
|
if (isEncrypted) {
|
|
402
417
|
promise = this.webex.internal.encryption.download(item.scr, item.options);
|
|
403
|
-
}
|
|
404
|
-
else if (item.scr && item.scr.loc) {
|
|
418
|
+
} else if (item.scr && item.scr.loc) {
|
|
405
419
|
promise = this._downloadUnencryptedFile(item.scr.loc, options);
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
420
|
+
} else {
|
|
408
421
|
promise = this._downloadUnencryptedFile(item.url, options);
|
|
409
422
|
}
|
|
410
423
|
|
|
@@ -446,11 +459,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
446
459
|
_downloadUnencryptedFile(uri, options = {}) {
|
|
447
460
|
Object.assign(options, {
|
|
448
461
|
uri,
|
|
449
|
-
responseType: 'buffer'
|
|
462
|
+
responseType: 'buffer',
|
|
450
463
|
});
|
|
451
464
|
|
|
452
|
-
const promise = this.request(options)
|
|
453
|
-
.then((res) => res.body);
|
|
465
|
+
const promise = this.request(options).then((res) => res.body);
|
|
454
466
|
|
|
455
467
|
proxyEvents(options.download, promise);
|
|
456
468
|
|
|
@@ -469,7 +481,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
469
481
|
const activity = {
|
|
470
482
|
actor,
|
|
471
483
|
objectType: 'activity',
|
|
472
|
-
verb
|
|
484
|
+
verb,
|
|
473
485
|
};
|
|
474
486
|
|
|
475
487
|
if (!actor) {
|
|
@@ -479,7 +491,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
479
491
|
if (isString(actor)) {
|
|
480
492
|
activity.actor = {
|
|
481
493
|
objectType: 'person',
|
|
482
|
-
id: actor
|
|
494
|
+
id: actor,
|
|
483
495
|
};
|
|
484
496
|
}
|
|
485
497
|
|
|
@@ -495,20 +507,20 @@ const Conversation = WebexPlugin.extend({
|
|
|
495
507
|
},
|
|
496
508
|
|
|
497
509
|
/**
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
510
|
+
* Gets an array of activities with an array of activity URLS
|
|
511
|
+
* @param {Array} activityUrls
|
|
512
|
+
* @param {Object} options
|
|
513
|
+
* @param {String} options.cluster cluster where the activities are located
|
|
514
|
+
* @param {String} options.url base convo url where the activities are located
|
|
515
|
+
* @returns {Promise<Object>} Resolves with the activities
|
|
516
|
+
*/
|
|
505
517
|
bulkActivitiesFetch(activityUrls, options = {}) {
|
|
506
|
-
let cluster
|
|
518
|
+
let cluster;
|
|
519
|
+
let url;
|
|
507
520
|
|
|
508
521
|
if (typeof options === 'string') {
|
|
509
522
|
cluster = options;
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
523
|
+
} else {
|
|
512
524
|
({cluster, url} = options);
|
|
513
525
|
}
|
|
514
526
|
|
|
@@ -516,45 +528,42 @@ const Conversation = WebexPlugin.extend({
|
|
|
516
528
|
const params = {
|
|
517
529
|
method: 'POST',
|
|
518
530
|
body: {
|
|
519
|
-
activityUrls
|
|
520
|
-
}
|
|
531
|
+
activityUrls,
|
|
532
|
+
},
|
|
521
533
|
};
|
|
522
534
|
|
|
523
535
|
if (url) {
|
|
524
536
|
const uri = `${url}/${resource}`;
|
|
525
537
|
|
|
526
538
|
Object.assign(params, {
|
|
527
|
-
uri
|
|
539
|
+
uri,
|
|
528
540
|
});
|
|
529
|
-
}
|
|
530
|
-
else if (cluster) {
|
|
541
|
+
} else if (cluster) {
|
|
531
542
|
const uri = `${this.getUrlFromClusterId({cluster})}/${resource}`;
|
|
532
543
|
|
|
533
544
|
Object.assign(params, {
|
|
534
|
-
uri
|
|
545
|
+
uri,
|
|
535
546
|
});
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
547
|
+
} else {
|
|
538
548
|
Object.assign(params, {
|
|
539
549
|
api: 'conversation',
|
|
540
|
-
resource
|
|
550
|
+
resource,
|
|
541
551
|
});
|
|
542
552
|
}
|
|
543
553
|
|
|
544
|
-
return this.webex.request(params)
|
|
545
|
-
|
|
546
|
-
const activitiesArr = [];
|
|
554
|
+
return this.webex.request(params).then((res) => {
|
|
555
|
+
const activitiesArr = [];
|
|
547
556
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
557
|
+
if (res.body.multistatus) {
|
|
558
|
+
res.body.multistatus.forEach((statusData) => {
|
|
559
|
+
if (statusData.status === '200' && statusData.data && statusData.data.activity) {
|
|
560
|
+
activitiesArr.push(statusData.data.activity);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
555
564
|
|
|
556
|
-
|
|
557
|
-
|
|
565
|
+
return activitiesArr;
|
|
566
|
+
});
|
|
558
567
|
},
|
|
559
568
|
|
|
560
569
|
/**
|
|
@@ -572,27 +581,27 @@ const Conversation = WebexPlugin.extend({
|
|
|
572
581
|
|
|
573
582
|
try {
|
|
574
583
|
uri = !user ? this.getConvoUrl(conversation) : '';
|
|
575
|
-
}
|
|
576
|
-
catch (err) {
|
|
584
|
+
} catch (err) {
|
|
577
585
|
return Promise.reject(Error(err));
|
|
578
586
|
}
|
|
579
587
|
|
|
580
588
|
const params = {
|
|
581
|
-
qs:
|
|
589
|
+
qs: {
|
|
582
590
|
uuidEntryFormat: true,
|
|
583
591
|
personRefresh: true,
|
|
584
592
|
activitiesLimit: 0,
|
|
585
593
|
includeConvWithDeletedUserUUID: false,
|
|
586
|
-
includeParticipants: false
|
|
587
|
-
|
|
588
|
-
|
|
594
|
+
includeParticipants: false,
|
|
595
|
+
...omit(options, 'id', 'user', 'url'),
|
|
596
|
+
},
|
|
597
|
+
disableTransform: options.disableTransform,
|
|
589
598
|
};
|
|
590
599
|
|
|
591
600
|
// Default behavior is to set includeParticipants=false,
|
|
592
601
|
// which makes the payload lighter by removing participant info.
|
|
593
602
|
// If the caller explicitly sets the participantAckFilter or
|
|
594
603
|
// participantsLimit, we don't want that default setting.
|
|
595
|
-
if (
|
|
604
|
+
if ('participantAckFilter' in options || 'participantsLimit' in options) {
|
|
596
605
|
delete params.qs.includeParticipants;
|
|
597
606
|
}
|
|
598
607
|
|
|
@@ -601,21 +610,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
601
610
|
if (userId) {
|
|
602
611
|
Object.assign(params, {
|
|
603
612
|
service: 'conversation',
|
|
604
|
-
resource: `conversations/user/${userId}
|
|
613
|
+
resource: `conversations/user/${userId}`,
|
|
605
614
|
});
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
615
|
+
} else {
|
|
608
616
|
params.uri = uri;
|
|
609
617
|
}
|
|
610
618
|
|
|
611
619
|
return this.request(params);
|
|
612
620
|
})
|
|
613
|
-
.then(
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
621
|
+
.then(
|
|
622
|
+
tap(({body}) => {
|
|
623
|
+
const {id, url} = body;
|
|
624
|
+
|
|
625
|
+
this._recordUUIDs(body);
|
|
626
|
+
idToUrl.set(id, url);
|
|
627
|
+
})
|
|
628
|
+
)
|
|
619
629
|
.then((res) => res.body);
|
|
620
630
|
},
|
|
621
631
|
|
|
@@ -631,10 +641,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
631
641
|
* @returns {Promise<Activity>}
|
|
632
642
|
*/
|
|
633
643
|
leave(conversation, participant, activity) {
|
|
634
|
-
const convoWithUrl =
|
|
635
|
-
Object.assign(
|
|
636
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
637
|
-
);
|
|
644
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
638
645
|
|
|
639
646
|
return Promise.resolve()
|
|
640
647
|
.then(() => {
|
|
@@ -642,19 +649,20 @@ const Conversation = WebexPlugin.extend({
|
|
|
642
649
|
participant = this.webex.internal.device.userId;
|
|
643
650
|
}
|
|
644
651
|
|
|
645
|
-
return this.webex.internal.user.asUUID(participant)
|
|
646
|
-
|
|
652
|
+
return this.webex.internal.user.asUUID(participant).then((id) =>
|
|
653
|
+
this.prepare(activity, {
|
|
647
654
|
verb: 'leave',
|
|
648
655
|
target: this.prepareConversation(convoWithUrl),
|
|
649
656
|
object: {
|
|
650
657
|
id,
|
|
651
|
-
objectType: 'person'
|
|
658
|
+
objectType: 'person',
|
|
652
659
|
},
|
|
653
660
|
kmsMessage: {
|
|
654
661
|
method: 'delete',
|
|
655
|
-
uri: `<KRO>/authorizations?${querystring.stringify({authId: id})}
|
|
656
|
-
}
|
|
657
|
-
})
|
|
662
|
+
uri: `<KRO>/authorizations?${querystring.stringify({authId: id})}`,
|
|
663
|
+
},
|
|
664
|
+
})
|
|
665
|
+
);
|
|
658
666
|
})
|
|
659
667
|
.then((a) => this.submit(a));
|
|
660
668
|
},
|
|
@@ -677,15 +685,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
677
685
|
resource: options.summary ? 'conversationsSummary' : 'conversations',
|
|
678
686
|
qs: omit(options, ['deferDecrypt', 'summary']),
|
|
679
687
|
deferDecrypt: options.deferDecrypt,
|
|
680
|
-
limit: getConvoLimit(options)
|
|
681
|
-
})
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
688
|
+
limit: getConvoLimit(options),
|
|
689
|
+
}).then((results) => {
|
|
690
|
+
for (const convo of results) {
|
|
691
|
+
idToUrl.set(convo.id, convo.url);
|
|
692
|
+
}
|
|
686
693
|
|
|
687
|
-
|
|
688
|
-
|
|
694
|
+
return results;
|
|
695
|
+
});
|
|
689
696
|
},
|
|
690
697
|
|
|
691
698
|
/**
|
|
@@ -709,42 +716,40 @@ const Conversation = WebexPlugin.extend({
|
|
|
709
716
|
|
|
710
717
|
// Go get the next page of results
|
|
711
718
|
return this.request({
|
|
712
|
-
url: options.page.links.next
|
|
719
|
+
url: options.page.links.next,
|
|
713
720
|
}).then((res) => ({page: new Page(res, this.webex)}));
|
|
714
721
|
}
|
|
715
722
|
|
|
716
723
|
// No page - so this is the first request to kick off the pagination process
|
|
717
|
-
const queryOptions =
|
|
724
|
+
const queryOptions = {
|
|
718
725
|
personRefresh: true,
|
|
719
726
|
uuidEntryFormat: true,
|
|
720
727
|
activitiesLimit: 0,
|
|
721
728
|
participantsLimit: 0,
|
|
722
|
-
paginate: true
|
|
723
|
-
|
|
729
|
+
paginate: true,
|
|
730
|
+
...omit(options, ['deferDecrypt', 'url']),
|
|
731
|
+
};
|
|
724
732
|
|
|
725
733
|
const reqOptions = {
|
|
726
734
|
qs: queryOptions,
|
|
727
735
|
deferDecrypt: options.deferDecrypt,
|
|
728
|
-
limit: getConvoLimit(options)
|
|
736
|
+
limit: getConvoLimit(options),
|
|
729
737
|
};
|
|
730
738
|
|
|
731
739
|
// if options.url is present we likely received one or more additional urls due to federation. In this case
|
|
732
740
|
// we need to initialize pagination against that url instead of the default home cluster
|
|
733
741
|
if (options.url) {
|
|
734
742
|
reqOptions.uri = `${options.url}/conversations`;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
743
|
+
} else {
|
|
737
744
|
reqOptions.service = 'conversation';
|
|
738
745
|
reqOptions.resource = 'conversations';
|
|
739
746
|
}
|
|
740
747
|
|
|
741
|
-
|
|
742
748
|
return this.request(reqOptions).then((res) => {
|
|
743
749
|
const response = {
|
|
744
|
-
page: new Page(res, this.webex)
|
|
750
|
+
page: new Page(res, this.webex),
|
|
745
751
|
};
|
|
746
752
|
|
|
747
|
-
|
|
748
753
|
if (res.body && res.body.additionalUrls) {
|
|
749
754
|
response.additionalUrls = res.body.additionalUrls;
|
|
750
755
|
}
|
|
@@ -764,15 +769,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
764
769
|
service: 'conversation',
|
|
765
770
|
resource: 'conversations/left',
|
|
766
771
|
qs: options,
|
|
767
|
-
limit: getConvoLimit(options)
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
772
|
+
limit: getConvoLimit(options),
|
|
773
|
+
}).then((results) => {
|
|
774
|
+
for (const convo of results) {
|
|
775
|
+
idToUrl.set(convo.id, convo.url);
|
|
776
|
+
}
|
|
773
777
|
|
|
774
|
-
|
|
775
|
-
|
|
778
|
+
return results;
|
|
779
|
+
});
|
|
776
780
|
},
|
|
777
781
|
|
|
778
782
|
/**
|
|
@@ -807,7 +811,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
807
811
|
const params = {
|
|
808
812
|
method: 'GET',
|
|
809
813
|
url: `${conversationUrl}/parents`,
|
|
810
|
-
qs: query
|
|
814
|
+
qs: query,
|
|
811
815
|
};
|
|
812
816
|
|
|
813
817
|
const response = await this.request(params);
|
|
@@ -827,7 +831,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
827
831
|
const {conversationUrl, activityParentId, query} = options;
|
|
828
832
|
const {activityType} = query;
|
|
829
833
|
|
|
830
|
-
const initialResponse = await this.listChildActivitiesByParentId(
|
|
834
|
+
const initialResponse = await this.listChildActivitiesByParentId(
|
|
835
|
+
conversationUrl,
|
|
836
|
+
activityParentId,
|
|
837
|
+
activityType,
|
|
838
|
+
query
|
|
839
|
+
);
|
|
831
840
|
|
|
832
841
|
let page = new Page(initialResponse, this.webex);
|
|
833
842
|
|
|
@@ -861,12 +870,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
861
870
|
async listChildActivitiesByParentId(conversationUrl, activityParentId, activityType, query = {}) {
|
|
862
871
|
const finalQuery = {
|
|
863
872
|
...query,
|
|
864
|
-
activityType
|
|
873
|
+
activityType,
|
|
865
874
|
};
|
|
866
875
|
const params = {
|
|
867
876
|
method: 'GET',
|
|
868
877
|
url: `${conversationUrl}/parents/${activityParentId}`,
|
|
869
|
-
qs: finalQuery
|
|
878
|
+
qs: finalQuery,
|
|
870
879
|
};
|
|
871
880
|
|
|
872
881
|
return this.request(params);
|
|
@@ -883,10 +892,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
883
892
|
const {body} = await this.request({
|
|
884
893
|
method: 'GET',
|
|
885
894
|
url: `${conversationUrl}/activities/${activityParentId}`,
|
|
886
|
-
qs: query
|
|
895
|
+
qs: query,
|
|
887
896
|
});
|
|
888
897
|
|
|
889
|
-
const reactionObjects = body.children
|
|
898
|
+
const reactionObjects = body.children
|
|
899
|
+
? body.children.filter(
|
|
900
|
+
(child) => child.type === 'reactionSelfSummary' || child.type === 'reactionSummary'
|
|
901
|
+
)
|
|
902
|
+
: [];
|
|
890
903
|
|
|
891
904
|
return reactionObjects;
|
|
892
905
|
},
|
|
@@ -900,7 +913,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
900
913
|
return this._list({
|
|
901
914
|
service: 'conversation',
|
|
902
915
|
resource: 'mentions',
|
|
903
|
-
qs: omit(options, 'mentions')
|
|
916
|
+
qs: omit(options, 'mentions'),
|
|
904
917
|
});
|
|
905
918
|
},
|
|
906
919
|
|
|
@@ -911,9 +924,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
911
924
|
* @returns {Promise} Resolves with the created activity
|
|
912
925
|
*/
|
|
913
926
|
muteMentions(conversation, activity) {
|
|
914
|
-
return this.tag(
|
|
915
|
-
|
|
916
|
-
|
|
927
|
+
return this.tag(
|
|
928
|
+
conversation,
|
|
929
|
+
{
|
|
930
|
+
tags: ['MENTION_NOTIFICATIONS_OFF'],
|
|
931
|
+
},
|
|
932
|
+
activity
|
|
933
|
+
);
|
|
917
934
|
},
|
|
918
935
|
|
|
919
936
|
/**
|
|
@@ -923,9 +940,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
923
940
|
* @returns {Promise} Resolves with the created activity
|
|
924
941
|
*/
|
|
925
942
|
muteMessages(conversation, activity) {
|
|
926
|
-
return this.tag(
|
|
927
|
-
|
|
928
|
-
|
|
943
|
+
return this.tag(
|
|
944
|
+
conversation,
|
|
945
|
+
{
|
|
946
|
+
tags: ['MESSAGE_NOTIFICATIONS_OFF'],
|
|
947
|
+
},
|
|
948
|
+
activity
|
|
949
|
+
);
|
|
929
950
|
},
|
|
930
951
|
|
|
931
952
|
/**
|
|
@@ -935,9 +956,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
935
956
|
* @returns {Promise} Resolves with the created activity
|
|
936
957
|
*/
|
|
937
958
|
ignore(conversation, activity) {
|
|
938
|
-
return this.tag(
|
|
939
|
-
|
|
940
|
-
|
|
959
|
+
return this.tag(
|
|
960
|
+
conversation,
|
|
961
|
+
{
|
|
962
|
+
tags: ['IGNORED'],
|
|
963
|
+
},
|
|
964
|
+
activity
|
|
965
|
+
);
|
|
941
966
|
},
|
|
942
967
|
|
|
943
968
|
/**
|
|
@@ -948,22 +973,18 @@ const Conversation = WebexPlugin.extend({
|
|
|
948
973
|
* @returns {Promise}
|
|
949
974
|
*/
|
|
950
975
|
cardAction(conversation, inputs, parentActivity, activity = {}) {
|
|
951
|
-
const convoWithUrl =
|
|
952
|
-
Object.assign(
|
|
953
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
954
|
-
);
|
|
976
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
955
977
|
|
|
956
978
|
activity.parent = {
|
|
957
979
|
id: parentActivity.id,
|
|
958
|
-
type: 'cardAction'
|
|
980
|
+
type: 'cardAction',
|
|
959
981
|
};
|
|
960
982
|
|
|
961
983
|
return this.prepare(activity, {
|
|
962
984
|
verb: 'cardAction',
|
|
963
985
|
target: this.prepareConversation(convoWithUrl),
|
|
964
|
-
object:
|
|
965
|
-
})
|
|
966
|
-
.then((a) => this.submit(a));
|
|
986
|
+
object: {objectType: 'submit', ...inputs},
|
|
987
|
+
}).then((a) => this.submit(a));
|
|
967
988
|
},
|
|
968
989
|
|
|
969
990
|
/**
|
|
@@ -977,105 +998,122 @@ const Conversation = WebexPlugin.extend({
|
|
|
977
998
|
* @returns {Promise<Activity>}
|
|
978
999
|
*/
|
|
979
1000
|
post(conversation, message, activity) {
|
|
980
|
-
const convoWithUrl =
|
|
981
|
-
Object.assign(
|
|
982
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
983
|
-
);
|
|
1001
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
984
1002
|
|
|
985
1003
|
if (isString(message)) {
|
|
986
1004
|
message = {
|
|
987
|
-
displayName: message
|
|
1005
|
+
displayName: message,
|
|
988
1006
|
};
|
|
989
1007
|
}
|
|
990
1008
|
|
|
991
1009
|
return this.prepare(activity, {
|
|
992
1010
|
verb: 'post',
|
|
993
1011
|
target: this.prepareConversation(convoWithUrl),
|
|
994
|
-
object:
|
|
995
|
-
})
|
|
996
|
-
.then((a) => this.submit(a));
|
|
1012
|
+
object: {objectType: 'comment', ...message},
|
|
1013
|
+
}).then((a) => this.submit(a));
|
|
997
1014
|
},
|
|
998
1015
|
|
|
999
1016
|
prepareConversation(conversation) {
|
|
1000
|
-
return defaults(
|
|
1001
|
-
|
|
1002
|
-
|
|
1017
|
+
return defaults(
|
|
1018
|
+
pick(
|
|
1019
|
+
conversation,
|
|
1020
|
+
'id',
|
|
1021
|
+
'url',
|
|
1022
|
+
'objectType',
|
|
1023
|
+
'defaultActivityEncryptionKeyUrl',
|
|
1024
|
+
'kmsResourceObjectUrl'
|
|
1025
|
+
),
|
|
1026
|
+
{
|
|
1027
|
+
objectType: 'conversation',
|
|
1028
|
+
}
|
|
1029
|
+
);
|
|
1003
1030
|
},
|
|
1004
1031
|
|
|
1005
1032
|
prepare(activity, params) {
|
|
1006
1033
|
params = params || {};
|
|
1007
1034
|
activity = activity || {};
|
|
1008
1035
|
|
|
1009
|
-
return Promise.resolve(activity.prepare ? activity.prepare(params) : activity)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
// Workaround because parent is a reserved props in Ampersand
|
|
1020
|
-
if ((activity.parentActivityId && activity.activityType) || (activity.parent && activity.parent.id && activity.parent.type)) {
|
|
1021
|
-
act.parent = {
|
|
1022
|
-
id: activity.parentActivityId || activity.parent.id,
|
|
1023
|
-
type: activity.activityType || activity.parent.type
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1036
|
+
return Promise.resolve(activity.prepare ? activity.prepare(params) : activity).then((act) => {
|
|
1037
|
+
defaults(act, {
|
|
1038
|
+
verb: params.verb,
|
|
1039
|
+
kmsMessage: params.kmsMessage,
|
|
1040
|
+
objectType: 'activity',
|
|
1041
|
+
clientTempId: uuid.v4(),
|
|
1042
|
+
actor: this.webex.internal.device.userId,
|
|
1043
|
+
});
|
|
1026
1044
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1045
|
+
// Workaround because parent is a reserved props in Ampersand
|
|
1046
|
+
if (
|
|
1047
|
+
(activity.parentActivityId && activity.activityType) ||
|
|
1048
|
+
(activity.parent && activity.parent.id && activity.parent.type)
|
|
1049
|
+
) {
|
|
1050
|
+
act.parent = {
|
|
1051
|
+
id: activity.parentActivityId || activity.parent.id,
|
|
1052
|
+
type: activity.activityType || activity.parent.type,
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1033
1055
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1056
|
+
if (isString(act.actor)) {
|
|
1057
|
+
act.actor = {
|
|
1058
|
+
objectType: 'person',
|
|
1059
|
+
id: act.actor,
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1040
1062
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1063
|
+
['actor', 'object'].forEach((key) => {
|
|
1064
|
+
if (params[key]) {
|
|
1065
|
+
act[key] = act[key] || {};
|
|
1066
|
+
defaults(act[key], params[key]);
|
|
1045
1067
|
}
|
|
1068
|
+
});
|
|
1046
1069
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
throw new Error(`\`act.${key}.objectType\` must be defined`);
|
|
1058
|
-
}
|
|
1070
|
+
if (params.target) {
|
|
1071
|
+
merge(act, {
|
|
1072
|
+
target: pick(
|
|
1073
|
+
params.target,
|
|
1074
|
+
'id',
|
|
1075
|
+
'url',
|
|
1076
|
+
'objectType',
|
|
1077
|
+
'kmsResourceObjectUrl',
|
|
1078
|
+
'defaultActivityEncryptionKeyUrl'
|
|
1079
|
+
),
|
|
1059
1080
|
});
|
|
1081
|
+
}
|
|
1060
1082
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1083
|
+
['object', 'target'].forEach((key) => {
|
|
1084
|
+
if (act[key] && act[key].url && !act[key].id) {
|
|
1085
|
+
act[key].id = act[key].url.split('/').pop();
|
|
1063
1086
|
}
|
|
1087
|
+
});
|
|
1064
1088
|
|
|
1065
|
-
|
|
1089
|
+
['actor', 'object', 'target'].forEach((key) => {
|
|
1090
|
+
if (act[key] && !act[key].objectType) {
|
|
1091
|
+
// Reminder: throwing here because it's the only way to get out of
|
|
1092
|
+
// this loop in event of an error.
|
|
1093
|
+
throw new Error(`\`act.${key}.objectType\` must be defined`);
|
|
1094
|
+
}
|
|
1066
1095
|
});
|
|
1096
|
+
|
|
1097
|
+
if (act.object && act.object.content && !act.object.displayName) {
|
|
1098
|
+
return Promise.reject(
|
|
1099
|
+
new Error('Cannot submit activity object with `content` but no `displayName`')
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return act;
|
|
1104
|
+
});
|
|
1067
1105
|
},
|
|
1068
1106
|
|
|
1069
1107
|
/**
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1108
|
+
* Get a subset of threads for a user.
|
|
1109
|
+
* @param {Object} options
|
|
1110
|
+
* @returns {Promise<Array<Activity>>}
|
|
1111
|
+
*/
|
|
1074
1112
|
async listThreads(options) {
|
|
1075
1113
|
return this._list({
|
|
1076
1114
|
service: 'conversation',
|
|
1077
1115
|
resource: 'threads',
|
|
1078
|
-
qs: omit(options, 'showAllTypes')
|
|
1116
|
+
qs: omit(options, 'showAllTypes'),
|
|
1079
1117
|
});
|
|
1080
1118
|
},
|
|
1081
1119
|
|
|
@@ -1085,8 +1123,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1085
1123
|
* @returns {Promise}
|
|
1086
1124
|
*/
|
|
1087
1125
|
processActivityEvent(event) {
|
|
1088
|
-
return this.webex.transform('inbound', event)
|
|
1089
|
-
.then(() => event);
|
|
1126
|
+
return this.webex.transform('inbound', event).then(() => event);
|
|
1090
1127
|
},
|
|
1091
1128
|
|
|
1092
1129
|
/**
|
|
@@ -1095,8 +1132,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1095
1132
|
* @returns {Promise}
|
|
1096
1133
|
*/
|
|
1097
1134
|
processInmeetingchatEvent(event) {
|
|
1098
|
-
return this.webex.transform('inbound', event)
|
|
1099
|
-
.then(() => event);
|
|
1135
|
+
return this.webex.transform('inbound', event).then(() => event);
|
|
1100
1136
|
},
|
|
1101
1137
|
|
|
1102
1138
|
/**
|
|
@@ -1106,14 +1142,18 @@ const Conversation = WebexPlugin.extend({
|
|
|
1106
1142
|
* @returns {Promise} Resolves with the created activity
|
|
1107
1143
|
*/
|
|
1108
1144
|
removeAllMuteTags(conversation, activity) {
|
|
1109
|
-
return this.untag(
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1145
|
+
return this.untag(
|
|
1146
|
+
conversation,
|
|
1147
|
+
{
|
|
1148
|
+
tags: [
|
|
1149
|
+
'MENTION_NOTIFICATIONS_OFF',
|
|
1150
|
+
'MENTION_NOTIFICATIONS_ON',
|
|
1151
|
+
'MESSAGE_NOTIFICATIONS_OFF',
|
|
1152
|
+
'MESSAGE_NOTIFICATIONS_ON',
|
|
1153
|
+
],
|
|
1154
|
+
},
|
|
1155
|
+
activity
|
|
1156
|
+
);
|
|
1117
1157
|
},
|
|
1118
1158
|
|
|
1119
1159
|
/**
|
|
@@ -1144,10 +1184,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1144
1184
|
return Promise.reject(new Error('Room avatars must be less than 1MB'));
|
|
1145
1185
|
}
|
|
1146
1186
|
|
|
1147
|
-
const convoWithUrl =
|
|
1148
|
-
Object.assign(
|
|
1149
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1150
|
-
);
|
|
1187
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1151
1188
|
|
|
1152
1189
|
return Promise.resolve()
|
|
1153
1190
|
.then(() => {
|
|
@@ -1157,7 +1194,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1157
1194
|
activity.add(avatar, uploadOptions);
|
|
1158
1195
|
|
|
1159
1196
|
return this.prepare(activity, {
|
|
1160
|
-
target: this.prepareConversation(convoWithUrl)
|
|
1197
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1161
1198
|
});
|
|
1162
1199
|
})
|
|
1163
1200
|
.then((a) => {
|
|
@@ -1179,9 +1216,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1179
1216
|
* @param {Object} conversations If this is a team, the list of conversations in the team
|
|
1180
1217
|
* @returns {String} url for the specific convo
|
|
1181
1218
|
*/
|
|
1182
|
-
getConvoUrl({
|
|
1183
|
-
id, url, cluster, conversations, generalConversationUuid
|
|
1184
|
-
}) {
|
|
1219
|
+
getConvoUrl({id, url, cluster, conversations, generalConversationUuid}) {
|
|
1185
1220
|
if (generalConversationUuid) {
|
|
1186
1221
|
// This is a Team
|
|
1187
1222
|
// Because Convo doesn't have an endpoint for the team URL
|
|
@@ -1201,9 +1236,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1201
1236
|
if (cluster) {
|
|
1202
1237
|
return this.getUrlFromClusterId({cluster, id});
|
|
1203
1238
|
}
|
|
1204
|
-
this.logger.warn(
|
|
1205
|
-
'You should be using the `url` instead of the `id` property'
|
|
1206
|
-
);
|
|
1239
|
+
this.logger.warn('You should be using the `url` instead of the `id` property');
|
|
1207
1240
|
const relatedUrl = idToUrl.get(id);
|
|
1208
1241
|
|
|
1209
1242
|
if (!relatedUrl) {
|
|
@@ -1228,11 +1261,8 @@ const Conversation = WebexPlugin.extend({
|
|
|
1228
1261
|
if (!conversation.id) {
|
|
1229
1262
|
if (conversation.url) {
|
|
1230
1263
|
conversation.id = conversation.url.split('/').pop();
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
return Promise.reject(
|
|
1234
|
-
new Error('conversation: could not identify conversation')
|
|
1235
|
-
);
|
|
1264
|
+
} else {
|
|
1265
|
+
return Promise.reject(new Error('conversation: could not identify conversation'));
|
|
1236
1266
|
}
|
|
1237
1267
|
}
|
|
1238
1268
|
|
|
@@ -1240,8 +1270,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1240
1270
|
|
|
1241
1271
|
if (options.typing) {
|
|
1242
1272
|
eventType = 'status.start_typing';
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1273
|
+
} else {
|
|
1245
1274
|
eventType = 'status.stop_typing';
|
|
1246
1275
|
}
|
|
1247
1276
|
|
|
@@ -1251,9 +1280,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
1251
1280
|
method: 'POST',
|
|
1252
1281
|
body: {
|
|
1253
1282
|
conversationId: conversation.id,
|
|
1254
|
-
eventType
|
|
1283
|
+
eventType,
|
|
1255
1284
|
},
|
|
1256
|
-
url: `${url}/${resource}
|
|
1285
|
+
url: `${url}/${resource}`,
|
|
1257
1286
|
};
|
|
1258
1287
|
|
|
1259
1288
|
return this.request(params);
|
|
@@ -1269,27 +1298,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
1269
1298
|
if (isArray(activity)) {
|
|
1270
1299
|
activity = {
|
|
1271
1300
|
object: {
|
|
1272
|
-
files: activity
|
|
1273
|
-
}
|
|
1301
|
+
files: activity,
|
|
1302
|
+
},
|
|
1274
1303
|
};
|
|
1275
1304
|
}
|
|
1276
1305
|
|
|
1277
|
-
const convoWithUrl =
|
|
1278
|
-
Object.assign(
|
|
1279
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1280
|
-
);
|
|
1306
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1281
1307
|
|
|
1282
1308
|
if (!(activity instanceof ShareActivity)) {
|
|
1283
1309
|
activity = ShareActivity.create(convoWithUrl, activity, this.webex);
|
|
1284
1310
|
}
|
|
1285
1311
|
|
|
1286
1312
|
return this.prepare(activity, {
|
|
1287
|
-
target: this.prepareConversation(convoWithUrl)
|
|
1288
|
-
})
|
|
1289
|
-
.then((a) => this.submit(a));
|
|
1313
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1314
|
+
}).then((a) => this.submit(a));
|
|
1290
1315
|
},
|
|
1291
1316
|
|
|
1292
|
-
|
|
1293
1317
|
/**
|
|
1294
1318
|
* Submits an activity to the conversation service
|
|
1295
1319
|
* @param {Object} activity
|
|
@@ -1303,15 +1327,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
1303
1327
|
method: 'POST',
|
|
1304
1328
|
body: activity,
|
|
1305
1329
|
qs: {
|
|
1306
|
-
personRefresh: true
|
|
1330
|
+
personRefresh: true,
|
|
1307
1331
|
},
|
|
1308
|
-
url: `${url}/${resource}
|
|
1332
|
+
url: `${url}/${resource}`,
|
|
1309
1333
|
};
|
|
1310
1334
|
|
|
1311
1335
|
if (activity.verb === 'share') {
|
|
1312
1336
|
Object.assign(params.qs, {
|
|
1313
1337
|
transcode: true,
|
|
1314
|
-
async: false
|
|
1338
|
+
async: false,
|
|
1315
1339
|
});
|
|
1316
1340
|
}
|
|
1317
1341
|
/**
|
|
@@ -1323,7 +1347,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1323
1347
|
const customActivityCopy = (value) => {
|
|
1324
1348
|
const {files} = params.body.object;
|
|
1325
1349
|
|
|
1326
|
-
if (
|
|
1350
|
+
if (
|
|
1351
|
+
files &&
|
|
1352
|
+
value &&
|
|
1353
|
+
files.items.length > 0 &&
|
|
1354
|
+
value.constructor === files.items[0].scr.constructor
|
|
1355
|
+
) {
|
|
1327
1356
|
const copySrc = cloneDeep(value);
|
|
1328
1357
|
|
|
1329
1358
|
copySrc.toJWE = value.toJWE;
|
|
@@ -1344,22 +1373,24 @@ const Conversation = WebexPlugin.extend({
|
|
|
1344
1373
|
if (error.body && error.body.errorCode === KEY_ROTATION_REQUIRED) {
|
|
1345
1374
|
cloneActivity.body.target.defaultActivityEncryptionKeyUrl = null;
|
|
1346
1375
|
this.request(cloneActivity);
|
|
1347
|
-
}
|
|
1348
|
-
else if (
|
|
1376
|
+
} else if (
|
|
1349
1377
|
error.body &&
|
|
1350
|
-
|
|
1378
|
+
(error.body.errorCode === KEY_ALREADY_ROTATED ||
|
|
1379
|
+
error.body.errorCode === ENCRYPTION_KEY_URL_MISMATCH)
|
|
1351
1380
|
) {
|
|
1352
1381
|
// handle when key need to update
|
|
1353
|
-
this.webex
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1382
|
+
this.webex
|
|
1383
|
+
.request({
|
|
1384
|
+
method: 'GET',
|
|
1385
|
+
api: 'conversation',
|
|
1386
|
+
resource: `conversations/${params.body.target.id}`,
|
|
1387
|
+
})
|
|
1388
|
+
.then((res) => {
|
|
1389
|
+
cloneActivity.body.target.defaultActivityEncryptionKeyUrl =
|
|
1390
|
+
res.body.defaultActivityEncryptionkeyUrl;
|
|
1391
|
+
this.request(cloneActivity);
|
|
1392
|
+
});
|
|
1393
|
+
} else {
|
|
1363
1394
|
throw error;
|
|
1364
1395
|
}
|
|
1365
1396
|
});
|
|
@@ -1371,10 +1402,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1371
1402
|
* @returns {Promise}
|
|
1372
1403
|
*/
|
|
1373
1404
|
unassign(conversation, activity) {
|
|
1374
|
-
const convoWithUrl =
|
|
1375
|
-
Object.assign(
|
|
1376
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1377
|
-
);
|
|
1405
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1378
1406
|
|
|
1379
1407
|
return this.prepare(activity, {
|
|
1380
1408
|
verb: 'unassign',
|
|
@@ -1382,11 +1410,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1382
1410
|
object: {
|
|
1383
1411
|
objectType: 'content',
|
|
1384
1412
|
files: {
|
|
1385
|
-
items: []
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
})
|
|
1389
|
-
.then((a) => this.submit(a));
|
|
1413
|
+
items: [],
|
|
1414
|
+
},
|
|
1415
|
+
},
|
|
1416
|
+
}).then((a) => this.submit(a));
|
|
1390
1417
|
},
|
|
1391
1418
|
|
|
1392
1419
|
/**
|
|
@@ -1396,9 +1423,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1396
1423
|
* @returns {Promise} Resolves with the created activity
|
|
1397
1424
|
*/
|
|
1398
1425
|
unmuteMentions(conversation, activity) {
|
|
1399
|
-
return this.tag(
|
|
1400
|
-
|
|
1401
|
-
|
|
1426
|
+
return this.tag(
|
|
1427
|
+
conversation,
|
|
1428
|
+
{
|
|
1429
|
+
tags: ['MENTION_NOTIFICATIONS_ON'],
|
|
1430
|
+
},
|
|
1431
|
+
activity
|
|
1432
|
+
);
|
|
1402
1433
|
},
|
|
1403
1434
|
|
|
1404
1435
|
/**
|
|
@@ -1408,9 +1439,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1408
1439
|
* @returns {Promise} Resolves with the created activity
|
|
1409
1440
|
*/
|
|
1410
1441
|
unmuteMessages(conversation, activity) {
|
|
1411
|
-
return this.tag(
|
|
1412
|
-
|
|
1413
|
-
|
|
1442
|
+
return this.tag(
|
|
1443
|
+
conversation,
|
|
1444
|
+
{
|
|
1445
|
+
tags: ['MESSAGE_NOTIFICATIONS_ON'],
|
|
1446
|
+
},
|
|
1447
|
+
activity
|
|
1448
|
+
);
|
|
1414
1449
|
},
|
|
1415
1450
|
|
|
1416
1451
|
/**
|
|
@@ -1420,9 +1455,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1420
1455
|
* @returns {Promise} Resolves with the created activity
|
|
1421
1456
|
*/
|
|
1422
1457
|
unignore(conversation, activity) {
|
|
1423
|
-
return this.untag(
|
|
1424
|
-
|
|
1425
|
-
|
|
1458
|
+
return this.untag(
|
|
1459
|
+
conversation,
|
|
1460
|
+
{
|
|
1461
|
+
tags: ['IGNORED'],
|
|
1462
|
+
},
|
|
1463
|
+
activity
|
|
1464
|
+
);
|
|
1426
1465
|
},
|
|
1427
1466
|
|
|
1428
1467
|
/**
|
|
@@ -1437,17 +1476,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1437
1476
|
return Promise.reject(new Error('`object` must be an object'));
|
|
1438
1477
|
}
|
|
1439
1478
|
|
|
1440
|
-
const convoWithUrl =
|
|
1441
|
-
Object.assign(
|
|
1442
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1443
|
-
);
|
|
1479
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1444
1480
|
|
|
1445
1481
|
return this.prepare(activity, {
|
|
1446
1482
|
verb: 'update',
|
|
1447
1483
|
target: this.prepareConversation(convoWithUrl),
|
|
1448
|
-
object
|
|
1449
|
-
})
|
|
1450
|
-
.then((a) => this.submit(a));
|
|
1484
|
+
object,
|
|
1485
|
+
}).then((a) => this.submit(a));
|
|
1451
1486
|
},
|
|
1452
1487
|
|
|
1453
1488
|
/**
|
|
@@ -1460,16 +1495,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1460
1495
|
* @returns {Promise<Activity>}
|
|
1461
1496
|
*/
|
|
1462
1497
|
updateKey(conversation, key, activity) {
|
|
1463
|
-
const convoWithUrl =
|
|
1464
|
-
Object.assign(
|
|
1465
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1466
|
-
);
|
|
1498
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1467
1499
|
|
|
1468
1500
|
return this.get(convoWithUrl, {
|
|
1469
1501
|
activitiesLimit: 0,
|
|
1470
|
-
includeParticipants: true
|
|
1471
|
-
})
|
|
1472
|
-
.then((c) => this._updateKey(c, key, activity));
|
|
1502
|
+
includeParticipants: true,
|
|
1503
|
+
}).then((c) => this._updateKey(c, key, activity));
|
|
1473
1504
|
},
|
|
1474
1505
|
|
|
1475
1506
|
/**
|
|
@@ -1483,52 +1514,44 @@ const Conversation = WebexPlugin.extend({
|
|
|
1483
1514
|
* @returns {Promise<Activity>}
|
|
1484
1515
|
*/
|
|
1485
1516
|
_updateKey(conversation, key, activity) {
|
|
1486
|
-
const convoWithUrl =
|
|
1487
|
-
Object.assign(
|
|
1488
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1489
|
-
);
|
|
1517
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1490
1518
|
|
|
1491
1519
|
return Promise.resolve(
|
|
1492
1520
|
key || this.webex.internal.encryption.kms.createUnboundKeys({count: 1})
|
|
1493
|
-
)
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
};
|
|
1521
|
+
).then((keys) => {
|
|
1522
|
+
const k = isArray(keys) ? keys[0] : keys;
|
|
1523
|
+
const params = {
|
|
1524
|
+
verb: 'updateKey',
|
|
1525
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1526
|
+
object: {
|
|
1527
|
+
defaultActivityEncryptionKeyUrl: k.uri,
|
|
1528
|
+
objectType: 'conversation',
|
|
1529
|
+
},
|
|
1530
|
+
};
|
|
1504
1531
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
]
|
|
1526
|
-
};
|
|
1527
|
-
}
|
|
1532
|
+
// Reminder: the kmsResourceObjectUrl is only usable if there is
|
|
1533
|
+
// defaultActivityEncryptionKeyUrl.
|
|
1534
|
+
// Valid defaultActivityEncryptionKeyUrl start with 'kms:'
|
|
1535
|
+
if (
|
|
1536
|
+
convoWithUrl.kmsResourceObjectUrl &&
|
|
1537
|
+
convoWithUrl.kmsResourceObjectUrl.startsWith('kms:')
|
|
1538
|
+
) {
|
|
1539
|
+
params.kmsMessage = {
|
|
1540
|
+
method: 'update',
|
|
1541
|
+
resourceUri: '<KRO>',
|
|
1542
|
+
uri: k.uri,
|
|
1543
|
+
};
|
|
1544
|
+
} else {
|
|
1545
|
+
params.kmsMessage = {
|
|
1546
|
+
method: 'create',
|
|
1547
|
+
uri: '/resources',
|
|
1548
|
+
userIds: map(convoWithUrl.participants.items, 'id'),
|
|
1549
|
+
keyUris: [k.uri],
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1528
1552
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
});
|
|
1553
|
+
return this.prepare(activity, params).then((a) => this.submit(a));
|
|
1554
|
+
});
|
|
1532
1555
|
},
|
|
1533
1556
|
|
|
1534
1557
|
/**
|
|
@@ -1544,10 +1567,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
1544
1567
|
resource: 'conversations',
|
|
1545
1568
|
body: payload,
|
|
1546
1569
|
qs: {
|
|
1547
|
-
forceCreate: options.allowPartialCreation
|
|
1548
|
-
}
|
|
1549
|
-
})
|
|
1550
|
-
.then((res) => res.body);
|
|
1570
|
+
forceCreate: options.allowPartialCreation,
|
|
1571
|
+
},
|
|
1572
|
+
}).then((res) => res.body);
|
|
1551
1573
|
},
|
|
1552
1574
|
|
|
1553
1575
|
/**
|
|
@@ -1592,13 +1614,11 @@ const Conversation = WebexPlugin.extend({
|
|
|
1592
1614
|
|
|
1593
1615
|
// Wait for the postauth catalog to update and then try to retrieve the
|
|
1594
1616
|
// conversation service url again.
|
|
1595
|
-
return this.webex.internal
|
|
1617
|
+
return this.webex.internal
|
|
1618
|
+
.waitForCatalog('postauth')
|
|
1596
1619
|
.then(() => this.webex.internal.services.get('conversation'))
|
|
1597
1620
|
.catch((error) => {
|
|
1598
|
-
this.logger.warn(
|
|
1599
|
-
'conversation: unable to get conversation url',
|
|
1600
|
-
error.message
|
|
1601
|
-
);
|
|
1621
|
+
this.logger.warn('conversation: unable to get conversation url', error.message);
|
|
1602
1622
|
|
|
1603
1623
|
return Promise.reject(error);
|
|
1604
1624
|
});
|
|
@@ -1611,29 +1631,30 @@ const Conversation = WebexPlugin.extend({
|
|
|
1611
1631
|
*/
|
|
1612
1632
|
_inferConversationUrl(conversation) {
|
|
1613
1633
|
if (conversation.id) {
|
|
1614
|
-
return this.webex.internal.feature
|
|
1634
|
+
return this.webex.internal.feature
|
|
1635
|
+
.getFeature('developer', 'web-high-availability')
|
|
1615
1636
|
.then((haMessagingEnabled) => {
|
|
1616
1637
|
if (haMessagingEnabled) {
|
|
1617
1638
|
// recompute conversation URL each time as the host may have changed
|
|
1618
1639
|
// since last usage
|
|
1619
|
-
return this.getConversationUrl()
|
|
1620
|
-
.
|
|
1621
|
-
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1640
|
+
return this.getConversationUrl().then((url) => {
|
|
1641
|
+
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1622
1642
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1643
|
+
return conversation;
|
|
1644
|
+
});
|
|
1625
1645
|
}
|
|
1626
1646
|
if (!conversation.url) {
|
|
1627
|
-
return this.getConversationUrl()
|
|
1628
|
-
.
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1647
|
+
return this.getConversationUrl().then((url) => {
|
|
1648
|
+
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1649
|
+
/* istanbul ignore else */
|
|
1650
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1651
|
+
this.logger.warn(
|
|
1652
|
+
'conversation: inferred conversation url from conversation id; please pass whole conversation objects to Conversation methods'
|
|
1653
|
+
);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
return conversation;
|
|
1657
|
+
});
|
|
1637
1658
|
}
|
|
1638
1659
|
|
|
1639
1660
|
return Promise.resolve(conversation);
|
|
@@ -1657,11 +1678,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1657
1678
|
|
|
1658
1679
|
return this._list({
|
|
1659
1680
|
qs: omit(options, 'resource'),
|
|
1660
|
-
url: `${url}/${resource}
|
|
1681
|
+
url: `${url}/${resource}`,
|
|
1661
1682
|
});
|
|
1662
1683
|
},
|
|
1663
1684
|
|
|
1664
|
-
|
|
1665
1685
|
/**
|
|
1666
1686
|
* common interface for facade of generator functions
|
|
1667
1687
|
* @typedef {object} IGeneratorResponse
|
|
@@ -1688,10 +1708,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1688
1708
|
* jumpToActivity - gets searched-for activity and surrounding activities
|
|
1689
1709
|
*/
|
|
1690
1710
|
listActivitiesThreadOrdered(options) {
|
|
1691
|
-
const {
|
|
1692
|
-
conversationUrl,
|
|
1693
|
-
conversationId
|
|
1694
|
-
} = options;
|
|
1711
|
+
const {conversationUrl, conversationId} = options;
|
|
1695
1712
|
|
|
1696
1713
|
if (!conversationUrl && !conversationId) {
|
|
1697
1714
|
throw new Error('must provide a conversation URL or conversation ID');
|
|
@@ -1723,7 +1740,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1723
1740
|
}
|
|
1724
1741
|
|
|
1725
1742
|
const searchOptions = {
|
|
1726
|
-
...baseOptions,
|
|
1743
|
+
...baseOptions,
|
|
1744
|
+
url: newUrl,
|
|
1745
|
+
queryType: MID,
|
|
1746
|
+
search: searchObject,
|
|
1727
1747
|
};
|
|
1728
1748
|
|
|
1729
1749
|
threadOrderer = this._listActivitiesThreadOrdered(searchOptions);
|
|
@@ -1732,7 +1752,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1732
1752
|
|
|
1733
1753
|
return {
|
|
1734
1754
|
done: true,
|
|
1735
|
-
value: searchResults
|
|
1755
|
+
value: searchResults,
|
|
1736
1756
|
};
|
|
1737
1757
|
};
|
|
1738
1758
|
|
|
@@ -1744,11 +1764,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1744
1764
|
const {value = []} = await threadOrderer.next(olderOptions);
|
|
1745
1765
|
|
|
1746
1766
|
const oldestInBatch = value[0] && value[0].activity;
|
|
1747
|
-
const moreActivitiesExist =
|
|
1767
|
+
const moreActivitiesExist =
|
|
1768
|
+
oldestInBatch && getActivityType(oldestInBatch) !== ACTIVITY_TYPES.CREATE;
|
|
1748
1769
|
|
|
1749
1770
|
return {
|
|
1750
1771
|
done: !moreActivitiesExist,
|
|
1751
|
-
value
|
|
1772
|
+
value,
|
|
1752
1773
|
};
|
|
1753
1774
|
};
|
|
1754
1775
|
|
|
@@ -1763,22 +1784,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
1763
1784
|
|
|
1764
1785
|
return {
|
|
1765
1786
|
done: !value.length,
|
|
1766
|
-
value
|
|
1787
|
+
value,
|
|
1767
1788
|
};
|
|
1768
1789
|
};
|
|
1769
1790
|
|
|
1770
1791
|
return {
|
|
1771
1792
|
jumpToActivity,
|
|
1772
1793
|
getNewer,
|
|
1773
|
-
getOlder
|
|
1794
|
+
getOlder,
|
|
1774
1795
|
};
|
|
1775
1796
|
},
|
|
1776
1797
|
|
|
1777
1798
|
/**
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1799
|
+
* Represents reactions to messages
|
|
1800
|
+
* @typedef {object} Reaction
|
|
1801
|
+
* @property {object} activity reaction2summary server activity object
|
|
1802
|
+
*/
|
|
1782
1803
|
|
|
1783
1804
|
/**
|
|
1784
1805
|
* Represents a root (parent, with or without children) activity, along with any replies and reactions
|
|
@@ -1804,34 +1825,30 @@ const Conversation = WebexPlugin.extend({
|
|
|
1804
1825
|
*
|
|
1805
1826
|
* @returns {void}
|
|
1806
1827
|
*/
|
|
1807
|
-
async*
|
|
1828
|
+
async *_listActivitiesThreadOrdered(options = {}) {
|
|
1808
1829
|
// ***********************************************
|
|
1809
1830
|
// INSTANCE STATE VARIABLES
|
|
1810
1831
|
// variables that will be used for the life of the generator
|
|
1811
1832
|
// ***********************************************
|
|
1812
1833
|
|
|
1813
|
-
let {
|
|
1814
|
-
minActivities = defaultMinDisplayableActivities,
|
|
1815
|
-
queryType = INITIAL
|
|
1816
|
-
} = options;
|
|
1834
|
+
let {minActivities = defaultMinDisplayableActivities, queryType = INITIAL} = options;
|
|
1817
1835
|
|
|
1818
1836
|
// must fetch initially before getting newer activities!
|
|
1819
1837
|
if (queryType === NEWER) {
|
|
1820
1838
|
queryType = INITIAL;
|
|
1821
1839
|
}
|
|
1822
1840
|
|
|
1823
|
-
const {
|
|
1824
|
-
url: convoUrl,
|
|
1825
|
-
search = {},
|
|
1826
|
-
includeChildren
|
|
1827
|
-
} = options;
|
|
1841
|
+
const {url: convoUrl, search = {}, includeChildren} = options;
|
|
1828
1842
|
|
|
1829
1843
|
// manage oldest, newest activities (ie bookends)
|
|
1830
1844
|
const {setBookends, getNewestAct, getOldestAct} = bookendManager();
|
|
1831
1845
|
|
|
1832
1846
|
// default batch should be equal to minActivities when fetching back in time, but halved when fetching newer due to subsequent child fetches filling up the minActivities count
|
|
1833
1847
|
// reduces server RTs when fetching older activities
|
|
1834
|
-
const defaultBatchSize =
|
|
1848
|
+
const defaultBatchSize =
|
|
1849
|
+
queryType === INITIAL || queryType === OLDER
|
|
1850
|
+
? minActivities
|
|
1851
|
+
: Math.max(minBatchSize, Math.ceil(minActivities / 2));
|
|
1835
1852
|
let batchSize = defaultBatchSize;
|
|
1836
1853
|
|
|
1837
1854
|
// exposes activity states and handlers with simple getters
|
|
@@ -1853,22 +1870,19 @@ const Conversation = WebexPlugin.extend({
|
|
|
1853
1870
|
|
|
1854
1871
|
// used to determine if we should continue to fetch older activities
|
|
1855
1872
|
// must be set per iteration, as querying newer activities is still valid when all end of convo has been reached
|
|
1856
|
-
const {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
[
|
|
1869
|
-
[ACTIVITY_TYPES.TOMBSTONE]: addNewRoot,
|
|
1870
|
-
[ACTIVITY_TYPES.CREATE]: addNewRoot
|
|
1871
|
-
}[type]);
|
|
1873
|
+
const {getNoMoreActs, checkAndSetNoMoreActs, checkAndSetNoOlderActs, checkAndSetNoNewerActs} =
|
|
1874
|
+
noMoreActivitiesManager();
|
|
1875
|
+
|
|
1876
|
+
const getActivityHandlerByType = (type) =>
|
|
1877
|
+
({
|
|
1878
|
+
[ACTIVITY_TYPES.ROOT]: addNewRoot,
|
|
1879
|
+
[ACTIVITY_TYPES.REPLY]: getActivityHandlerByKey(ACTIVITY_TYPES.REPLY),
|
|
1880
|
+
[ACTIVITY_TYPES.EDIT]: getActivityHandlerByKey(ACTIVITY_TYPES.EDIT),
|
|
1881
|
+
[ACTIVITY_TYPES.REACTION]: getActivityHandlerByKey(ACTIVITY_TYPES.REACTION),
|
|
1882
|
+
[ACTIVITY_TYPES.REACTION_SELF]: getActivityHandlerByKey(ACTIVITY_TYPES.REACTION_SELF),
|
|
1883
|
+
[ACTIVITY_TYPES.TOMBSTONE]: addNewRoot,
|
|
1884
|
+
[ACTIVITY_TYPES.CREATE]: addNewRoot,
|
|
1885
|
+
}[type]);
|
|
1872
1886
|
|
|
1873
1887
|
const handleNewActivity = (activity) => {
|
|
1874
1888
|
const actType = getActivityType(activity);
|
|
@@ -1906,12 +1920,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1906
1920
|
handleNewActivities(activities);
|
|
1907
1921
|
};
|
|
1908
1922
|
|
|
1909
|
-
const getQueryResponseHandler = (type) =>
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1923
|
+
const getQueryResponseHandler = (type) =>
|
|
1924
|
+
({
|
|
1925
|
+
[OLDER]: handleOlderQuery,
|
|
1926
|
+
[NEWER]: handleNewerQuery,
|
|
1927
|
+
[MID]: handleSearch,
|
|
1928
|
+
[INITIAL]: handleOlderQuery,
|
|
1929
|
+
}[type]);
|
|
1915
1930
|
|
|
1916
1931
|
// ***********************************************
|
|
1917
1932
|
// INNER LOOP
|
|
@@ -1930,7 +1945,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1930
1945
|
conversationUrl: convoUrl,
|
|
1931
1946
|
limit: batchSize,
|
|
1932
1947
|
includeChildren,
|
|
1933
|
-
...query
|
|
1948
|
+
...query,
|
|
1934
1949
|
};
|
|
1935
1950
|
|
|
1936
1951
|
// request activities in batches
|
|
@@ -1953,10 +1968,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1953
1968
|
}
|
|
1954
1969
|
|
|
1955
1970
|
// we dont always need to fetch for parents
|
|
1956
|
-
const [
|
|
1957
|
-
allBatchActivities,
|
|
1958
|
-
parents = {}
|
|
1959
|
-
] = await Promise.all($fetchRequests);
|
|
1971
|
+
const [allBatchActivities, parents = {}] = await Promise.all($fetchRequests);
|
|
1960
1972
|
|
|
1961
1973
|
// use query type to decide how to handle response
|
|
1962
1974
|
const handler = getQueryResponseHandler(queryType);
|
|
@@ -1968,11 +1980,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1968
1980
|
do this by checking the hash for each of the above parent IDs
|
|
1969
1981
|
fetch children when we have a parent whose ID is represented in the parent ID lists
|
|
1970
1982
|
*/
|
|
1971
|
-
const {
|
|
1972
|
-
reply: replyIds = [],
|
|
1973
|
-
edit: editIds = [],
|
|
1974
|
-
reaction: reactionIds = []
|
|
1975
|
-
} = parents;
|
|
1983
|
+
const {reply: replyIds = [], edit: editIds = [], reaction: reactionIds = []} = parents;
|
|
1976
1984
|
|
|
1977
1985
|
// if no parent IDs returned, do nothing
|
|
1978
1986
|
if (replyIds.length || editIds.length || reactionIds.length) {
|
|
@@ -1985,11 +1993,16 @@ const Conversation = WebexPlugin.extend({
|
|
|
1985
1993
|
|
|
1986
1994
|
const childFetchOptions = {
|
|
1987
1995
|
conversationUrl: convoUrl,
|
|
1988
|
-
activityParentId: actId
|
|
1996
|
+
activityParentId: actId,
|
|
1989
1997
|
};
|
|
1990
1998
|
|
|
1991
1999
|
if (reactionIds.includes(actId)) {
|
|
1992
|
-
$reactionFetches.push(
|
|
2000
|
+
$reactionFetches.push(
|
|
2001
|
+
this.getReactionSummaryByParentId(convoUrl, actId, {
|
|
2002
|
+
activityType: 'reactionSummary',
|
|
2003
|
+
includeChildren: true,
|
|
2004
|
+
})
|
|
2005
|
+
);
|
|
1993
2006
|
}
|
|
1994
2007
|
if (replyIds.includes(actId)) {
|
|
1995
2008
|
childFetchOptions.query = {activityType: 'reply'};
|
|
@@ -2005,14 +2018,19 @@ const Conversation = WebexPlugin.extend({
|
|
|
2005
2018
|
const [reactions, replies, edits] = await Promise.all([
|
|
2006
2019
|
Promise.all($reactionFetches),
|
|
2007
2020
|
Promise.all($replyFetches),
|
|
2008
|
-
Promise.all($editFetches)
|
|
2021
|
+
Promise.all($editFetches),
|
|
2009
2022
|
]);
|
|
2010
2023
|
|
|
2011
2024
|
// new reactions may have come in that also need their reactions fetched
|
|
2012
2025
|
const newReplyReactions = await Promise.all(
|
|
2013
2026
|
replies
|
|
2014
2027
|
.filter((reply) => replyIds.includes(reply.id))
|
|
2015
|
-
.map((reply) =>
|
|
2028
|
+
.map((reply) =>
|
|
2029
|
+
this.getReactionSummaryByParentId(convoUrl, reply.id, {
|
|
2030
|
+
activityType: 'reactionSummary',
|
|
2031
|
+
includeChildren: true,
|
|
2032
|
+
})
|
|
2033
|
+
)
|
|
2016
2034
|
);
|
|
2017
2035
|
|
|
2018
2036
|
const allReactions = [...reactions, ...newReplyReactions];
|
|
@@ -2060,13 +2078,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
2060
2078
|
// we're still building our activity list - derive new query from prior query and start loop again
|
|
2061
2079
|
if (queryType === INITIAL) {
|
|
2062
2080
|
query = getQuery(OLDER, {oldestPublishedDate: currentOldestPublishedDate, batchSize});
|
|
2063
|
-
}
|
|
2064
|
-
else {
|
|
2081
|
+
} else {
|
|
2065
2082
|
query = getQuery(queryType, {
|
|
2066
2083
|
batchSize,
|
|
2067
2084
|
activityToSearch: search,
|
|
2068
2085
|
oldestPublishedDate: currentOldestPublishedDate,
|
|
2069
|
-
newestPublishedDate: currentNewestPublishedDate
|
|
2086
|
+
newestPublishedDate: currentNewestPublishedDate,
|
|
2070
2087
|
});
|
|
2071
2088
|
}
|
|
2072
2089
|
|
|
@@ -2087,7 +2104,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2087
2104
|
return replies;
|
|
2088
2105
|
}
|
|
2089
2106
|
|
|
2090
|
-
const sortedReplies = sortActivitiesByPublishedDate(
|
|
2107
|
+
const sortedReplies = sortActivitiesByPublishedDate(
|
|
2108
|
+
getActivityObjectsFromMap(repliesByParentId)
|
|
2109
|
+
);
|
|
2091
2110
|
|
|
2092
2111
|
sortedReplies.forEach((replyActivity) => {
|
|
2093
2112
|
const replyId = replyActivity.id;
|
|
@@ -2097,20 +2116,26 @@ const Conversation = WebexPlugin.extend({
|
|
|
2097
2116
|
|
|
2098
2117
|
const latestActivity = edit || replyActivity;
|
|
2099
2118
|
// hash of root activities (in case of plain reply) and the reply activity (in case of edit)
|
|
2100
|
-
const allRelevantActivitiesArr = [
|
|
2119
|
+
const allRelevantActivitiesArr = [
|
|
2120
|
+
...getActivityObjectsFromMap(getRootActivityHash()),
|
|
2121
|
+
...getActivityObjectsFromMap(repliesByParentId),
|
|
2122
|
+
];
|
|
2101
2123
|
const allRelevantActivities = allRelevantActivitiesArr.reduce((hashMap, act) => {
|
|
2102
2124
|
hashMap[act.id] = act;
|
|
2103
2125
|
|
|
2104
2126
|
return hashMap;
|
|
2105
2127
|
}, {});
|
|
2106
2128
|
|
|
2107
|
-
const finalReply = this._createParsedServerActivity(
|
|
2129
|
+
const finalReply = this._createParsedServerActivity(
|
|
2130
|
+
latestActivity,
|
|
2131
|
+
allRelevantActivities
|
|
2132
|
+
);
|
|
2108
2133
|
|
|
2109
2134
|
const fullReply = {
|
|
2110
2135
|
id: replyId,
|
|
2111
2136
|
activity: finalReply,
|
|
2112
2137
|
reaction,
|
|
2113
|
-
reactionSelf
|
|
2138
|
+
reactionSelf,
|
|
2114
2139
|
};
|
|
2115
2140
|
|
|
2116
2141
|
const sanitizedFullReply = sanitizeActivity(fullReply);
|
|
@@ -2121,7 +2146,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2121
2146
|
return replies;
|
|
2122
2147
|
};
|
|
2123
2148
|
|
|
2124
|
-
const orderedRoots = sortActivitiesByPublishedDate(
|
|
2149
|
+
const orderedRoots = sortActivitiesByPublishedDate(
|
|
2150
|
+
getActivityObjectsFromMap(getRootActivityHash())
|
|
2151
|
+
);
|
|
2125
2152
|
|
|
2126
2153
|
orderedRoots.forEach((rootActivity) => {
|
|
2127
2154
|
const rootId = rootActivity.id;
|
|
@@ -2131,13 +2158,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
2131
2158
|
const reactionSelf = getActivityByTypeAndParentId(ACTIVITY_TYPES.REACTION_SELF, rootId);
|
|
2132
2159
|
|
|
2133
2160
|
const latestActivity = edit || rootActivity;
|
|
2134
|
-
const finalActivity = this._createParsedServerActivity(latestActivity, {
|
|
2161
|
+
const finalActivity = this._createParsedServerActivity(latestActivity, {
|
|
2162
|
+
[rootId]: rootActivity,
|
|
2163
|
+
});
|
|
2135
2164
|
|
|
2136
2165
|
const fullRoot = {
|
|
2137
2166
|
id: rootId,
|
|
2138
2167
|
activity: finalActivity,
|
|
2139
2168
|
reaction,
|
|
2140
|
-
reactionSelf
|
|
2169
|
+
reactionSelf,
|
|
2141
2170
|
};
|
|
2142
2171
|
|
|
2143
2172
|
const sanitizedFullRoot = sanitizeActivity(fullRoot);
|
|
@@ -2159,10 +2188,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2159
2188
|
activityToSearch: search,
|
|
2160
2189
|
oldestPublishedDate: currentOldestPublishedDate,
|
|
2161
2190
|
newestPublishedDate: currentNewestPublishedDate,
|
|
2162
|
-
batchSize
|
|
2191
|
+
batchSize,
|
|
2163
2192
|
});
|
|
2164
|
-
}
|
|
2165
|
-
else {
|
|
2193
|
+
} else {
|
|
2166
2194
|
return;
|
|
2167
2195
|
}
|
|
2168
2196
|
}
|
|
@@ -2183,10 +2211,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
2183
2211
|
*/
|
|
2184
2212
|
|
|
2185
2213
|
/**
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2214
|
+
* hashmap of server activities, keyed by id
|
|
2215
|
+
* @typedef {object} ActivityHash
|
|
2216
|
+
* @property {Object}
|
|
2217
|
+
*/
|
|
2190
2218
|
|
|
2191
2219
|
/**
|
|
2192
2220
|
* extends a given server object with fields that point to their parent activities from the hashmap passed in
|
|
@@ -2198,7 +2226,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2198
2226
|
const isOrphan = getIsActivityOrphaned(activity, allActivitiesHash);
|
|
2199
2227
|
|
|
2200
2228
|
if (isOrphan) {
|
|
2201
|
-
throw new Error(
|
|
2229
|
+
throw new Error(
|
|
2230
|
+
'activity has a parent that cannot be found in allActivitiesHash! please handle this as necessary'
|
|
2231
|
+
);
|
|
2202
2232
|
}
|
|
2203
2233
|
|
|
2204
2234
|
const activityType = determineActivityType(activity, allActivitiesHash);
|
|
@@ -2230,12 +2260,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
2230
2260
|
* @returns {Promise<Array<Conversation>>}
|
|
2231
2261
|
*/
|
|
2232
2262
|
async _list(options) {
|
|
2233
|
-
options.qs =
|
|
2263
|
+
options.qs = {
|
|
2234
2264
|
personRefresh: true,
|
|
2235
2265
|
uuidEntryFormat: true,
|
|
2236
2266
|
activitiesLimit: 0,
|
|
2237
|
-
participantsLimit: 0
|
|
2238
|
-
|
|
2267
|
+
participantsLimit: 0,
|
|
2268
|
+
...options.qs,
|
|
2269
|
+
};
|
|
2239
2270
|
|
|
2240
2271
|
const res = await this.request(options);
|
|
2241
2272
|
|
|
@@ -2243,8 +2274,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2243
2274
|
|
|
2244
2275
|
if (!res.body || !res.body.items || res.body.items.length === 0) {
|
|
2245
2276
|
list = [];
|
|
2246
|
-
}
|
|
2247
|
-
else {
|
|
2277
|
+
} else {
|
|
2248
2278
|
list = res.body.items.slice(0);
|
|
2249
2279
|
if (last(list).published < list[0].published) {
|
|
2250
2280
|
list.reverse();
|
|
@@ -2263,9 +2293,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2263
2293
|
// This won't get us the exact limit but it will retrieve something
|
|
2264
2294
|
// from every cluster listed.
|
|
2265
2295
|
if (options.limit) {
|
|
2266
|
-
limit = Math.floor(
|
|
2267
|
-
(options.limit.value - list.length) / res.body.additionalUrls.length
|
|
2268
|
-
);
|
|
2296
|
+
limit = Math.floor((options.limit.value - list.length) / res.body.additionalUrls.length);
|
|
2269
2297
|
}
|
|
2270
2298
|
|
|
2271
2299
|
// If the limit is 0 for some reason,
|
|
@@ -2274,7 +2302,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2274
2302
|
const results = await Promise.all(
|
|
2275
2303
|
res.body.additionalUrls.map((host) => {
|
|
2276
2304
|
const url = `${host}/${options.resource}`;
|
|
2277
|
-
const newOptions =
|
|
2305
|
+
const newOptions = {...options, uri: url, url};
|
|
2278
2306
|
|
|
2279
2307
|
if (options.limit) {
|
|
2280
2308
|
newOptions.qs[newOptions.limit.name] = limit;
|
|
@@ -2309,19 +2337,23 @@ const Conversation = WebexPlugin.extend({
|
|
|
2309
2337
|
* @returns {Promise<Conversation>}
|
|
2310
2338
|
*/
|
|
2311
2339
|
_maybeCreateOneOnOneThenPost(params, options) {
|
|
2312
|
-
return this.get(
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2340
|
+
return this.get(
|
|
2341
|
+
defaults({
|
|
2342
|
+
// the use of uniq in Conversation#create guarantees participant[1] will
|
|
2343
|
+
// always be the other user
|
|
2344
|
+
user: params.participants[1],
|
|
2345
|
+
}),
|
|
2346
|
+
Object.assign(options, {includeConvWithDeletedUserUUID: true, includeParticipants: true})
|
|
2347
|
+
)
|
|
2317
2348
|
.then((conversation) => {
|
|
2318
2349
|
if (params.comment || params.html) {
|
|
2319
|
-
return this.post(conversation, {content: params.html, displayName: params.comment})
|
|
2320
|
-
|
|
2350
|
+
return this.post(conversation, {content: params.html, displayName: params.comment}).then(
|
|
2351
|
+
(activity) => {
|
|
2321
2352
|
conversation.activities.items.push(activity);
|
|
2322
2353
|
|
|
2323
2354
|
return conversation;
|
|
2324
|
-
}
|
|
2355
|
+
}
|
|
2356
|
+
);
|
|
2325
2357
|
}
|
|
2326
2358
|
|
|
2327
2359
|
return conversation;
|
|
@@ -2343,17 +2375,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
2343
2375
|
_prepareConversationForCreation(params) {
|
|
2344
2376
|
const payload = {
|
|
2345
2377
|
activities: {
|
|
2346
|
-
items: [
|
|
2347
|
-
this.expand('create')
|
|
2348
|
-
]
|
|
2378
|
+
items: [this.expand('create')],
|
|
2349
2379
|
},
|
|
2350
2380
|
objectType: 'conversation',
|
|
2351
2381
|
kmsMessage: {
|
|
2352
2382
|
method: 'create',
|
|
2353
2383
|
uri: '/resources',
|
|
2354
2384
|
userIds: cloneDeep(params.participants),
|
|
2355
|
-
keyUris: []
|
|
2356
|
-
}
|
|
2385
|
+
keyUris: [],
|
|
2386
|
+
},
|
|
2357
2387
|
};
|
|
2358
2388
|
|
|
2359
2389
|
if (params.displayName) {
|
|
@@ -2365,32 +2395,40 @@ const Conversation = WebexPlugin.extend({
|
|
|
2365
2395
|
}
|
|
2366
2396
|
|
|
2367
2397
|
params.participants.forEach((participant) => {
|
|
2368
|
-
payload.activities.items.push(
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2398
|
+
payload.activities.items.push(
|
|
2399
|
+
this.expand('add', {
|
|
2400
|
+
objectType: 'person',
|
|
2401
|
+
id: participant,
|
|
2402
|
+
})
|
|
2403
|
+
);
|
|
2372
2404
|
});
|
|
2373
2405
|
|
|
2374
2406
|
if (params.comment) {
|
|
2375
|
-
payload.activities.items.push(
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2407
|
+
payload.activities.items.push(
|
|
2408
|
+
this.expand('post', {
|
|
2409
|
+
objectType: 'comment',
|
|
2410
|
+
content: params.html,
|
|
2411
|
+
displayName: params.comment,
|
|
2412
|
+
})
|
|
2413
|
+
);
|
|
2380
2414
|
}
|
|
2381
2415
|
|
|
2382
2416
|
if (!params.isDefaultClassification && params.classificationId) {
|
|
2383
|
-
payload.activities.items.push(
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2417
|
+
payload.activities.items.push(
|
|
2418
|
+
this.expand('update', {
|
|
2419
|
+
objectType: 'classification',
|
|
2420
|
+
classificationId: params.classificationId,
|
|
2421
|
+
effectiveDate: params.effectiveDate,
|
|
2422
|
+
})
|
|
2423
|
+
);
|
|
2388
2424
|
}
|
|
2389
2425
|
|
|
2390
2426
|
if (params.favorite) {
|
|
2391
|
-
payload.activities.items.push(
|
|
2392
|
-
|
|
2393
|
-
|
|
2427
|
+
payload.activities.items.push(
|
|
2428
|
+
this.expand('favorite', {
|
|
2429
|
+
objectType: 'conversation',
|
|
2430
|
+
})
|
|
2431
|
+
);
|
|
2394
2432
|
}
|
|
2395
2433
|
|
|
2396
2434
|
return payload;
|
|
@@ -2406,68 +2444,59 @@ const Conversation = WebexPlugin.extend({
|
|
|
2406
2444
|
return Promise.resolve(conversation);
|
|
2407
2445
|
}
|
|
2408
2446
|
|
|
2409
|
-
return Promise.all(
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2447
|
+
return Promise.all(
|
|
2448
|
+
conversation.participants.items.map((participant) => {
|
|
2449
|
+
// ROOMs or LYRA_SPACEs do not have email addresses, so there's no point attempting to
|
|
2450
|
+
// record their UUIDs.
|
|
2451
|
+
if (participant.type === 'ROOM' || participant.type === 'LYRA_SPACE') {
|
|
2452
|
+
return Promise.resolve();
|
|
2453
|
+
}
|
|
2415
2454
|
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2455
|
+
return this.webex.internal.user
|
|
2456
|
+
.recordUUID(participant)
|
|
2457
|
+
.catch((err) => this.logger.warn('Could not record uuid', err));
|
|
2458
|
+
})
|
|
2459
|
+
);
|
|
2460
|
+
},
|
|
2420
2461
|
});
|
|
2421
2462
|
|
|
2422
|
-
[
|
|
2423
|
-
'favorite',
|
|
2424
|
-
'hide',
|
|
2425
|
-
'lock',
|
|
2426
|
-
'mute',
|
|
2427
|
-
'unfavorite',
|
|
2428
|
-
'unhide',
|
|
2429
|
-
'unlock',
|
|
2430
|
-
'unmute'
|
|
2431
|
-
].forEach((verb) => {
|
|
2463
|
+
['favorite', 'hide', 'lock', 'mute', 'unfavorite', 'unhide', 'unlock', 'unmute'].forEach((verb) => {
|
|
2432
2464
|
Conversation.prototype[verb] = function submitSimpleActivity(conversation, activity) {
|
|
2433
|
-
const convoWithUrl =
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
)
|
|
2438
|
-
);
|
|
2465
|
+
const convoWithUrl = this.prepareConversation({
|
|
2466
|
+
...conversation,
|
|
2467
|
+
url: this.getConvoUrl(conversation),
|
|
2468
|
+
});
|
|
2439
2469
|
|
|
2440
2470
|
return this.prepare(activity, {
|
|
2441
2471
|
verb,
|
|
2442
2472
|
object: convoWithUrl,
|
|
2443
|
-
target: convoWithUrl
|
|
2444
|
-
})
|
|
2445
|
-
.then((a) => this.submit(a));
|
|
2473
|
+
target: convoWithUrl,
|
|
2474
|
+
}).then((a) => this.submit(a));
|
|
2446
2475
|
};
|
|
2447
2476
|
});
|
|
2448
2477
|
|
|
2449
|
-
[
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2457
|
-
);
|
|
2478
|
+
['assignModerator', 'unassignModerator'].forEach((verb) => {
|
|
2479
|
+
Conversation.prototype[verb] = function submitModerationChangeActivity(
|
|
2480
|
+
conversation,
|
|
2481
|
+
moderator,
|
|
2482
|
+
activity
|
|
2483
|
+
) {
|
|
2484
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
2458
2485
|
|
|
2459
2486
|
return Promise.all([
|
|
2460
2487
|
convoWithUrl,
|
|
2461
|
-
moderator ? this.webex.internal.user.asUUID(moderator) : this.webex.internal.device.userId
|
|
2488
|
+
moderator ? this.webex.internal.user.asUUID(moderator) : this.webex.internal.device.userId,
|
|
2462
2489
|
])
|
|
2463
|
-
.then(([c, userId]) =>
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2490
|
+
.then(([c, userId]) =>
|
|
2491
|
+
this.prepare(activity, {
|
|
2492
|
+
verb,
|
|
2493
|
+
target: this.prepareConversation(c),
|
|
2494
|
+
object: {
|
|
2495
|
+
id: userId,
|
|
2496
|
+
objectType: 'person',
|
|
2497
|
+
},
|
|
2498
|
+
})
|
|
2499
|
+
)
|
|
2471
2500
|
.then((a) => this.submit(a));
|
|
2472
2501
|
};
|
|
2473
2502
|
});
|
|
@@ -2479,56 +2508,44 @@ const Conversation = WebexPlugin.extend({
|
|
|
2479
2508
|
* @param {Activity} activity
|
|
2480
2509
|
* @returns {Promise<Activity>}
|
|
2481
2510
|
*/
|
|
2482
|
-
[
|
|
2483
|
-
'setSpaceProperty',
|
|
2484
|
-
'unsetSpaceProperty'
|
|
2485
|
-
].forEach((fnName) => {
|
|
2511
|
+
['setSpaceProperty', 'unsetSpaceProperty'].forEach((fnName) => {
|
|
2486
2512
|
const verb = fnName.startsWith('set') ? 'set' : 'unset';
|
|
2487
2513
|
|
|
2488
|
-
Conversation.prototype[fnName] = function submitSpacePropertyActivity(
|
|
2514
|
+
Conversation.prototype[fnName] = function submitSpacePropertyActivity(
|
|
2515
|
+
conversation,
|
|
2516
|
+
tag,
|
|
2517
|
+
activity
|
|
2518
|
+
) {
|
|
2489
2519
|
if (!isString(tag)) {
|
|
2490
2520
|
return Promise.reject(new Error('`tag` must be a string'));
|
|
2491
2521
|
}
|
|
2492
2522
|
|
|
2493
|
-
const convoWithUrl =
|
|
2494
|
-
Object.assign(
|
|
2495
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2496
|
-
);
|
|
2523
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
2497
2524
|
|
|
2498
2525
|
return this.prepare(activity, {
|
|
2499
2526
|
verb,
|
|
2500
2527
|
target: this.prepareConversation(convoWithUrl),
|
|
2501
2528
|
object: {
|
|
2502
2529
|
tags: [tag],
|
|
2503
|
-
objectType: 'spaceProperty'
|
|
2504
|
-
}
|
|
2505
|
-
})
|
|
2506
|
-
.then((a) => this.submit(a));
|
|
2530
|
+
objectType: 'spaceProperty',
|
|
2531
|
+
},
|
|
2532
|
+
}).then((a) => this.submit(a));
|
|
2507
2533
|
};
|
|
2508
2534
|
});
|
|
2509
2535
|
|
|
2510
|
-
[
|
|
2511
|
-
'tag',
|
|
2512
|
-
'untag'
|
|
2513
|
-
].forEach((verb) => {
|
|
2536
|
+
['tag', 'untag'].forEach((verb) => {
|
|
2514
2537
|
Conversation.prototype[verb] = function submitObjectActivity(conversation, object, activity) {
|
|
2515
2538
|
if (!isObject(object)) {
|
|
2516
2539
|
return Promise.reject(new Error('`object` must be an object'));
|
|
2517
2540
|
}
|
|
2518
2541
|
|
|
2519
|
-
const c =
|
|
2520
|
-
this.prepareConversation(
|
|
2521
|
-
Object.assign(
|
|
2522
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2523
|
-
)
|
|
2524
|
-
);
|
|
2542
|
+
const c = this.prepareConversation({...conversation, url: this.getConvoUrl(conversation)});
|
|
2525
2543
|
|
|
2526
2544
|
return this.prepare(activity, {
|
|
2527
2545
|
verb,
|
|
2528
2546
|
target: c,
|
|
2529
|
-
object: Object.assign(c, object)
|
|
2530
|
-
})
|
|
2531
|
-
.then((a) => this.submit(a));
|
|
2547
|
+
object: Object.assign(c, object),
|
|
2548
|
+
}).then((a) => this.submit(a));
|
|
2532
2549
|
};
|
|
2533
2550
|
});
|
|
2534
2551
|
|