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