@webex/internal-plugin-conversation 3.0.0-beta.3 → 3.0.0-beta.300
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 +791 -1202
- 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 +17 -49
- 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 +40 -106
- 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 +621 -591
- package/src/decryption-transforms.js +103 -62
- package/src/encryption-transforms.js +111 -83
- package/src/index.js +82 -66
- package/src/share-activity.js +64 -55
- package/src/to-array.js +2 -2
- package/test/integration/spec/create.js +186 -121
- package/test/integration/spec/encryption.js +249 -186
- package/test/integration/spec/get.js +764 -514
- 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 +265 -163
- package/test/unit/spec/decrypt-transforms.js +112 -131
- package/test/unit/spec/encryption-transforms.js +47 -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,32 +302,37 @@ 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
|
/**
|
|
295
310
|
* delete a reaction
|
|
296
311
|
* @param {Object} conversation
|
|
297
|
-
* @param {Object} reactionId
|
|
312
|
+
* @param {Object} reactionId,
|
|
313
|
+
* @param {String} recipientId,
|
|
298
314
|
* @returns {Promise<Activity>}
|
|
299
315
|
*/
|
|
300
|
-
deleteReaction(conversation, reactionId) {
|
|
316
|
+
deleteReaction(conversation, reactionId, recipientId) {
|
|
301
317
|
const deleteReactionPayload = {
|
|
302
318
|
actor: {objectType: 'person', id: this.webex.internal.device.userId},
|
|
303
319
|
object: {
|
|
304
320
|
id: reactionId,
|
|
305
|
-
objectType: 'activity'
|
|
321
|
+
objectType: 'activity',
|
|
306
322
|
},
|
|
307
323
|
objectType: 'activity',
|
|
308
324
|
target: {
|
|
309
325
|
id: conversation.id,
|
|
310
|
-
objectType: 'conversation'
|
|
326
|
+
objectType: 'conversation',
|
|
311
327
|
},
|
|
312
|
-
verb: 'delete'
|
|
328
|
+
verb: 'delete',
|
|
313
329
|
};
|
|
314
330
|
|
|
331
|
+
// Is not required for the request to be accepted, but follows specification.
|
|
332
|
+
if (recipientId) {
|
|
333
|
+
deleteReactionPayload.recipients = {items: [{id: recipientId, objectType: 'person'}]};
|
|
334
|
+
}
|
|
335
|
+
|
|
315
336
|
return this.sendReaction(conversation, deleteReactionPayload);
|
|
316
337
|
},
|
|
317
338
|
|
|
@@ -320,34 +341,38 @@ const Conversation = WebexPlugin.extend({
|
|
|
320
341
|
* @param {Object} conversation
|
|
321
342
|
* @param {Object} displayName must be 'celebrate', 'heart', 'thumbsup', 'smiley', 'haha', 'confused', 'sad'
|
|
322
343
|
* @param {Object} activity activity object from convo we are reacting to
|
|
344
|
+
* @param {String} recipientId,
|
|
323
345
|
* @returns {Promise<Activity>}
|
|
324
346
|
*/
|
|
325
|
-
addReaction(conversation, displayName, activity) {
|
|
347
|
+
addReaction(conversation, displayName, activity, recipientId) {
|
|
326
348
|
return this.createReactionHmac(displayName, activity).then((hmac) => {
|
|
327
349
|
const addReactionPayload = {
|
|
328
350
|
actor: {objectType: 'person', id: this.webex.internal.device.userId},
|
|
329
351
|
target: {
|
|
330
352
|
id: conversation.id,
|
|
331
|
-
objectType: 'conversation'
|
|
353
|
+
objectType: 'conversation',
|
|
332
354
|
},
|
|
333
355
|
verb: 'add',
|
|
334
356
|
objectType: 'activity',
|
|
335
357
|
parent: {
|
|
336
358
|
type: 'reaction',
|
|
337
|
-
id: activity.id
|
|
359
|
+
id: activity.id,
|
|
338
360
|
},
|
|
339
361
|
object: {
|
|
340
362
|
objectType: 'reaction2',
|
|
341
363
|
displayName,
|
|
342
|
-
hmac
|
|
343
|
-
}
|
|
364
|
+
hmac,
|
|
365
|
+
},
|
|
344
366
|
};
|
|
345
367
|
|
|
368
|
+
if (recipientId) {
|
|
369
|
+
addReactionPayload.recipients = {items: [{id: recipientId, objectType: 'person'}]};
|
|
370
|
+
}
|
|
371
|
+
|
|
346
372
|
return this.sendReaction(conversation, addReactionPayload);
|
|
347
373
|
});
|
|
348
374
|
},
|
|
349
375
|
|
|
350
|
-
|
|
351
376
|
/**
|
|
352
377
|
* delete content
|
|
353
378
|
* @param {Object} conversation
|
|
@@ -357,7 +382,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
357
382
|
*/
|
|
358
383
|
delete(conversation, object, activity) {
|
|
359
384
|
const url = this.getConvoUrl(conversation);
|
|
360
|
-
const convoWithUrl =
|
|
385
|
+
const convoWithUrl = {...conversation, url};
|
|
361
386
|
|
|
362
387
|
if (!isObject(object)) {
|
|
363
388
|
return Promise.reject(new Error('`object` must be an object'));
|
|
@@ -375,12 +400,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
375
400
|
request.target.kmsResourceObjectUrl = object.object.kmsResourceObjectUrl;
|
|
376
401
|
request.kmsMessage = {
|
|
377
402
|
method: 'delete',
|
|
378
|
-
uri: `<KRO>/authorizations?${querystring.stringify({
|
|
403
|
+
uri: `<KRO>/authorizations?${querystring.stringify({
|
|
404
|
+
authId: convoWithUrl.kmsResourceObjectUrl,
|
|
405
|
+
})}`,
|
|
379
406
|
};
|
|
380
407
|
}
|
|
381
408
|
|
|
382
|
-
return this.prepare(activity, request)
|
|
383
|
-
.then((a) => this.submit(a));
|
|
409
|
+
return this.prepare(activity, request).then((a) => this.submit(a));
|
|
384
410
|
},
|
|
385
411
|
|
|
386
412
|
/**
|
|
@@ -399,12 +425,8 @@ const Conversation = WebexPlugin.extend({
|
|
|
399
425
|
let promise;
|
|
400
426
|
|
|
401
427
|
if (isEncrypted) {
|
|
402
|
-
promise = this.webex.internal.encryption.download(item.scr, item.options);
|
|
403
|
-
}
|
|
404
|
-
else if (item.scr && item.scr.loc) {
|
|
405
|
-
promise = this._downloadUnencryptedFile(item.scr.loc, options);
|
|
406
|
-
}
|
|
407
|
-
else {
|
|
428
|
+
promise = this.webex.internal.encryption.download(item.url, item.scr, item.options);
|
|
429
|
+
} else {
|
|
408
430
|
promise = this._downloadUnencryptedFile(item.url, options);
|
|
409
431
|
}
|
|
410
432
|
|
|
@@ -446,11 +468,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
446
468
|
_downloadUnencryptedFile(uri, options = {}) {
|
|
447
469
|
Object.assign(options, {
|
|
448
470
|
uri,
|
|
449
|
-
responseType: 'buffer'
|
|
471
|
+
responseType: 'buffer',
|
|
450
472
|
});
|
|
451
473
|
|
|
452
|
-
const promise = this.request(options)
|
|
453
|
-
.then((res) => res.body);
|
|
474
|
+
const promise = this.request(options).then((res) => res.body);
|
|
454
475
|
|
|
455
476
|
proxyEvents(options.download, promise);
|
|
456
477
|
|
|
@@ -469,7 +490,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
469
490
|
const activity = {
|
|
470
491
|
actor,
|
|
471
492
|
objectType: 'activity',
|
|
472
|
-
verb
|
|
493
|
+
verb,
|
|
473
494
|
};
|
|
474
495
|
|
|
475
496
|
if (!actor) {
|
|
@@ -479,7 +500,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
479
500
|
if (isString(actor)) {
|
|
480
501
|
activity.actor = {
|
|
481
502
|
objectType: 'person',
|
|
482
|
-
id: actor
|
|
503
|
+
id: actor,
|
|
483
504
|
};
|
|
484
505
|
}
|
|
485
506
|
|
|
@@ -495,20 +516,20 @@ const Conversation = WebexPlugin.extend({
|
|
|
495
516
|
},
|
|
496
517
|
|
|
497
518
|
/**
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
519
|
+
* Gets an array of activities with an array of activity URLS
|
|
520
|
+
* @param {Array} activityUrls
|
|
521
|
+
* @param {Object} options
|
|
522
|
+
* @param {String} options.cluster cluster where the activities are located
|
|
523
|
+
* @param {String} options.url base convo url where the activities are located
|
|
524
|
+
* @returns {Promise<Object>} Resolves with the activities
|
|
525
|
+
*/
|
|
505
526
|
bulkActivitiesFetch(activityUrls, options = {}) {
|
|
506
|
-
let cluster
|
|
527
|
+
let cluster;
|
|
528
|
+
let url;
|
|
507
529
|
|
|
508
530
|
if (typeof options === 'string') {
|
|
509
531
|
cluster = options;
|
|
510
|
-
}
|
|
511
|
-
else {
|
|
532
|
+
} else {
|
|
512
533
|
({cluster, url} = options);
|
|
513
534
|
}
|
|
514
535
|
|
|
@@ -516,45 +537,42 @@ const Conversation = WebexPlugin.extend({
|
|
|
516
537
|
const params = {
|
|
517
538
|
method: 'POST',
|
|
518
539
|
body: {
|
|
519
|
-
activityUrls
|
|
520
|
-
}
|
|
540
|
+
activityUrls,
|
|
541
|
+
},
|
|
521
542
|
};
|
|
522
543
|
|
|
523
544
|
if (url) {
|
|
524
545
|
const uri = `${url}/${resource}`;
|
|
525
546
|
|
|
526
547
|
Object.assign(params, {
|
|
527
|
-
uri
|
|
548
|
+
uri,
|
|
528
549
|
});
|
|
529
|
-
}
|
|
530
|
-
else if (cluster) {
|
|
550
|
+
} else if (cluster) {
|
|
531
551
|
const uri = `${this.getUrlFromClusterId({cluster})}/${resource}`;
|
|
532
552
|
|
|
533
553
|
Object.assign(params, {
|
|
534
|
-
uri
|
|
554
|
+
uri,
|
|
535
555
|
});
|
|
536
|
-
}
|
|
537
|
-
else {
|
|
556
|
+
} else {
|
|
538
557
|
Object.assign(params, {
|
|
539
558
|
api: 'conversation',
|
|
540
|
-
resource
|
|
559
|
+
resource,
|
|
541
560
|
});
|
|
542
561
|
}
|
|
543
562
|
|
|
544
|
-
return this.webex.request(params)
|
|
545
|
-
|
|
546
|
-
const activitiesArr = [];
|
|
563
|
+
return this.webex.request(params).then((res) => {
|
|
564
|
+
const activitiesArr = [];
|
|
547
565
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
566
|
+
if (res.body.multistatus) {
|
|
567
|
+
res.body.multistatus.forEach((statusData) => {
|
|
568
|
+
if (statusData.status === '200' && statusData.data && statusData.data.activity) {
|
|
569
|
+
activitiesArr.push(statusData.data.activity);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
555
573
|
|
|
556
|
-
|
|
557
|
-
|
|
574
|
+
return activitiesArr;
|
|
575
|
+
});
|
|
558
576
|
},
|
|
559
577
|
|
|
560
578
|
/**
|
|
@@ -572,27 +590,27 @@ const Conversation = WebexPlugin.extend({
|
|
|
572
590
|
|
|
573
591
|
try {
|
|
574
592
|
uri = !user ? this.getConvoUrl(conversation) : '';
|
|
575
|
-
}
|
|
576
|
-
catch (err) {
|
|
593
|
+
} catch (err) {
|
|
577
594
|
return Promise.reject(Error(err));
|
|
578
595
|
}
|
|
579
596
|
|
|
580
597
|
const params = {
|
|
581
|
-
qs:
|
|
598
|
+
qs: {
|
|
582
599
|
uuidEntryFormat: true,
|
|
583
600
|
personRefresh: true,
|
|
584
601
|
activitiesLimit: 0,
|
|
585
602
|
includeConvWithDeletedUserUUID: false,
|
|
586
|
-
includeParticipants: false
|
|
587
|
-
|
|
588
|
-
|
|
603
|
+
includeParticipants: false,
|
|
604
|
+
...omit(options, 'id', 'user', 'url'),
|
|
605
|
+
},
|
|
606
|
+
disableTransform: options.disableTransform,
|
|
589
607
|
};
|
|
590
608
|
|
|
591
609
|
// Default behavior is to set includeParticipants=false,
|
|
592
610
|
// which makes the payload lighter by removing participant info.
|
|
593
611
|
// If the caller explicitly sets the participantAckFilter or
|
|
594
612
|
// participantsLimit, we don't want that default setting.
|
|
595
|
-
if (
|
|
613
|
+
if ('participantAckFilter' in options || 'participantsLimit' in options) {
|
|
596
614
|
delete params.qs.includeParticipants;
|
|
597
615
|
}
|
|
598
616
|
|
|
@@ -601,21 +619,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
601
619
|
if (userId) {
|
|
602
620
|
Object.assign(params, {
|
|
603
621
|
service: 'conversation',
|
|
604
|
-
resource: `conversations/user/${userId}
|
|
622
|
+
resource: `conversations/user/${userId}`,
|
|
605
623
|
});
|
|
606
|
-
}
|
|
607
|
-
else {
|
|
624
|
+
} else {
|
|
608
625
|
params.uri = uri;
|
|
609
626
|
}
|
|
610
627
|
|
|
611
628
|
return this.request(params);
|
|
612
629
|
})
|
|
613
|
-
.then(
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
630
|
+
.then(
|
|
631
|
+
tap(({body}) => {
|
|
632
|
+
const {id, url} = body;
|
|
633
|
+
|
|
634
|
+
this._recordUUIDs(body);
|
|
635
|
+
idToUrl.set(id, url);
|
|
636
|
+
})
|
|
637
|
+
)
|
|
619
638
|
.then((res) => res.body);
|
|
620
639
|
},
|
|
621
640
|
|
|
@@ -631,10 +650,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
631
650
|
* @returns {Promise<Activity>}
|
|
632
651
|
*/
|
|
633
652
|
leave(conversation, participant, activity) {
|
|
634
|
-
const convoWithUrl =
|
|
635
|
-
Object.assign(
|
|
636
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
637
|
-
);
|
|
653
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
638
654
|
|
|
639
655
|
return Promise.resolve()
|
|
640
656
|
.then(() => {
|
|
@@ -642,19 +658,20 @@ const Conversation = WebexPlugin.extend({
|
|
|
642
658
|
participant = this.webex.internal.device.userId;
|
|
643
659
|
}
|
|
644
660
|
|
|
645
|
-
return this.webex.internal.user.asUUID(participant)
|
|
646
|
-
|
|
661
|
+
return this.webex.internal.user.asUUID(participant).then((id) =>
|
|
662
|
+
this.prepare(activity, {
|
|
647
663
|
verb: 'leave',
|
|
648
664
|
target: this.prepareConversation(convoWithUrl),
|
|
649
665
|
object: {
|
|
650
666
|
id,
|
|
651
|
-
objectType: 'person'
|
|
667
|
+
objectType: 'person',
|
|
652
668
|
},
|
|
653
669
|
kmsMessage: {
|
|
654
670
|
method: 'delete',
|
|
655
|
-
uri: `<KRO>/authorizations?${querystring.stringify({authId: id})}
|
|
656
|
-
}
|
|
657
|
-
})
|
|
671
|
+
uri: `<KRO>/authorizations?${querystring.stringify({authId: id})}`,
|
|
672
|
+
},
|
|
673
|
+
})
|
|
674
|
+
);
|
|
658
675
|
})
|
|
659
676
|
.then((a) => this.submit(a));
|
|
660
677
|
},
|
|
@@ -677,15 +694,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
677
694
|
resource: options.summary ? 'conversationsSummary' : 'conversations',
|
|
678
695
|
qs: omit(options, ['deferDecrypt', 'summary']),
|
|
679
696
|
deferDecrypt: options.deferDecrypt,
|
|
680
|
-
limit: getConvoLimit(options)
|
|
681
|
-
})
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
697
|
+
limit: getConvoLimit(options),
|
|
698
|
+
}).then((results) => {
|
|
699
|
+
for (const convo of results) {
|
|
700
|
+
idToUrl.set(convo.id, convo.url);
|
|
701
|
+
}
|
|
686
702
|
|
|
687
|
-
|
|
688
|
-
|
|
703
|
+
return results;
|
|
704
|
+
});
|
|
689
705
|
},
|
|
690
706
|
|
|
691
707
|
/**
|
|
@@ -709,42 +725,40 @@ const Conversation = WebexPlugin.extend({
|
|
|
709
725
|
|
|
710
726
|
// Go get the next page of results
|
|
711
727
|
return this.request({
|
|
712
|
-
url: options.page.links.next
|
|
728
|
+
url: options.page.links.next,
|
|
713
729
|
}).then((res) => ({page: new Page(res, this.webex)}));
|
|
714
730
|
}
|
|
715
731
|
|
|
716
732
|
// No page - so this is the first request to kick off the pagination process
|
|
717
|
-
const queryOptions =
|
|
733
|
+
const queryOptions = {
|
|
718
734
|
personRefresh: true,
|
|
719
735
|
uuidEntryFormat: true,
|
|
720
736
|
activitiesLimit: 0,
|
|
721
737
|
participantsLimit: 0,
|
|
722
|
-
paginate: true
|
|
723
|
-
|
|
738
|
+
paginate: true,
|
|
739
|
+
...omit(options, ['deferDecrypt', 'url']),
|
|
740
|
+
};
|
|
724
741
|
|
|
725
742
|
const reqOptions = {
|
|
726
743
|
qs: queryOptions,
|
|
727
744
|
deferDecrypt: options.deferDecrypt,
|
|
728
|
-
limit: getConvoLimit(options)
|
|
745
|
+
limit: getConvoLimit(options),
|
|
729
746
|
};
|
|
730
747
|
|
|
731
748
|
// if options.url is present we likely received one or more additional urls due to federation. In this case
|
|
732
749
|
// we need to initialize pagination against that url instead of the default home cluster
|
|
733
750
|
if (options.url) {
|
|
734
751
|
reqOptions.uri = `${options.url}/conversations`;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
752
|
+
} else {
|
|
737
753
|
reqOptions.service = 'conversation';
|
|
738
754
|
reqOptions.resource = 'conversations';
|
|
739
755
|
}
|
|
740
756
|
|
|
741
|
-
|
|
742
757
|
return this.request(reqOptions).then((res) => {
|
|
743
758
|
const response = {
|
|
744
|
-
page: new Page(res, this.webex)
|
|
759
|
+
page: new Page(res, this.webex),
|
|
745
760
|
};
|
|
746
761
|
|
|
747
|
-
|
|
748
762
|
if (res.body && res.body.additionalUrls) {
|
|
749
763
|
response.additionalUrls = res.body.additionalUrls;
|
|
750
764
|
}
|
|
@@ -764,15 +778,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
764
778
|
service: 'conversation',
|
|
765
779
|
resource: 'conversations/left',
|
|
766
780
|
qs: options,
|
|
767
|
-
limit: getConvoLimit(options)
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
781
|
+
limit: getConvoLimit(options),
|
|
782
|
+
}).then((results) => {
|
|
783
|
+
for (const convo of results) {
|
|
784
|
+
idToUrl.set(convo.id, convo.url);
|
|
785
|
+
}
|
|
773
786
|
|
|
774
|
-
|
|
775
|
-
|
|
787
|
+
return results;
|
|
788
|
+
});
|
|
776
789
|
},
|
|
777
790
|
|
|
778
791
|
/**
|
|
@@ -807,7 +820,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
807
820
|
const params = {
|
|
808
821
|
method: 'GET',
|
|
809
822
|
url: `${conversationUrl}/parents`,
|
|
810
|
-
qs: query
|
|
823
|
+
qs: query,
|
|
811
824
|
};
|
|
812
825
|
|
|
813
826
|
const response = await this.request(params);
|
|
@@ -827,7 +840,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
827
840
|
const {conversationUrl, activityParentId, query} = options;
|
|
828
841
|
const {activityType} = query;
|
|
829
842
|
|
|
830
|
-
const initialResponse = await this.listChildActivitiesByParentId(
|
|
843
|
+
const initialResponse = await this.listChildActivitiesByParentId(
|
|
844
|
+
conversationUrl,
|
|
845
|
+
activityParentId,
|
|
846
|
+
activityType,
|
|
847
|
+
query
|
|
848
|
+
);
|
|
831
849
|
|
|
832
850
|
let page = new Page(initialResponse, this.webex);
|
|
833
851
|
|
|
@@ -861,12 +879,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
861
879
|
async listChildActivitiesByParentId(conversationUrl, activityParentId, activityType, query = {}) {
|
|
862
880
|
const finalQuery = {
|
|
863
881
|
...query,
|
|
864
|
-
activityType
|
|
882
|
+
activityType,
|
|
865
883
|
};
|
|
866
884
|
const params = {
|
|
867
885
|
method: 'GET',
|
|
868
886
|
url: `${conversationUrl}/parents/${activityParentId}`,
|
|
869
|
-
qs: finalQuery
|
|
887
|
+
qs: finalQuery,
|
|
870
888
|
};
|
|
871
889
|
|
|
872
890
|
return this.request(params);
|
|
@@ -883,10 +901,14 @@ const Conversation = WebexPlugin.extend({
|
|
|
883
901
|
const {body} = await this.request({
|
|
884
902
|
method: 'GET',
|
|
885
903
|
url: `${conversationUrl}/activities/${activityParentId}`,
|
|
886
|
-
qs: query
|
|
904
|
+
qs: query,
|
|
887
905
|
});
|
|
888
906
|
|
|
889
|
-
const reactionObjects = body.children
|
|
907
|
+
const reactionObjects = body.children
|
|
908
|
+
? body.children.filter(
|
|
909
|
+
(child) => child.type === 'reactionSelfSummary' || child.type === 'reactionSummary'
|
|
910
|
+
)
|
|
911
|
+
: [];
|
|
890
912
|
|
|
891
913
|
return reactionObjects;
|
|
892
914
|
},
|
|
@@ -900,7 +922,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
900
922
|
return this._list({
|
|
901
923
|
service: 'conversation',
|
|
902
924
|
resource: 'mentions',
|
|
903
|
-
qs: omit(options, 'mentions')
|
|
925
|
+
qs: omit(options, 'mentions'),
|
|
904
926
|
});
|
|
905
927
|
},
|
|
906
928
|
|
|
@@ -911,9 +933,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
911
933
|
* @returns {Promise} Resolves with the created activity
|
|
912
934
|
*/
|
|
913
935
|
muteMentions(conversation, activity) {
|
|
914
|
-
return this.tag(
|
|
915
|
-
|
|
916
|
-
|
|
936
|
+
return this.tag(
|
|
937
|
+
conversation,
|
|
938
|
+
{
|
|
939
|
+
tags: ['MENTION_NOTIFICATIONS_OFF'],
|
|
940
|
+
},
|
|
941
|
+
activity
|
|
942
|
+
);
|
|
917
943
|
},
|
|
918
944
|
|
|
919
945
|
/**
|
|
@@ -923,9 +949,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
923
949
|
* @returns {Promise} Resolves with the created activity
|
|
924
950
|
*/
|
|
925
951
|
muteMessages(conversation, activity) {
|
|
926
|
-
return this.tag(
|
|
927
|
-
|
|
928
|
-
|
|
952
|
+
return this.tag(
|
|
953
|
+
conversation,
|
|
954
|
+
{
|
|
955
|
+
tags: ['MESSAGE_NOTIFICATIONS_OFF'],
|
|
956
|
+
},
|
|
957
|
+
activity
|
|
958
|
+
);
|
|
929
959
|
},
|
|
930
960
|
|
|
931
961
|
/**
|
|
@@ -935,9 +965,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
935
965
|
* @returns {Promise} Resolves with the created activity
|
|
936
966
|
*/
|
|
937
967
|
ignore(conversation, activity) {
|
|
938
|
-
return this.tag(
|
|
939
|
-
|
|
940
|
-
|
|
968
|
+
return this.tag(
|
|
969
|
+
conversation,
|
|
970
|
+
{
|
|
971
|
+
tags: ['IGNORED'],
|
|
972
|
+
},
|
|
973
|
+
activity
|
|
974
|
+
);
|
|
941
975
|
},
|
|
942
976
|
|
|
943
977
|
/**
|
|
@@ -948,22 +982,18 @@ const Conversation = WebexPlugin.extend({
|
|
|
948
982
|
* @returns {Promise}
|
|
949
983
|
*/
|
|
950
984
|
cardAction(conversation, inputs, parentActivity, activity = {}) {
|
|
951
|
-
const convoWithUrl =
|
|
952
|
-
Object.assign(
|
|
953
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
954
|
-
);
|
|
985
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
955
986
|
|
|
956
987
|
activity.parent = {
|
|
957
988
|
id: parentActivity.id,
|
|
958
|
-
type: 'cardAction'
|
|
989
|
+
type: 'cardAction',
|
|
959
990
|
};
|
|
960
991
|
|
|
961
992
|
return this.prepare(activity, {
|
|
962
993
|
verb: 'cardAction',
|
|
963
994
|
target: this.prepareConversation(convoWithUrl),
|
|
964
|
-
object:
|
|
965
|
-
})
|
|
966
|
-
.then((a) => this.submit(a));
|
|
995
|
+
object: {objectType: 'submit', ...inputs},
|
|
996
|
+
}).then((a) => this.submit(a));
|
|
967
997
|
},
|
|
968
998
|
|
|
969
999
|
/**
|
|
@@ -977,105 +1007,126 @@ const Conversation = WebexPlugin.extend({
|
|
|
977
1007
|
* @returns {Promise<Activity>}
|
|
978
1008
|
*/
|
|
979
1009
|
post(conversation, message, activity) {
|
|
980
|
-
const convoWithUrl =
|
|
981
|
-
Object.assign(
|
|
982
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
983
|
-
);
|
|
1010
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
984
1011
|
|
|
985
1012
|
if (isString(message)) {
|
|
986
1013
|
message = {
|
|
987
|
-
displayName: message
|
|
1014
|
+
displayName: message,
|
|
988
1015
|
};
|
|
989
1016
|
}
|
|
990
1017
|
|
|
991
1018
|
return this.prepare(activity, {
|
|
992
1019
|
verb: 'post',
|
|
993
1020
|
target: this.prepareConversation(convoWithUrl),
|
|
994
|
-
object:
|
|
995
|
-
})
|
|
996
|
-
.then((a) => this.submit(a));
|
|
1021
|
+
object: {objectType: 'comment', ...message},
|
|
1022
|
+
}).then((a) => this.submit(a));
|
|
997
1023
|
},
|
|
998
1024
|
|
|
999
1025
|
prepareConversation(conversation) {
|
|
1000
|
-
return defaults(
|
|
1001
|
-
|
|
1002
|
-
|
|
1026
|
+
return defaults(
|
|
1027
|
+
pick(
|
|
1028
|
+
conversation,
|
|
1029
|
+
'id',
|
|
1030
|
+
'url',
|
|
1031
|
+
'objectType',
|
|
1032
|
+
'defaultActivityEncryptionKeyUrl',
|
|
1033
|
+
'kmsResourceObjectUrl'
|
|
1034
|
+
),
|
|
1035
|
+
{
|
|
1036
|
+
objectType: 'conversation',
|
|
1037
|
+
}
|
|
1038
|
+
);
|
|
1003
1039
|
},
|
|
1004
1040
|
|
|
1005
1041
|
prepare(activity, params) {
|
|
1006
1042
|
params = params || {};
|
|
1007
1043
|
activity = activity || {};
|
|
1008
1044
|
|
|
1009
|
-
return Promise.resolve(activity.prepare ? activity.prepare(params) : activity)
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
});
|
|
1045
|
+
return Promise.resolve(activity.prepare ? activity.prepare(params) : activity).then((act) => {
|
|
1046
|
+
defaults(act, {
|
|
1047
|
+
verb: params.verb,
|
|
1048
|
+
kmsMessage: params.kmsMessage,
|
|
1049
|
+
objectType: 'activity',
|
|
1050
|
+
clientTempId: uuid.v4(),
|
|
1051
|
+
actor: this.webex.internal.device.userId,
|
|
1052
|
+
});
|
|
1018
1053
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1054
|
+
// Workaround because parent is a reserved props in Ampersand
|
|
1055
|
+
if (
|
|
1056
|
+
(activity.parentActivityId && activity.activityType) ||
|
|
1057
|
+
(activity.parent && activity.parent.id && activity.parent.type)
|
|
1058
|
+
) {
|
|
1059
|
+
act.parent = {
|
|
1060
|
+
id: activity.parentActivityId || activity.parent.id,
|
|
1061
|
+
type: activity.activityType || activity.parent.type,
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1026
1064
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
id: act.actor
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1065
|
+
if (activity.recipients) {
|
|
1066
|
+
act.recipients = activity.recipients;
|
|
1067
|
+
}
|
|
1033
1068
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1069
|
+
if (isString(act.actor)) {
|
|
1070
|
+
act.actor = {
|
|
1071
|
+
objectType: 'person',
|
|
1072
|
+
id: act.actor,
|
|
1073
|
+
};
|
|
1074
|
+
}
|
|
1040
1075
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1076
|
+
['actor', 'object'].forEach((key) => {
|
|
1077
|
+
if (params[key]) {
|
|
1078
|
+
act[key] = act[key] || {};
|
|
1079
|
+
defaults(act[key], params[key]);
|
|
1045
1080
|
}
|
|
1081
|
+
});
|
|
1046
1082
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
throw new Error(`\`act.${key}.objectType\` must be defined`);
|
|
1058
|
-
}
|
|
1083
|
+
if (params.target) {
|
|
1084
|
+
merge(act, {
|
|
1085
|
+
target: pick(
|
|
1086
|
+
params.target,
|
|
1087
|
+
'id',
|
|
1088
|
+
'url',
|
|
1089
|
+
'objectType',
|
|
1090
|
+
'kmsResourceObjectUrl',
|
|
1091
|
+
'defaultActivityEncryptionKeyUrl'
|
|
1092
|
+
),
|
|
1059
1093
|
});
|
|
1094
|
+
}
|
|
1060
1095
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1096
|
+
['object', 'target'].forEach((key) => {
|
|
1097
|
+
if (act[key] && act[key].url && !act[key].id) {
|
|
1098
|
+
act[key].id = act[key].url.split('/').pop();
|
|
1063
1099
|
}
|
|
1100
|
+
});
|
|
1064
1101
|
|
|
1065
|
-
|
|
1102
|
+
['actor', 'object', 'target'].forEach((key) => {
|
|
1103
|
+
if (act[key] && !act[key].objectType) {
|
|
1104
|
+
// Reminder: throwing here because it's the only way to get out of
|
|
1105
|
+
// this loop in event of an error.
|
|
1106
|
+
throw new Error(`\`act.${key}.objectType\` must be defined`);
|
|
1107
|
+
}
|
|
1066
1108
|
});
|
|
1109
|
+
|
|
1110
|
+
if (act.object && act.object.content && !act.object.displayName) {
|
|
1111
|
+
return Promise.reject(
|
|
1112
|
+
new Error('Cannot submit activity object with `content` but no `displayName`')
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
return act;
|
|
1117
|
+
});
|
|
1067
1118
|
},
|
|
1068
1119
|
|
|
1069
1120
|
/**
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1121
|
+
* Get a subset of threads for a user.
|
|
1122
|
+
* @param {Object} options
|
|
1123
|
+
* @returns {Promise<Array<Activity>>}
|
|
1124
|
+
*/
|
|
1074
1125
|
async listThreads(options) {
|
|
1075
1126
|
return this._list({
|
|
1076
1127
|
service: 'conversation',
|
|
1077
1128
|
resource: 'threads',
|
|
1078
|
-
qs: omit(options, 'showAllTypes')
|
|
1129
|
+
qs: omit(options, 'showAllTypes'),
|
|
1079
1130
|
});
|
|
1080
1131
|
},
|
|
1081
1132
|
|
|
@@ -1085,8 +1136,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1085
1136
|
* @returns {Promise}
|
|
1086
1137
|
*/
|
|
1087
1138
|
processActivityEvent(event) {
|
|
1088
|
-
return this.webex.transform('inbound', event)
|
|
1089
|
-
.then(() => event);
|
|
1139
|
+
return this.webex.transform('inbound', event).then(() => event);
|
|
1090
1140
|
},
|
|
1091
1141
|
|
|
1092
1142
|
/**
|
|
@@ -1095,8 +1145,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1095
1145
|
* @returns {Promise}
|
|
1096
1146
|
*/
|
|
1097
1147
|
processInmeetingchatEvent(event) {
|
|
1098
|
-
return this.webex.transform('inbound', event)
|
|
1099
|
-
.then(() => event);
|
|
1148
|
+
return this.webex.transform('inbound', event).then(() => event);
|
|
1100
1149
|
},
|
|
1101
1150
|
|
|
1102
1151
|
/**
|
|
@@ -1106,14 +1155,18 @@ const Conversation = WebexPlugin.extend({
|
|
|
1106
1155
|
* @returns {Promise} Resolves with the created activity
|
|
1107
1156
|
*/
|
|
1108
1157
|
removeAllMuteTags(conversation, activity) {
|
|
1109
|
-
return this.untag(
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1158
|
+
return this.untag(
|
|
1159
|
+
conversation,
|
|
1160
|
+
{
|
|
1161
|
+
tags: [
|
|
1162
|
+
'MENTION_NOTIFICATIONS_OFF',
|
|
1163
|
+
'MENTION_NOTIFICATIONS_ON',
|
|
1164
|
+
'MESSAGE_NOTIFICATIONS_OFF',
|
|
1165
|
+
'MESSAGE_NOTIFICATIONS_ON',
|
|
1166
|
+
],
|
|
1167
|
+
},
|
|
1168
|
+
activity
|
|
1169
|
+
);
|
|
1117
1170
|
},
|
|
1118
1171
|
|
|
1119
1172
|
/**
|
|
@@ -1144,10 +1197,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1144
1197
|
return Promise.reject(new Error('Room avatars must be less than 1MB'));
|
|
1145
1198
|
}
|
|
1146
1199
|
|
|
1147
|
-
const convoWithUrl =
|
|
1148
|
-
Object.assign(
|
|
1149
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1150
|
-
);
|
|
1200
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1151
1201
|
|
|
1152
1202
|
return Promise.resolve()
|
|
1153
1203
|
.then(() => {
|
|
@@ -1157,7 +1207,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1157
1207
|
activity.add(avatar, uploadOptions);
|
|
1158
1208
|
|
|
1159
1209
|
return this.prepare(activity, {
|
|
1160
|
-
target: this.prepareConversation(convoWithUrl)
|
|
1210
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1161
1211
|
});
|
|
1162
1212
|
})
|
|
1163
1213
|
.then((a) => {
|
|
@@ -1179,9 +1229,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1179
1229
|
* @param {Object} conversations If this is a team, the list of conversations in the team
|
|
1180
1230
|
* @returns {String} url for the specific convo
|
|
1181
1231
|
*/
|
|
1182
|
-
getConvoUrl({
|
|
1183
|
-
id, url, cluster, conversations, generalConversationUuid
|
|
1184
|
-
}) {
|
|
1232
|
+
getConvoUrl({id, url, cluster, conversations, generalConversationUuid}) {
|
|
1185
1233
|
if (generalConversationUuid) {
|
|
1186
1234
|
// This is a Team
|
|
1187
1235
|
// Because Convo doesn't have an endpoint for the team URL
|
|
@@ -1201,9 +1249,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1201
1249
|
if (cluster) {
|
|
1202
1250
|
return this.getUrlFromClusterId({cluster, id});
|
|
1203
1251
|
}
|
|
1204
|
-
this.logger.warn(
|
|
1205
|
-
'You should be using the `url` instead of the `id` property'
|
|
1206
|
-
);
|
|
1252
|
+
this.logger.warn('You should be using the `url` instead of the `id` property');
|
|
1207
1253
|
const relatedUrl = idToUrl.get(id);
|
|
1208
1254
|
|
|
1209
1255
|
if (!relatedUrl) {
|
|
@@ -1228,11 +1274,8 @@ const Conversation = WebexPlugin.extend({
|
|
|
1228
1274
|
if (!conversation.id) {
|
|
1229
1275
|
if (conversation.url) {
|
|
1230
1276
|
conversation.id = conversation.url.split('/').pop();
|
|
1231
|
-
}
|
|
1232
|
-
|
|
1233
|
-
return Promise.reject(
|
|
1234
|
-
new Error('conversation: could not identify conversation')
|
|
1235
|
-
);
|
|
1277
|
+
} else {
|
|
1278
|
+
return Promise.reject(new Error('conversation: could not identify conversation'));
|
|
1236
1279
|
}
|
|
1237
1280
|
}
|
|
1238
1281
|
|
|
@@ -1240,8 +1283,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1240
1283
|
|
|
1241
1284
|
if (options.typing) {
|
|
1242
1285
|
eventType = 'status.start_typing';
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1286
|
+
} else {
|
|
1245
1287
|
eventType = 'status.stop_typing';
|
|
1246
1288
|
}
|
|
1247
1289
|
|
|
@@ -1251,9 +1293,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
1251
1293
|
method: 'POST',
|
|
1252
1294
|
body: {
|
|
1253
1295
|
conversationId: conversation.id,
|
|
1254
|
-
eventType
|
|
1296
|
+
eventType,
|
|
1255
1297
|
},
|
|
1256
|
-
url: `${url}/${resource}
|
|
1298
|
+
url: `${url}/${resource}`,
|
|
1257
1299
|
};
|
|
1258
1300
|
|
|
1259
1301
|
return this.request(params);
|
|
@@ -1269,27 +1311,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
1269
1311
|
if (isArray(activity)) {
|
|
1270
1312
|
activity = {
|
|
1271
1313
|
object: {
|
|
1272
|
-
files: activity
|
|
1273
|
-
}
|
|
1314
|
+
files: activity,
|
|
1315
|
+
},
|
|
1274
1316
|
};
|
|
1275
1317
|
}
|
|
1276
1318
|
|
|
1277
|
-
const convoWithUrl =
|
|
1278
|
-
Object.assign(
|
|
1279
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1280
|
-
);
|
|
1319
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1281
1320
|
|
|
1282
1321
|
if (!(activity instanceof ShareActivity)) {
|
|
1283
1322
|
activity = ShareActivity.create(convoWithUrl, activity, this.webex);
|
|
1284
1323
|
}
|
|
1285
1324
|
|
|
1286
1325
|
return this.prepare(activity, {
|
|
1287
|
-
target: this.prepareConversation(convoWithUrl)
|
|
1288
|
-
})
|
|
1289
|
-
.then((a) => this.submit(a));
|
|
1326
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1327
|
+
}).then((a) => this.submit(a));
|
|
1290
1328
|
},
|
|
1291
1329
|
|
|
1292
|
-
|
|
1293
1330
|
/**
|
|
1294
1331
|
* Submits an activity to the conversation service
|
|
1295
1332
|
* @param {Object} activity
|
|
@@ -1303,15 +1340,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
1303
1340
|
method: 'POST',
|
|
1304
1341
|
body: activity,
|
|
1305
1342
|
qs: {
|
|
1306
|
-
personRefresh: true
|
|
1343
|
+
personRefresh: true,
|
|
1307
1344
|
},
|
|
1308
|
-
url: `${url}/${resource}
|
|
1345
|
+
url: `${url}/${resource}`,
|
|
1309
1346
|
};
|
|
1310
1347
|
|
|
1311
1348
|
if (activity.verb === 'share') {
|
|
1312
1349
|
Object.assign(params.qs, {
|
|
1313
1350
|
transcode: true,
|
|
1314
|
-
async: false
|
|
1351
|
+
async: false,
|
|
1315
1352
|
});
|
|
1316
1353
|
}
|
|
1317
1354
|
/**
|
|
@@ -1323,7 +1360,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1323
1360
|
const customActivityCopy = (value) => {
|
|
1324
1361
|
const {files} = params.body.object;
|
|
1325
1362
|
|
|
1326
|
-
if (
|
|
1363
|
+
if (
|
|
1364
|
+
files &&
|
|
1365
|
+
value &&
|
|
1366
|
+
files.items.length > 0 &&
|
|
1367
|
+
value.constructor === files.items[0].scr.constructor
|
|
1368
|
+
) {
|
|
1327
1369
|
const copySrc = cloneDeep(value);
|
|
1328
1370
|
|
|
1329
1371
|
copySrc.toJWE = value.toJWE;
|
|
@@ -1344,22 +1386,24 @@ const Conversation = WebexPlugin.extend({
|
|
|
1344
1386
|
if (error.body && error.body.errorCode === KEY_ROTATION_REQUIRED) {
|
|
1345
1387
|
cloneActivity.body.target.defaultActivityEncryptionKeyUrl = null;
|
|
1346
1388
|
this.request(cloneActivity);
|
|
1347
|
-
}
|
|
1348
|
-
else if (
|
|
1389
|
+
} else if (
|
|
1349
1390
|
error.body &&
|
|
1350
|
-
|
|
1391
|
+
(error.body.errorCode === KEY_ALREADY_ROTATED ||
|
|
1392
|
+
error.body.errorCode === ENCRYPTION_KEY_URL_MISMATCH)
|
|
1351
1393
|
) {
|
|
1352
1394
|
// handle when key need to update
|
|
1353
|
-
this.webex
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1395
|
+
this.webex
|
|
1396
|
+
.request({
|
|
1397
|
+
method: 'GET',
|
|
1398
|
+
api: 'conversation',
|
|
1399
|
+
resource: `conversations/${params.body.target.id}`,
|
|
1400
|
+
})
|
|
1401
|
+
.then((res) => {
|
|
1402
|
+
cloneActivity.body.target.defaultActivityEncryptionKeyUrl =
|
|
1403
|
+
res.body.defaultActivityEncryptionkeyUrl;
|
|
1404
|
+
this.request(cloneActivity);
|
|
1405
|
+
});
|
|
1406
|
+
} else {
|
|
1363
1407
|
throw error;
|
|
1364
1408
|
}
|
|
1365
1409
|
});
|
|
@@ -1371,10 +1415,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1371
1415
|
* @returns {Promise}
|
|
1372
1416
|
*/
|
|
1373
1417
|
unassign(conversation, activity) {
|
|
1374
|
-
const convoWithUrl =
|
|
1375
|
-
Object.assign(
|
|
1376
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1377
|
-
);
|
|
1418
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1378
1419
|
|
|
1379
1420
|
return this.prepare(activity, {
|
|
1380
1421
|
verb: 'unassign',
|
|
@@ -1382,11 +1423,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1382
1423
|
object: {
|
|
1383
1424
|
objectType: 'content',
|
|
1384
1425
|
files: {
|
|
1385
|
-
items: []
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
})
|
|
1389
|
-
.then((a) => this.submit(a));
|
|
1426
|
+
items: [],
|
|
1427
|
+
},
|
|
1428
|
+
},
|
|
1429
|
+
}).then((a) => this.submit(a));
|
|
1390
1430
|
},
|
|
1391
1431
|
|
|
1392
1432
|
/**
|
|
@@ -1396,9 +1436,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1396
1436
|
* @returns {Promise} Resolves with the created activity
|
|
1397
1437
|
*/
|
|
1398
1438
|
unmuteMentions(conversation, activity) {
|
|
1399
|
-
return this.tag(
|
|
1400
|
-
|
|
1401
|
-
|
|
1439
|
+
return this.tag(
|
|
1440
|
+
conversation,
|
|
1441
|
+
{
|
|
1442
|
+
tags: ['MENTION_NOTIFICATIONS_ON'],
|
|
1443
|
+
},
|
|
1444
|
+
activity
|
|
1445
|
+
);
|
|
1402
1446
|
},
|
|
1403
1447
|
|
|
1404
1448
|
/**
|
|
@@ -1408,9 +1452,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1408
1452
|
* @returns {Promise} Resolves with the created activity
|
|
1409
1453
|
*/
|
|
1410
1454
|
unmuteMessages(conversation, activity) {
|
|
1411
|
-
return this.tag(
|
|
1412
|
-
|
|
1413
|
-
|
|
1455
|
+
return this.tag(
|
|
1456
|
+
conversation,
|
|
1457
|
+
{
|
|
1458
|
+
tags: ['MESSAGE_NOTIFICATIONS_ON'],
|
|
1459
|
+
},
|
|
1460
|
+
activity
|
|
1461
|
+
);
|
|
1414
1462
|
},
|
|
1415
1463
|
|
|
1416
1464
|
/**
|
|
@@ -1420,9 +1468,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1420
1468
|
* @returns {Promise} Resolves with the created activity
|
|
1421
1469
|
*/
|
|
1422
1470
|
unignore(conversation, activity) {
|
|
1423
|
-
return this.untag(
|
|
1424
|
-
|
|
1425
|
-
|
|
1471
|
+
return this.untag(
|
|
1472
|
+
conversation,
|
|
1473
|
+
{
|
|
1474
|
+
tags: ['IGNORED'],
|
|
1475
|
+
},
|
|
1476
|
+
activity
|
|
1477
|
+
);
|
|
1426
1478
|
},
|
|
1427
1479
|
|
|
1428
1480
|
/**
|
|
@@ -1437,17 +1489,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1437
1489
|
return Promise.reject(new Error('`object` must be an object'));
|
|
1438
1490
|
}
|
|
1439
1491
|
|
|
1440
|
-
const convoWithUrl =
|
|
1441
|
-
Object.assign(
|
|
1442
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1443
|
-
);
|
|
1492
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1444
1493
|
|
|
1445
1494
|
return this.prepare(activity, {
|
|
1446
1495
|
verb: 'update',
|
|
1447
1496
|
target: this.prepareConversation(convoWithUrl),
|
|
1448
|
-
object
|
|
1449
|
-
})
|
|
1450
|
-
.then((a) => this.submit(a));
|
|
1497
|
+
object,
|
|
1498
|
+
}).then((a) => this.submit(a));
|
|
1451
1499
|
},
|
|
1452
1500
|
|
|
1453
1501
|
/**
|
|
@@ -1460,16 +1508,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1460
1508
|
* @returns {Promise<Activity>}
|
|
1461
1509
|
*/
|
|
1462
1510
|
updateKey(conversation, key, activity) {
|
|
1463
|
-
const convoWithUrl =
|
|
1464
|
-
Object.assign(
|
|
1465
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1466
|
-
);
|
|
1511
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1467
1512
|
|
|
1468
1513
|
return this.get(convoWithUrl, {
|
|
1469
1514
|
activitiesLimit: 0,
|
|
1470
|
-
includeParticipants: true
|
|
1471
|
-
})
|
|
1472
|
-
.then((c) => this._updateKey(c, key, activity));
|
|
1515
|
+
includeParticipants: true,
|
|
1516
|
+
}).then((c) => this._updateKey(c, key, activity));
|
|
1473
1517
|
},
|
|
1474
1518
|
|
|
1475
1519
|
/**
|
|
@@ -1483,52 +1527,44 @@ const Conversation = WebexPlugin.extend({
|
|
|
1483
1527
|
* @returns {Promise<Activity>}
|
|
1484
1528
|
*/
|
|
1485
1529
|
_updateKey(conversation, key, activity) {
|
|
1486
|
-
const convoWithUrl =
|
|
1487
|
-
Object.assign(
|
|
1488
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
1489
|
-
);
|
|
1530
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
1490
1531
|
|
|
1491
1532
|
return Promise.resolve(
|
|
1492
1533
|
key || this.webex.internal.encryption.kms.createUnboundKeys({count: 1})
|
|
1493
|
-
)
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
};
|
|
1534
|
+
).then((keys) => {
|
|
1535
|
+
const k = isArray(keys) ? keys[0] : keys;
|
|
1536
|
+
const params = {
|
|
1537
|
+
verb: 'updateKey',
|
|
1538
|
+
target: this.prepareConversation(convoWithUrl),
|
|
1539
|
+
object: {
|
|
1540
|
+
defaultActivityEncryptionKeyUrl: k.uri,
|
|
1541
|
+
objectType: 'conversation',
|
|
1542
|
+
},
|
|
1543
|
+
};
|
|
1504
1544
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
]
|
|
1526
|
-
};
|
|
1527
|
-
}
|
|
1545
|
+
// Reminder: the kmsResourceObjectUrl is only usable if there is
|
|
1546
|
+
// defaultActivityEncryptionKeyUrl.
|
|
1547
|
+
// Valid defaultActivityEncryptionKeyUrl start with 'kms:'
|
|
1548
|
+
if (
|
|
1549
|
+
convoWithUrl.kmsResourceObjectUrl &&
|
|
1550
|
+
convoWithUrl.kmsResourceObjectUrl.startsWith('kms:')
|
|
1551
|
+
) {
|
|
1552
|
+
params.kmsMessage = {
|
|
1553
|
+
method: 'update',
|
|
1554
|
+
resourceUri: '<KRO>',
|
|
1555
|
+
uri: k.uri,
|
|
1556
|
+
};
|
|
1557
|
+
} else {
|
|
1558
|
+
params.kmsMessage = {
|
|
1559
|
+
method: 'create',
|
|
1560
|
+
uri: '/resources',
|
|
1561
|
+
userIds: map(convoWithUrl.participants.items, 'id'),
|
|
1562
|
+
keyUris: [k.uri],
|
|
1563
|
+
};
|
|
1564
|
+
}
|
|
1528
1565
|
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
});
|
|
1566
|
+
return this.prepare(activity, params).then((a) => this.submit(a));
|
|
1567
|
+
});
|
|
1532
1568
|
},
|
|
1533
1569
|
|
|
1534
1570
|
/**
|
|
@@ -1544,10 +1580,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
1544
1580
|
resource: 'conversations',
|
|
1545
1581
|
body: payload,
|
|
1546
1582
|
qs: {
|
|
1547
|
-
forceCreate: options.allowPartialCreation
|
|
1548
|
-
}
|
|
1549
|
-
})
|
|
1550
|
-
.then((res) => res.body);
|
|
1583
|
+
forceCreate: options.allowPartialCreation,
|
|
1584
|
+
},
|
|
1585
|
+
}).then((res) => res.body);
|
|
1551
1586
|
},
|
|
1552
1587
|
|
|
1553
1588
|
/**
|
|
@@ -1592,13 +1627,11 @@ const Conversation = WebexPlugin.extend({
|
|
|
1592
1627
|
|
|
1593
1628
|
// Wait for the postauth catalog to update and then try to retrieve the
|
|
1594
1629
|
// conversation service url again.
|
|
1595
|
-
return this.webex.internal
|
|
1630
|
+
return this.webex.internal
|
|
1631
|
+
.waitForCatalog('postauth')
|
|
1596
1632
|
.then(() => this.webex.internal.services.get('conversation'))
|
|
1597
1633
|
.catch((error) => {
|
|
1598
|
-
this.logger.warn(
|
|
1599
|
-
'conversation: unable to get conversation url',
|
|
1600
|
-
error.message
|
|
1601
|
-
);
|
|
1634
|
+
this.logger.warn('conversation: unable to get conversation url', error.message);
|
|
1602
1635
|
|
|
1603
1636
|
return Promise.reject(error);
|
|
1604
1637
|
});
|
|
@@ -1611,29 +1644,30 @@ const Conversation = WebexPlugin.extend({
|
|
|
1611
1644
|
*/
|
|
1612
1645
|
_inferConversationUrl(conversation) {
|
|
1613
1646
|
if (conversation.id) {
|
|
1614
|
-
return this.webex.internal.feature
|
|
1647
|
+
return this.webex.internal.feature
|
|
1648
|
+
.getFeature('developer', 'web-high-availability')
|
|
1615
1649
|
.then((haMessagingEnabled) => {
|
|
1616
1650
|
if (haMessagingEnabled) {
|
|
1617
1651
|
// recompute conversation URL each time as the host may have changed
|
|
1618
1652
|
// since last usage
|
|
1619
|
-
return this.getConversationUrl()
|
|
1620
|
-
.
|
|
1621
|
-
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1653
|
+
return this.getConversationUrl().then((url) => {
|
|
1654
|
+
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1622
1655
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1656
|
+
return conversation;
|
|
1657
|
+
});
|
|
1625
1658
|
}
|
|
1626
1659
|
if (!conversation.url) {
|
|
1627
|
-
return this.getConversationUrl()
|
|
1628
|
-
.
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1660
|
+
return this.getConversationUrl().then((url) => {
|
|
1661
|
+
conversation.url = `${url}/conversations/${conversation.id}`;
|
|
1662
|
+
/* istanbul ignore else */
|
|
1663
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1664
|
+
this.logger.warn(
|
|
1665
|
+
'conversation: inferred conversation url from conversation id; please pass whole conversation objects to Conversation methods'
|
|
1666
|
+
);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
return conversation;
|
|
1670
|
+
});
|
|
1637
1671
|
}
|
|
1638
1672
|
|
|
1639
1673
|
return Promise.resolve(conversation);
|
|
@@ -1657,11 +1691,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1657
1691
|
|
|
1658
1692
|
return this._list({
|
|
1659
1693
|
qs: omit(options, 'resource'),
|
|
1660
|
-
url: `${url}/${resource}
|
|
1694
|
+
url: `${url}/${resource}`,
|
|
1661
1695
|
});
|
|
1662
1696
|
},
|
|
1663
1697
|
|
|
1664
|
-
|
|
1665
1698
|
/**
|
|
1666
1699
|
* common interface for facade of generator functions
|
|
1667
1700
|
* @typedef {object} IGeneratorResponse
|
|
@@ -1688,10 +1721,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1688
1721
|
* jumpToActivity - gets searched-for activity and surrounding activities
|
|
1689
1722
|
*/
|
|
1690
1723
|
listActivitiesThreadOrdered(options) {
|
|
1691
|
-
const {
|
|
1692
|
-
conversationUrl,
|
|
1693
|
-
conversationId
|
|
1694
|
-
} = options;
|
|
1724
|
+
const {conversationUrl, conversationId} = options;
|
|
1695
1725
|
|
|
1696
1726
|
if (!conversationUrl && !conversationId) {
|
|
1697
1727
|
throw new Error('must provide a conversation URL or conversation ID');
|
|
@@ -1723,7 +1753,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
1723
1753
|
}
|
|
1724
1754
|
|
|
1725
1755
|
const searchOptions = {
|
|
1726
|
-
...baseOptions,
|
|
1756
|
+
...baseOptions,
|
|
1757
|
+
url: newUrl,
|
|
1758
|
+
queryType: MID,
|
|
1759
|
+
search: searchObject,
|
|
1727
1760
|
};
|
|
1728
1761
|
|
|
1729
1762
|
threadOrderer = this._listActivitiesThreadOrdered(searchOptions);
|
|
@@ -1732,7 +1765,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1732
1765
|
|
|
1733
1766
|
return {
|
|
1734
1767
|
done: true,
|
|
1735
|
-
value: searchResults
|
|
1768
|
+
value: searchResults,
|
|
1736
1769
|
};
|
|
1737
1770
|
};
|
|
1738
1771
|
|
|
@@ -1744,11 +1777,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
1744
1777
|
const {value = []} = await threadOrderer.next(olderOptions);
|
|
1745
1778
|
|
|
1746
1779
|
const oldestInBatch = value[0] && value[0].activity;
|
|
1747
|
-
const moreActivitiesExist =
|
|
1780
|
+
const moreActivitiesExist =
|
|
1781
|
+
oldestInBatch && getActivityType(oldestInBatch) !== ACTIVITY_TYPES.CREATE;
|
|
1748
1782
|
|
|
1749
1783
|
return {
|
|
1750
1784
|
done: !moreActivitiesExist,
|
|
1751
|
-
value
|
|
1785
|
+
value,
|
|
1752
1786
|
};
|
|
1753
1787
|
};
|
|
1754
1788
|
|
|
@@ -1763,22 +1797,22 @@ const Conversation = WebexPlugin.extend({
|
|
|
1763
1797
|
|
|
1764
1798
|
return {
|
|
1765
1799
|
done: !value.length,
|
|
1766
|
-
value
|
|
1800
|
+
value,
|
|
1767
1801
|
};
|
|
1768
1802
|
};
|
|
1769
1803
|
|
|
1770
1804
|
return {
|
|
1771
1805
|
jumpToActivity,
|
|
1772
1806
|
getNewer,
|
|
1773
|
-
getOlder
|
|
1807
|
+
getOlder,
|
|
1774
1808
|
};
|
|
1775
1809
|
},
|
|
1776
1810
|
|
|
1777
1811
|
/**
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1812
|
+
* Represents reactions to messages
|
|
1813
|
+
* @typedef {object} Reaction
|
|
1814
|
+
* @property {object} activity reaction2summary server activity object
|
|
1815
|
+
*/
|
|
1782
1816
|
|
|
1783
1817
|
/**
|
|
1784
1818
|
* Represents a root (parent, with or without children) activity, along with any replies and reactions
|
|
@@ -1804,34 +1838,30 @@ const Conversation = WebexPlugin.extend({
|
|
|
1804
1838
|
*
|
|
1805
1839
|
* @returns {void}
|
|
1806
1840
|
*/
|
|
1807
|
-
async*
|
|
1841
|
+
async *_listActivitiesThreadOrdered(options = {}) {
|
|
1808
1842
|
// ***********************************************
|
|
1809
1843
|
// INSTANCE STATE VARIABLES
|
|
1810
1844
|
// variables that will be used for the life of the generator
|
|
1811
1845
|
// ***********************************************
|
|
1812
1846
|
|
|
1813
|
-
let {
|
|
1814
|
-
minActivities = defaultMinDisplayableActivities,
|
|
1815
|
-
queryType = INITIAL
|
|
1816
|
-
} = options;
|
|
1847
|
+
let {minActivities = defaultMinDisplayableActivities, queryType = INITIAL} = options;
|
|
1817
1848
|
|
|
1818
1849
|
// must fetch initially before getting newer activities!
|
|
1819
1850
|
if (queryType === NEWER) {
|
|
1820
1851
|
queryType = INITIAL;
|
|
1821
1852
|
}
|
|
1822
1853
|
|
|
1823
|
-
const {
|
|
1824
|
-
url: convoUrl,
|
|
1825
|
-
search = {},
|
|
1826
|
-
includeChildren
|
|
1827
|
-
} = options;
|
|
1854
|
+
const {url: convoUrl, search = {}, includeChildren} = options;
|
|
1828
1855
|
|
|
1829
1856
|
// manage oldest, newest activities (ie bookends)
|
|
1830
1857
|
const {setBookends, getNewestAct, getOldestAct} = bookendManager();
|
|
1831
1858
|
|
|
1832
1859
|
// 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
1860
|
// reduces server RTs when fetching older activities
|
|
1834
|
-
const defaultBatchSize =
|
|
1861
|
+
const defaultBatchSize =
|
|
1862
|
+
queryType === INITIAL || queryType === OLDER
|
|
1863
|
+
? minActivities
|
|
1864
|
+
: Math.max(minBatchSize, Math.ceil(minActivities / 2));
|
|
1835
1865
|
let batchSize = defaultBatchSize;
|
|
1836
1866
|
|
|
1837
1867
|
// exposes activity states and handlers with simple getters
|
|
@@ -1853,22 +1883,19 @@ const Conversation = WebexPlugin.extend({
|
|
|
1853
1883
|
|
|
1854
1884
|
// used to determine if we should continue to fetch older activities
|
|
1855
1885
|
// 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]);
|
|
1886
|
+
const {getNoMoreActs, checkAndSetNoMoreActs, checkAndSetNoOlderActs, checkAndSetNoNewerActs} =
|
|
1887
|
+
noMoreActivitiesManager();
|
|
1888
|
+
|
|
1889
|
+
const getActivityHandlerByType = (type) =>
|
|
1890
|
+
({
|
|
1891
|
+
[ACTIVITY_TYPES.ROOT]: addNewRoot,
|
|
1892
|
+
[ACTIVITY_TYPES.REPLY]: getActivityHandlerByKey(ACTIVITY_TYPES.REPLY),
|
|
1893
|
+
[ACTIVITY_TYPES.EDIT]: getActivityHandlerByKey(ACTIVITY_TYPES.EDIT),
|
|
1894
|
+
[ACTIVITY_TYPES.REACTION]: getActivityHandlerByKey(ACTIVITY_TYPES.REACTION),
|
|
1895
|
+
[ACTIVITY_TYPES.REACTION_SELF]: getActivityHandlerByKey(ACTIVITY_TYPES.REACTION_SELF),
|
|
1896
|
+
[ACTIVITY_TYPES.TOMBSTONE]: addNewRoot,
|
|
1897
|
+
[ACTIVITY_TYPES.CREATE]: addNewRoot,
|
|
1898
|
+
}[type]);
|
|
1872
1899
|
|
|
1873
1900
|
const handleNewActivity = (activity) => {
|
|
1874
1901
|
const actType = getActivityType(activity);
|
|
@@ -1906,12 +1933,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
1906
1933
|
handleNewActivities(activities);
|
|
1907
1934
|
};
|
|
1908
1935
|
|
|
1909
|
-
const getQueryResponseHandler = (type) =>
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1936
|
+
const getQueryResponseHandler = (type) =>
|
|
1937
|
+
({
|
|
1938
|
+
[OLDER]: handleOlderQuery,
|
|
1939
|
+
[NEWER]: handleNewerQuery,
|
|
1940
|
+
[MID]: handleSearch,
|
|
1941
|
+
[INITIAL]: handleOlderQuery,
|
|
1942
|
+
}[type]);
|
|
1915
1943
|
|
|
1916
1944
|
// ***********************************************
|
|
1917
1945
|
// INNER LOOP
|
|
@@ -1930,7 +1958,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1930
1958
|
conversationUrl: convoUrl,
|
|
1931
1959
|
limit: batchSize,
|
|
1932
1960
|
includeChildren,
|
|
1933
|
-
...query
|
|
1961
|
+
...query,
|
|
1934
1962
|
};
|
|
1935
1963
|
|
|
1936
1964
|
// request activities in batches
|
|
@@ -1953,10 +1981,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1953
1981
|
}
|
|
1954
1982
|
|
|
1955
1983
|
// we dont always need to fetch for parents
|
|
1956
|
-
const [
|
|
1957
|
-
allBatchActivities,
|
|
1958
|
-
parents = {}
|
|
1959
|
-
] = await Promise.all($fetchRequests);
|
|
1984
|
+
const [allBatchActivities, parents = {}] = await Promise.all($fetchRequests);
|
|
1960
1985
|
|
|
1961
1986
|
// use query type to decide how to handle response
|
|
1962
1987
|
const handler = getQueryResponseHandler(queryType);
|
|
@@ -1968,11 +1993,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
1968
1993
|
do this by checking the hash for each of the above parent IDs
|
|
1969
1994
|
fetch children when we have a parent whose ID is represented in the parent ID lists
|
|
1970
1995
|
*/
|
|
1971
|
-
const {
|
|
1972
|
-
reply: replyIds = [],
|
|
1973
|
-
edit: editIds = [],
|
|
1974
|
-
reaction: reactionIds = []
|
|
1975
|
-
} = parents;
|
|
1996
|
+
const {reply: replyIds = [], edit: editIds = [], reaction: reactionIds = []} = parents;
|
|
1976
1997
|
|
|
1977
1998
|
// if no parent IDs returned, do nothing
|
|
1978
1999
|
if (replyIds.length || editIds.length || reactionIds.length) {
|
|
@@ -1985,11 +2006,16 @@ const Conversation = WebexPlugin.extend({
|
|
|
1985
2006
|
|
|
1986
2007
|
const childFetchOptions = {
|
|
1987
2008
|
conversationUrl: convoUrl,
|
|
1988
|
-
activityParentId: actId
|
|
2009
|
+
activityParentId: actId,
|
|
1989
2010
|
};
|
|
1990
2011
|
|
|
1991
2012
|
if (reactionIds.includes(actId)) {
|
|
1992
|
-
$reactionFetches.push(
|
|
2013
|
+
$reactionFetches.push(
|
|
2014
|
+
this.getReactionSummaryByParentId(convoUrl, actId, {
|
|
2015
|
+
activityType: 'reactionSummary',
|
|
2016
|
+
includeChildren: true,
|
|
2017
|
+
})
|
|
2018
|
+
);
|
|
1993
2019
|
}
|
|
1994
2020
|
if (replyIds.includes(actId)) {
|
|
1995
2021
|
childFetchOptions.query = {activityType: 'reply'};
|
|
@@ -2005,14 +2031,19 @@ const Conversation = WebexPlugin.extend({
|
|
|
2005
2031
|
const [reactions, replies, edits] = await Promise.all([
|
|
2006
2032
|
Promise.all($reactionFetches),
|
|
2007
2033
|
Promise.all($replyFetches),
|
|
2008
|
-
Promise.all($editFetches)
|
|
2034
|
+
Promise.all($editFetches),
|
|
2009
2035
|
]);
|
|
2010
2036
|
|
|
2011
2037
|
// new reactions may have come in that also need their reactions fetched
|
|
2012
2038
|
const newReplyReactions = await Promise.all(
|
|
2013
2039
|
replies
|
|
2014
2040
|
.filter((reply) => replyIds.includes(reply.id))
|
|
2015
|
-
.map((reply) =>
|
|
2041
|
+
.map((reply) =>
|
|
2042
|
+
this.getReactionSummaryByParentId(convoUrl, reply.id, {
|
|
2043
|
+
activityType: 'reactionSummary',
|
|
2044
|
+
includeChildren: true,
|
|
2045
|
+
})
|
|
2046
|
+
)
|
|
2016
2047
|
);
|
|
2017
2048
|
|
|
2018
2049
|
const allReactions = [...reactions, ...newReplyReactions];
|
|
@@ -2060,13 +2091,12 @@ const Conversation = WebexPlugin.extend({
|
|
|
2060
2091
|
// we're still building our activity list - derive new query from prior query and start loop again
|
|
2061
2092
|
if (queryType === INITIAL) {
|
|
2062
2093
|
query = getQuery(OLDER, {oldestPublishedDate: currentOldestPublishedDate, batchSize});
|
|
2063
|
-
}
|
|
2064
|
-
else {
|
|
2094
|
+
} else {
|
|
2065
2095
|
query = getQuery(queryType, {
|
|
2066
2096
|
batchSize,
|
|
2067
2097
|
activityToSearch: search,
|
|
2068
2098
|
oldestPublishedDate: currentOldestPublishedDate,
|
|
2069
|
-
newestPublishedDate: currentNewestPublishedDate
|
|
2099
|
+
newestPublishedDate: currentNewestPublishedDate,
|
|
2070
2100
|
});
|
|
2071
2101
|
}
|
|
2072
2102
|
|
|
@@ -2087,7 +2117,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2087
2117
|
return replies;
|
|
2088
2118
|
}
|
|
2089
2119
|
|
|
2090
|
-
const sortedReplies = sortActivitiesByPublishedDate(
|
|
2120
|
+
const sortedReplies = sortActivitiesByPublishedDate(
|
|
2121
|
+
getActivityObjectsFromMap(repliesByParentId)
|
|
2122
|
+
);
|
|
2091
2123
|
|
|
2092
2124
|
sortedReplies.forEach((replyActivity) => {
|
|
2093
2125
|
const replyId = replyActivity.id;
|
|
@@ -2097,20 +2129,26 @@ const Conversation = WebexPlugin.extend({
|
|
|
2097
2129
|
|
|
2098
2130
|
const latestActivity = edit || replyActivity;
|
|
2099
2131
|
// hash of root activities (in case of plain reply) and the reply activity (in case of edit)
|
|
2100
|
-
const allRelevantActivitiesArr = [
|
|
2132
|
+
const allRelevantActivitiesArr = [
|
|
2133
|
+
...getActivityObjectsFromMap(getRootActivityHash()),
|
|
2134
|
+
...getActivityObjectsFromMap(repliesByParentId),
|
|
2135
|
+
];
|
|
2101
2136
|
const allRelevantActivities = allRelevantActivitiesArr.reduce((hashMap, act) => {
|
|
2102
2137
|
hashMap[act.id] = act;
|
|
2103
2138
|
|
|
2104
2139
|
return hashMap;
|
|
2105
2140
|
}, {});
|
|
2106
2141
|
|
|
2107
|
-
const finalReply = this._createParsedServerActivity(
|
|
2142
|
+
const finalReply = this._createParsedServerActivity(
|
|
2143
|
+
latestActivity,
|
|
2144
|
+
allRelevantActivities
|
|
2145
|
+
);
|
|
2108
2146
|
|
|
2109
2147
|
const fullReply = {
|
|
2110
2148
|
id: replyId,
|
|
2111
2149
|
activity: finalReply,
|
|
2112
2150
|
reaction,
|
|
2113
|
-
reactionSelf
|
|
2151
|
+
reactionSelf,
|
|
2114
2152
|
};
|
|
2115
2153
|
|
|
2116
2154
|
const sanitizedFullReply = sanitizeActivity(fullReply);
|
|
@@ -2121,7 +2159,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2121
2159
|
return replies;
|
|
2122
2160
|
};
|
|
2123
2161
|
|
|
2124
|
-
const orderedRoots = sortActivitiesByPublishedDate(
|
|
2162
|
+
const orderedRoots = sortActivitiesByPublishedDate(
|
|
2163
|
+
getActivityObjectsFromMap(getRootActivityHash())
|
|
2164
|
+
);
|
|
2125
2165
|
|
|
2126
2166
|
orderedRoots.forEach((rootActivity) => {
|
|
2127
2167
|
const rootId = rootActivity.id;
|
|
@@ -2131,13 +2171,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
2131
2171
|
const reactionSelf = getActivityByTypeAndParentId(ACTIVITY_TYPES.REACTION_SELF, rootId);
|
|
2132
2172
|
|
|
2133
2173
|
const latestActivity = edit || rootActivity;
|
|
2134
|
-
const finalActivity = this._createParsedServerActivity(latestActivity, {
|
|
2174
|
+
const finalActivity = this._createParsedServerActivity(latestActivity, {
|
|
2175
|
+
[rootId]: rootActivity,
|
|
2176
|
+
});
|
|
2135
2177
|
|
|
2136
2178
|
const fullRoot = {
|
|
2137
2179
|
id: rootId,
|
|
2138
2180
|
activity: finalActivity,
|
|
2139
2181
|
reaction,
|
|
2140
|
-
reactionSelf
|
|
2182
|
+
reactionSelf,
|
|
2141
2183
|
};
|
|
2142
2184
|
|
|
2143
2185
|
const sanitizedFullRoot = sanitizeActivity(fullRoot);
|
|
@@ -2159,10 +2201,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2159
2201
|
activityToSearch: search,
|
|
2160
2202
|
oldestPublishedDate: currentOldestPublishedDate,
|
|
2161
2203
|
newestPublishedDate: currentNewestPublishedDate,
|
|
2162
|
-
batchSize
|
|
2204
|
+
batchSize,
|
|
2163
2205
|
});
|
|
2164
|
-
}
|
|
2165
|
-
else {
|
|
2206
|
+
} else {
|
|
2166
2207
|
return;
|
|
2167
2208
|
}
|
|
2168
2209
|
}
|
|
@@ -2183,10 +2224,10 @@ const Conversation = WebexPlugin.extend({
|
|
|
2183
2224
|
*/
|
|
2184
2225
|
|
|
2185
2226
|
/**
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2227
|
+
* hashmap of server activities, keyed by id
|
|
2228
|
+
* @typedef {object} ActivityHash
|
|
2229
|
+
* @property {Object}
|
|
2230
|
+
*/
|
|
2190
2231
|
|
|
2191
2232
|
/**
|
|
2192
2233
|
* extends a given server object with fields that point to their parent activities from the hashmap passed in
|
|
@@ -2198,7 +2239,9 @@ const Conversation = WebexPlugin.extend({
|
|
|
2198
2239
|
const isOrphan = getIsActivityOrphaned(activity, allActivitiesHash);
|
|
2199
2240
|
|
|
2200
2241
|
if (isOrphan) {
|
|
2201
|
-
throw new Error(
|
|
2242
|
+
throw new Error(
|
|
2243
|
+
'activity has a parent that cannot be found in allActivitiesHash! please handle this as necessary'
|
|
2244
|
+
);
|
|
2202
2245
|
}
|
|
2203
2246
|
|
|
2204
2247
|
const activityType = determineActivityType(activity, allActivitiesHash);
|
|
@@ -2230,12 +2273,13 @@ const Conversation = WebexPlugin.extend({
|
|
|
2230
2273
|
* @returns {Promise<Array<Conversation>>}
|
|
2231
2274
|
*/
|
|
2232
2275
|
async _list(options) {
|
|
2233
|
-
options.qs =
|
|
2276
|
+
options.qs = {
|
|
2234
2277
|
personRefresh: true,
|
|
2235
2278
|
uuidEntryFormat: true,
|
|
2236
2279
|
activitiesLimit: 0,
|
|
2237
|
-
participantsLimit: 0
|
|
2238
|
-
|
|
2280
|
+
participantsLimit: 0,
|
|
2281
|
+
...options.qs,
|
|
2282
|
+
};
|
|
2239
2283
|
|
|
2240
2284
|
const res = await this.request(options);
|
|
2241
2285
|
|
|
@@ -2243,8 +2287,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2243
2287
|
|
|
2244
2288
|
if (!res.body || !res.body.items || res.body.items.length === 0) {
|
|
2245
2289
|
list = [];
|
|
2246
|
-
}
|
|
2247
|
-
else {
|
|
2290
|
+
} else {
|
|
2248
2291
|
list = res.body.items.slice(0);
|
|
2249
2292
|
if (last(list).published < list[0].published) {
|
|
2250
2293
|
list.reverse();
|
|
@@ -2263,9 +2306,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2263
2306
|
// This won't get us the exact limit but it will retrieve something
|
|
2264
2307
|
// from every cluster listed.
|
|
2265
2308
|
if (options.limit) {
|
|
2266
|
-
limit = Math.floor(
|
|
2267
|
-
(options.limit.value - list.length) / res.body.additionalUrls.length
|
|
2268
|
-
);
|
|
2309
|
+
limit = Math.floor((options.limit.value - list.length) / res.body.additionalUrls.length);
|
|
2269
2310
|
}
|
|
2270
2311
|
|
|
2271
2312
|
// If the limit is 0 for some reason,
|
|
@@ -2274,7 +2315,7 @@ const Conversation = WebexPlugin.extend({
|
|
|
2274
2315
|
const results = await Promise.all(
|
|
2275
2316
|
res.body.additionalUrls.map((host) => {
|
|
2276
2317
|
const url = `${host}/${options.resource}`;
|
|
2277
|
-
const newOptions =
|
|
2318
|
+
const newOptions = {...options, uri: url, url};
|
|
2278
2319
|
|
|
2279
2320
|
if (options.limit) {
|
|
2280
2321
|
newOptions.qs[newOptions.limit.name] = limit;
|
|
@@ -2309,19 +2350,23 @@ const Conversation = WebexPlugin.extend({
|
|
|
2309
2350
|
* @returns {Promise<Conversation>}
|
|
2310
2351
|
*/
|
|
2311
2352
|
_maybeCreateOneOnOneThenPost(params, options) {
|
|
2312
|
-
return this.get(
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2353
|
+
return this.get(
|
|
2354
|
+
defaults({
|
|
2355
|
+
// the use of uniq in Conversation#create guarantees participant[1] will
|
|
2356
|
+
// always be the other user
|
|
2357
|
+
user: params.participants[1],
|
|
2358
|
+
}),
|
|
2359
|
+
Object.assign(options, {includeConvWithDeletedUserUUID: true, includeParticipants: true})
|
|
2360
|
+
)
|
|
2317
2361
|
.then((conversation) => {
|
|
2318
2362
|
if (params.comment || params.html) {
|
|
2319
|
-
return this.post(conversation, {content: params.html, displayName: params.comment})
|
|
2320
|
-
|
|
2363
|
+
return this.post(conversation, {content: params.html, displayName: params.comment}).then(
|
|
2364
|
+
(activity) => {
|
|
2321
2365
|
conversation.activities.items.push(activity);
|
|
2322
2366
|
|
|
2323
2367
|
return conversation;
|
|
2324
|
-
}
|
|
2368
|
+
}
|
|
2369
|
+
);
|
|
2325
2370
|
}
|
|
2326
2371
|
|
|
2327
2372
|
return conversation;
|
|
@@ -2343,17 +2388,15 @@ const Conversation = WebexPlugin.extend({
|
|
|
2343
2388
|
_prepareConversationForCreation(params) {
|
|
2344
2389
|
const payload = {
|
|
2345
2390
|
activities: {
|
|
2346
|
-
items: [
|
|
2347
|
-
this.expand('create')
|
|
2348
|
-
]
|
|
2391
|
+
items: [this.expand('create')],
|
|
2349
2392
|
},
|
|
2350
2393
|
objectType: 'conversation',
|
|
2351
2394
|
kmsMessage: {
|
|
2352
2395
|
method: 'create',
|
|
2353
2396
|
uri: '/resources',
|
|
2354
2397
|
userIds: cloneDeep(params.participants),
|
|
2355
|
-
keyUris: []
|
|
2356
|
-
}
|
|
2398
|
+
keyUris: [],
|
|
2399
|
+
},
|
|
2357
2400
|
};
|
|
2358
2401
|
|
|
2359
2402
|
if (params.displayName) {
|
|
@@ -2365,32 +2408,40 @@ const Conversation = WebexPlugin.extend({
|
|
|
2365
2408
|
}
|
|
2366
2409
|
|
|
2367
2410
|
params.participants.forEach((participant) => {
|
|
2368
|
-
payload.activities.items.push(
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2411
|
+
payload.activities.items.push(
|
|
2412
|
+
this.expand('add', {
|
|
2413
|
+
objectType: 'person',
|
|
2414
|
+
id: participant,
|
|
2415
|
+
})
|
|
2416
|
+
);
|
|
2372
2417
|
});
|
|
2373
2418
|
|
|
2374
2419
|
if (params.comment) {
|
|
2375
|
-
payload.activities.items.push(
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2420
|
+
payload.activities.items.push(
|
|
2421
|
+
this.expand('post', {
|
|
2422
|
+
objectType: 'comment',
|
|
2423
|
+
content: params.html,
|
|
2424
|
+
displayName: params.comment,
|
|
2425
|
+
})
|
|
2426
|
+
);
|
|
2380
2427
|
}
|
|
2381
2428
|
|
|
2382
2429
|
if (!params.isDefaultClassification && params.classificationId) {
|
|
2383
|
-
payload.activities.items.push(
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2430
|
+
payload.activities.items.push(
|
|
2431
|
+
this.expand('update', {
|
|
2432
|
+
objectType: 'classification',
|
|
2433
|
+
classificationId: params.classificationId,
|
|
2434
|
+
effectiveDate: params.effectiveDate,
|
|
2435
|
+
})
|
|
2436
|
+
);
|
|
2388
2437
|
}
|
|
2389
2438
|
|
|
2390
2439
|
if (params.favorite) {
|
|
2391
|
-
payload.activities.items.push(
|
|
2392
|
-
|
|
2393
|
-
|
|
2440
|
+
payload.activities.items.push(
|
|
2441
|
+
this.expand('favorite', {
|
|
2442
|
+
objectType: 'conversation',
|
|
2443
|
+
})
|
|
2444
|
+
);
|
|
2394
2445
|
}
|
|
2395
2446
|
|
|
2396
2447
|
return payload;
|
|
@@ -2406,68 +2457,59 @@ const Conversation = WebexPlugin.extend({
|
|
|
2406
2457
|
return Promise.resolve(conversation);
|
|
2407
2458
|
}
|
|
2408
2459
|
|
|
2409
|
-
return Promise.all(
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2460
|
+
return Promise.all(
|
|
2461
|
+
conversation.participants.items.map((participant) => {
|
|
2462
|
+
// ROOMs or LYRA_SPACEs do not have email addresses, so there's no point attempting to
|
|
2463
|
+
// record their UUIDs.
|
|
2464
|
+
if (participant.type === 'ROOM' || participant.type === 'LYRA_SPACE') {
|
|
2465
|
+
return Promise.resolve();
|
|
2466
|
+
}
|
|
2415
2467
|
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2468
|
+
return this.webex.internal.user
|
|
2469
|
+
.recordUUID(participant)
|
|
2470
|
+
.catch((err) => this.logger.warn('Could not record uuid', err));
|
|
2471
|
+
})
|
|
2472
|
+
);
|
|
2473
|
+
},
|
|
2420
2474
|
});
|
|
2421
2475
|
|
|
2422
|
-
[
|
|
2423
|
-
'favorite',
|
|
2424
|
-
'hide',
|
|
2425
|
-
'lock',
|
|
2426
|
-
'mute',
|
|
2427
|
-
'unfavorite',
|
|
2428
|
-
'unhide',
|
|
2429
|
-
'unlock',
|
|
2430
|
-
'unmute'
|
|
2431
|
-
].forEach((verb) => {
|
|
2476
|
+
['favorite', 'hide', 'lock', 'mute', 'unfavorite', 'unhide', 'unlock', 'unmute'].forEach((verb) => {
|
|
2432
2477
|
Conversation.prototype[verb] = function submitSimpleActivity(conversation, activity) {
|
|
2433
|
-
const convoWithUrl =
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
)
|
|
2438
|
-
);
|
|
2478
|
+
const convoWithUrl = this.prepareConversation({
|
|
2479
|
+
...conversation,
|
|
2480
|
+
url: this.getConvoUrl(conversation),
|
|
2481
|
+
});
|
|
2439
2482
|
|
|
2440
2483
|
return this.prepare(activity, {
|
|
2441
2484
|
verb,
|
|
2442
2485
|
object: convoWithUrl,
|
|
2443
|
-
target: convoWithUrl
|
|
2444
|
-
})
|
|
2445
|
-
.then((a) => this.submit(a));
|
|
2486
|
+
target: convoWithUrl,
|
|
2487
|
+
}).then((a) => this.submit(a));
|
|
2446
2488
|
};
|
|
2447
2489
|
});
|
|
2448
2490
|
|
|
2449
|
-
[
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2457
|
-
);
|
|
2491
|
+
['assignModerator', 'unassignModerator'].forEach((verb) => {
|
|
2492
|
+
Conversation.prototype[verb] = function submitModerationChangeActivity(
|
|
2493
|
+
conversation,
|
|
2494
|
+
moderator,
|
|
2495
|
+
activity
|
|
2496
|
+
) {
|
|
2497
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
2458
2498
|
|
|
2459
2499
|
return Promise.all([
|
|
2460
2500
|
convoWithUrl,
|
|
2461
|
-
moderator ? this.webex.internal.user.asUUID(moderator) : this.webex.internal.device.userId
|
|
2501
|
+
moderator ? this.webex.internal.user.asUUID(moderator) : this.webex.internal.device.userId,
|
|
2462
2502
|
])
|
|
2463
|
-
.then(([c, userId]) =>
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2503
|
+
.then(([c, userId]) =>
|
|
2504
|
+
this.prepare(activity, {
|
|
2505
|
+
verb,
|
|
2506
|
+
target: this.prepareConversation(c),
|
|
2507
|
+
object: {
|
|
2508
|
+
id: userId,
|
|
2509
|
+
objectType: 'person',
|
|
2510
|
+
},
|
|
2511
|
+
})
|
|
2512
|
+
)
|
|
2471
2513
|
.then((a) => this.submit(a));
|
|
2472
2514
|
};
|
|
2473
2515
|
});
|
|
@@ -2479,56 +2521,44 @@ const Conversation = WebexPlugin.extend({
|
|
|
2479
2521
|
* @param {Activity} activity
|
|
2480
2522
|
* @returns {Promise<Activity>}
|
|
2481
2523
|
*/
|
|
2482
|
-
[
|
|
2483
|
-
'setSpaceProperty',
|
|
2484
|
-
'unsetSpaceProperty'
|
|
2485
|
-
].forEach((fnName) => {
|
|
2524
|
+
['setSpaceProperty', 'unsetSpaceProperty'].forEach((fnName) => {
|
|
2486
2525
|
const verb = fnName.startsWith('set') ? 'set' : 'unset';
|
|
2487
2526
|
|
|
2488
|
-
Conversation.prototype[fnName] = function submitSpacePropertyActivity(
|
|
2527
|
+
Conversation.prototype[fnName] = function submitSpacePropertyActivity(
|
|
2528
|
+
conversation,
|
|
2529
|
+
tag,
|
|
2530
|
+
activity
|
|
2531
|
+
) {
|
|
2489
2532
|
if (!isString(tag)) {
|
|
2490
2533
|
return Promise.reject(new Error('`tag` must be a string'));
|
|
2491
2534
|
}
|
|
2492
2535
|
|
|
2493
|
-
const convoWithUrl =
|
|
2494
|
-
Object.assign(
|
|
2495
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2496
|
-
);
|
|
2536
|
+
const convoWithUrl = {...conversation, url: this.getConvoUrl(conversation)};
|
|
2497
2537
|
|
|
2498
2538
|
return this.prepare(activity, {
|
|
2499
2539
|
verb,
|
|
2500
2540
|
target: this.prepareConversation(convoWithUrl),
|
|
2501
2541
|
object: {
|
|
2502
2542
|
tags: [tag],
|
|
2503
|
-
objectType: 'spaceProperty'
|
|
2504
|
-
}
|
|
2505
|
-
})
|
|
2506
|
-
.then((a) => this.submit(a));
|
|
2543
|
+
objectType: 'spaceProperty',
|
|
2544
|
+
},
|
|
2545
|
+
}).then((a) => this.submit(a));
|
|
2507
2546
|
};
|
|
2508
2547
|
});
|
|
2509
2548
|
|
|
2510
|
-
[
|
|
2511
|
-
'tag',
|
|
2512
|
-
'untag'
|
|
2513
|
-
].forEach((verb) => {
|
|
2549
|
+
['tag', 'untag'].forEach((verb) => {
|
|
2514
2550
|
Conversation.prototype[verb] = function submitObjectActivity(conversation, object, activity) {
|
|
2515
2551
|
if (!isObject(object)) {
|
|
2516
2552
|
return Promise.reject(new Error('`object` must be an object'));
|
|
2517
2553
|
}
|
|
2518
2554
|
|
|
2519
|
-
const c =
|
|
2520
|
-
this.prepareConversation(
|
|
2521
|
-
Object.assign(
|
|
2522
|
-
{}, conversation, {url: this.getConvoUrl(conversation)}
|
|
2523
|
-
)
|
|
2524
|
-
);
|
|
2555
|
+
const c = this.prepareConversation({...conversation, url: this.getConvoUrl(conversation)});
|
|
2525
2556
|
|
|
2526
2557
|
return this.prepare(activity, {
|
|
2527
2558
|
verb,
|
|
2528
2559
|
target: c,
|
|
2529
|
-
object: Object.assign(c, object)
|
|
2530
|
-
})
|
|
2531
|
-
.then((a) => this.submit(a));
|
|
2560
|
+
object: Object.assign(c, object),
|
|
2561
|
+
}).then((a) => this.submit(a));
|
|
2532
2562
|
};
|
|
2533
2563
|
});
|
|
2534
2564
|
|