@webex/plugin-memberships 2.59.2 → 2.59.3-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,654 +1,654 @@
1
- /*!
2
- * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
- */
4
-
5
- import {
6
- SDK_EVENT,
7
- createEventEnvelope,
8
- ensureMyIdIsAvailable,
9
- buildHydraMembershipId,
10
- buildHydraMessageId,
11
- buildHydraOrgId,
12
- buildHydraPersonId,
13
- buildHydraRoomId,
14
- getHydraClusterString,
15
- getHydraRoomType,
16
- deconstructHydraId,
17
- } from '@webex/common';
18
- import {WebexPlugin, Page} from '@webex/webex-core';
19
- import {cloneDeep} from 'lodash';
20
-
21
- const debug = require('debug')('memberships');
22
-
23
- /**
24
- * @typedef {Object} MembershipObject
25
- * @property {string} id - Unique identifier for the membership
26
- * @property {string} roomId - The room ID
27
- * @property {string} personId - The person ID
28
- * @property {email} personEmail - The email address of the person / room member
29
- * @property {boolean} isModerator - Indicates whether the specified person should be a room moderator
30
- * @property {boolean} isMonitor - Indicates whether the specified member is a room monitor
31
- * @property {isoDate} created - The date and time that this membership was created
32
- */
33
-
34
- /**
35
- * Memberships represent a person's relationship to a room. Use this API to list
36
- * members of any room that you're in or create memberships to invite someone
37
- * to a room. Memberships can also be updated to make someone a moderator
38
- * or deleted to remove them from the room.
39
- * @class
40
- * @name Memberships
41
- */
42
- const Memberships = WebexPlugin.extend({
43
- /**
44
- * Register to listen for incoming membership events
45
- * This is an alternate approach to registering for membership webhooks.
46
- * The events passed to any registered handlers will be similar to the webhook JSON,
47
- * but will omit webhook specific fields such as name, secret, url, etc.
48
- * To utilize the `listen()` method, the authorization token used
49
- * will need to have `spark:all` and `spark:kms` scopes enabled.
50
- * Note that by configuring your application to enable or disable `spark:all`
51
- * via its configuration page will also enable or disable `spark:kms`.
52
- * See the <a href="https://webex.github.io/webex-js-sdk/samples/browser-socket/">Sample App</a>
53
- * for more details.
54
- * @instance
55
- * @memberof Memberships
56
- * @returns {Promise}
57
- * @example
58
- * webex.memberships.listen()
59
- * .then(() => {
60
- * console.log('listening to membership events');
61
- * webex.memberships.on('created', (event) => {
62
- * console.log(`Got a membership:created event:\n${event}`);
63
- * }
64
- * webex.memberships.on('updated', (event) => {
65
- * console.log(`Got a membership:updated event:\n${event}`);
66
- * }
67
- * webex.memberships.on('seen', (event) => {
68
- * // This represents a "read receipt" and will include a
69
- * // lastSeenId for the message this member has just "read",
70
- * // There is currently no equivalent webhook for this event.
71
- * console.log(`Got a membership:seen event:\n${event}`);
72
- * }
73
- * webex.memberships.on('deleted', (event) => => {
74
- * console.log(`Got a membership:created event:\n${event}`);
75
- * }
76
- * })
77
- * .catch((e) => console.error(`Unable to register for membership events: ${e}`));
78
- * // App logic goes here...
79
- * // Later when it is time to clean up
80
- * webex.memberships.stopListening();
81
- * webex.memberships.off('created');
82
- * webex.memberships.off('updated');
83
- * webex.memberships.off('seen');
84
- * webex.memberships.off('deleted');
85
-
86
- */
87
- listen() {
88
- // Create a common envelope that we will wrap all events in
89
- return createEventEnvelope(this.webex, SDK_EVENT.EXTERNAL.RESOURCE.MEMBERSHIPS).then(
90
- (envelope) => {
91
- this.eventEnvelope = envelope;
92
-
93
- // Register to listen to events
94
- return this.webex.internal.mercury.connect().then(() => {
95
- this.listenTo(this.webex.internal.mercury, SDK_EVENT.INTERNAL.WEBEX_ACTIVITY, (event) =>
96
- this.onWebexApiEvent(event)
97
- );
98
- });
99
- }
100
- );
101
- },
102
-
103
- /**
104
- * Adds a person to a room. The person can be added by ID (`personId`) or by
105
- * Email Address (`personEmail`). The person can be optionally added to the room
106
- * as a moderator.
107
- * @instance
108
- * @memberof Memberships
109
- * @param {MembershipObject} membership
110
- * @returns {Promise<MembershipObject>}
111
- * @example
112
- * webex.rooms.create({title: 'Create Membership Example'})
113
- * .then(function(room) {
114
- * return webex.memberships.create({
115
- * personEmail: 'alice@example.com',
116
- * roomId: room.id
117
- * });
118
- * })
119
- * .then(function(membership) {
120
- * var assert = require('assert');
121
- * assert(membership.id);
122
- * assert(membership.roomId);
123
- * assert(membership.personId);
124
- * assert(membership.personEmail);
125
- * assert('isModerator' in membership);
126
- * assert('isMonitor' in membership);
127
- * assert(membership.created);
128
- * return 'success';
129
- * });
130
- * // => success
131
- */
132
- create(membership) {
133
- return this.request({
134
- method: 'POST',
135
- service: 'hydra',
136
- resource: 'memberships',
137
- body: membership,
138
- }).then((res) => res.body);
139
- },
140
-
141
- /**
142
- * Returns a single membership.
143
- * @instance
144
- * @memberof Memberships
145
- * @param {MembershipObject|uuid} membership
146
- * @returns {Promise<MembershipObject>}
147
- * @example
148
- * var membership;
149
- * webex.rooms.create({title: 'Get Membership Example'})
150
- * .then(function(room) {
151
- * return webex.memberships.create({
152
- * personEmail: 'alice@example.com',
153
- * roomId: room.id
154
- * });
155
- * })
156
- * .then(function(m) {
157
- * membership = m;
158
- * return webex.memberships.get(m.id);
159
- * })
160
- * .then(function(m) {
161
- * var assert = require('assert');
162
- * assert.deepEqual(m, membership);
163
- * return 'success';
164
- * });
165
- * // => success
166
- */
167
- get(membership) {
168
- const id = membership.id || membership;
169
-
170
- return this.request({
171
- service: 'hydra',
172
- resource: `memberships/${id}`,
173
- }).then((res) => res.body.items || res.body);
174
- },
175
-
176
- /**
177
- * Returns a list of memberships. In most cases the results will only contain
178
- * rooms that the authenticated user is a member of. You can filter the results
179
- * by room to list people in a room or by person to find rooms that a
180
- * specific person is a member of.
181
- * @instance
182
- * @memberof Memberships
183
- * @param {Object} options
184
- * @param {string} options.personId
185
- * @param {string} options.personEmail
186
- * @param {string} options.roomId
187
- * @param {number} options.max
188
- * @returns {Promise<Page<MembershipObject>>}
189
- * @example
190
- * var room;
191
- * webex.rooms.create({title: 'List Membership Example'})
192
- * .then(function(r) {
193
- * room = r;
194
- * return webex.memberships.create({
195
- * personEmail: 'alice@example.com',
196
- * roomId: room.id
197
- * });
198
- * })
199
- * .then(function() {
200
- * return webex.memberships.list({roomId: room.id});
201
- * })
202
- * .then(function(memberships) {
203
- * var assert = require('assert');
204
- * assert.equal(memberships.length, 2);
205
- * for (var i = 0; i < memberships.length; i+= 1) {
206
- * assert.equal(memberships.items[i].roomId, room.id);
207
- * }
208
- * return 'success';
209
- * });
210
- * // => success
211
- */
212
- list(options) {
213
- return this.request({
214
- service: 'hydra',
215
- resource: 'memberships',
216
- qs: options,
217
- }).then((res) => new Page(res, this.webex));
218
- },
219
-
220
- /**
221
- * Returns a list of memberships with details about the lastSeenId for each
222
- * user, allowing a client to indicate "read status" in a space GUI
223
- *
224
- * This differs from the memberships.list() function in the following ways:
225
- * -- it accepts only a room or object with a valid roomId
226
- * -- no other options, eg: max, are considered
227
- * -- results are not paginated
228
- * -- memberships in the return do not include the
229
- * "created", "isRoomHidden", fields
230
- * -- memberships in the return do include the new
231
- * "lastSeenId", and "lastSeenDate" fields
232
- * these will not exist if the member has never "seen" the space
233
- *
234
- * In general this function should be used only when the
235
- * client needs to access read status info.
236
- *
237
- * This function may be deprecated when this info is provided in the membership
238
- * objects returned in the list function.
239
- *
240
- *
241
- * @instance
242
- * @memberof Memberships
243
- * @param {Object} options
244
- * @param {string} options.roomId
245
- * @returns {Promise<MembershipObjectList>}
246
- */
247
- listWithReadStatus(options) {
248
- const deconstructedId = deconstructHydraId(options.roomId);
249
- const conversation = {
250
- id: deconstructedId.id,
251
- cluster: deconstructedId.cluster,
252
- };
253
-
254
- return ensureMyIdIsAvailable(this.webex).then(() =>
255
- this.webex.internal.services.waitForCatalog('postauth').then(() =>
256
- this.webex.internal.conversation
257
- .get(conversation, {
258
- participantAckFilter: 'all', // show lastAck info for each participant
259
- activitiesLimit: 0, // don't send the whole history of activity
260
- })
261
- .then((resp) => {
262
- try {
263
- // We keep track of the last read message by each user
264
- const roomUUID = resp.id;
265
- const roomId = buildHydraRoomId(roomUUID, conversation.cluster);
266
- const participants = resp.participants.items;
267
- const lastReadInfo = {items: []};
268
- const roomType = getHydraRoomType(resp.tags);
269
- const myId = this.webex.internal.me.id;
270
- const isRoomHidden = resp.tags.includes(SDK_EVENT.INTERNAL.ACTIVITY_TAG.HIDDEN);
271
-
272
- for (let i = 0; i < participants.length; i += 1) {
273
- const participant = participants[i];
274
- const participantInfo = {
275
- id: buildHydraMembershipId(participant.entryUUID, roomUUID, conversation.cluster),
276
- roomId,
277
- personId: buildHydraPersonId(participant.entryUUID),
278
- personEmail: participant.entryEmailAddress || participant.entryEmail,
279
- personDisplayName: participant.displayName,
280
- personOrgId: buildHydraOrgId(participant.orgId, conversation.cluster),
281
- isMonitor: false, // deprecated, but included for completeness
282
- roomType,
283
- // created is not available in the conversations payload
284
- };
285
-
286
- if (isRoomHidden && participantInfo.personId === myId) {
287
- participantInfo.isRoomHidden = isRoomHidden;
288
- }
289
-
290
- if ('roomProperties' in participant) {
291
- if ('lastSeenActivityDate' in participant.roomProperties) {
292
- participantInfo.lastSeenId = buildHydraMessageId(
293
- participant.roomProperties.lastSeenActivityUUID,
294
- conversation.cluster
295
- );
296
- participantInfo.lastSeenDate = participant.roomProperties.lastSeenActivityDate;
297
- }
298
- if ('isModerator' in participant.roomProperties) {
299
- participantInfo.isModerator = participant.roomProperties.isModerator;
300
- }
301
- }
302
-
303
- lastReadInfo.items.push(participantInfo);
304
- }
305
-
306
- return Promise.resolve(lastReadInfo);
307
- } catch (e) {
308
- return Promise.reject(e);
309
- }
310
- })
311
- )
312
- );
313
- },
314
-
315
- /**
316
- * Deletes a single membership.
317
- * @instance
318
- * @memberof Memberships
319
- * @param {MembershipObject|uuid} membership
320
- * @returns {Promise}
321
- * @example
322
- * var membership, room;
323
- * webex.rooms.create({title: 'Remove Membership Example'})
324
- * .then(function(r) {
325
- * room = r;
326
- * return webex.memberships.create({
327
- * personEmail: 'alice@example.com',
328
- * roomId: room.id
329
- * });
330
- * })
331
- * .then(function(m) {
332
- * membership = m;
333
- * return webex.memberships.list({roomId: room.id});
334
- * })
335
- * .then(function(memberships) {
336
- * var assert = require('assert');
337
- * assert.equal(memberships.length, 2);
338
- * return webex.memberships.remove(membership);
339
- * })
340
- * .then(function() {
341
- * return webex.memberships.list({roomId: room.id});
342
- * })
343
- * .then(function(memberships) {
344
- * var assert = require('assert');
345
- * assert.equal(memberships.length, 1);
346
- * return 'success';
347
- * });
348
- * // => success
349
- */
350
- remove(membership) {
351
- const id = membership.id || membership;
352
-
353
- return this.request({
354
- method: 'DELETE',
355
- service: 'hydra',
356
- resource: `memberships/${id}`,
357
- }).then((res) => {
358
- // Firefox has some issues with 204s and/or DELETE. This should move to
359
- // http-core
360
- if (res.statusCode === 204) {
361
- return undefined;
362
- }
363
-
364
- return res.body;
365
- });
366
- },
367
-
368
- /**
369
- * Used to update a single membership's properties
370
- * @instance
371
- * @memberof Memberships
372
- * @param {MembershipObject|uuid} membership
373
- * @returns {Promise<MembershipObject>}
374
- * @example
375
- * // Change membership to make user a moderator
376
- * var membership, room;
377
- * webex.rooms.create({title: 'Memberships Example'})
378
- * .then(function(r) {
379
- * room = r;
380
- * return webex.memberships.list({roomId: room.id});
381
- * })
382
- * .then(function(memberships) {
383
- * membership = memberships.items[0];
384
- * var assert = require('assert');
385
- * assert.equal(membership.isModerator, false);
386
- * membership.isModerator = true;
387
- * return webex.memberships.update(membership);
388
- * })
389
- * .then(function() {
390
- * return webex.memberships.get(membership.id);
391
- * })
392
- * .then(function(membership) {
393
- * var assert = require('assert');
394
- * assert.equal(membership.isModerator, true);
395
- * return 'success';
396
- * });
397
- * // => success
398
- * @example
399
- * // Hide a one on one space
400
- * var assert = require('assert');
401
- * var membership, myId;
402
- * webex.people.get('me')
403
- * .then(function(person) {
404
- * myId = personId;
405
- * return webex.messages.create({
406
- * toPersonEmail: 'otherUser@acme.com',
407
- * text: 'This message will create a 1-1 space'
408
- * });
409
- * })
410
- * then(function(message) {
411
- * return webex.memberships.list({
412
- * roomId: message.roomId,
413
- * personId: myId
414
- * });
415
- * })
416
- * .then((memberships) => {
417
- * membership = memberships.items[0];
418
- * assert.equal(membership.isRoomHidden, false);
419
- * membership.isRoomHidden = true;
420
- * // This will generate a memberships:updated event
421
- * // that will only be seen by this user
422
- * return webex.memberships.update(membership);
423
- * })
424
- * .then(function(membership) {
425
- * assert.equal(membership.isRoomHidden, true);
426
- * return 'success';
427
- * });
428
- * // => success
429
- */
430
- update(membership) {
431
- const id = membership.id || membership;
432
-
433
- return this.request({
434
- method: 'PUT',
435
- service: 'hydra',
436
- resource: `memberships/${id}`,
437
- body: membership,
438
- }).then((res) => res.body);
439
- },
440
-
441
- /**
442
- * Updates the lastSeenId attribute of a membership.
443
- * Call this method to send a "read receipt" for a given message.
444
- * This will update the lastSeenId for the user's membership in
445
- * space where the message is.
446
- * @instance
447
- * @memberof Memberships
448
- * @param {string} message
449
- * @returns {Promise<MembershipObject>}
450
- */
451
- updateLastSeen(message) {
452
- const activity = {
453
- id: deconstructHydraId(message.id).id,
454
- };
455
- const deconstructedId = deconstructHydraId(message.roomId);
456
- const conversation = {
457
- id: deconstructedId.id,
458
- cluster: deconstructedId.cluster,
459
- };
460
-
461
- return this.webex.internal.services.waitForCatalog('postauth').then(() =>
462
- this.webex.internal.conversation.acknowledge(conversation, activity).then((ack) => ({
463
- lastSeenId: buildHydraMessageId(ack.object.id, conversation.cluster),
464
- id: buildHydraMembershipId(ack.actor.entryUUID, ack.target.id, conversation.cluster),
465
- personId: buildHydraPersonId(ack.actor.entryUUID, conversation.cluster),
466
- personEmail: ack.actor.emailAddress || ack.actor.entryEmail,
467
- personDisplayName: ack.actor.displayName,
468
- personOrgId: buildHydraOrgId(ack.actor.orgId, conversation.cluster),
469
- roomId: buildHydraRoomId(ack.target.id, conversation.cluster),
470
- roomType: getHydraRoomType(ack.target.tags),
471
- isRoomHidden: false, // any activity unhides a space.
472
- isMonitor: false, // deprecated, returned for back compat
473
- created: ack.published,
474
- }))
475
- );
476
- },
477
-
478
- /**
479
- * This function is called when an internal membership events fires,
480
- * if the user registered for these events with the public listen() method.
481
- * External users of the SDK should not call this function
482
- * @private
483
- * @memberof Memberships
484
- * @param {Object} event
485
- * @returns {void}
486
- */
487
- onWebexApiEvent(event) {
488
- const {activity} = event.data;
489
-
490
- /* eslint-disable no-case-declarations */
491
- switch (activity.verb) {
492
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.CREATE:
493
- const membershipCreatedEventDataArray = activity.object.participants.items.map(
494
- (participant) => {
495
- const output = cloneDeep(activity);
496
-
497
- output.target = cloneDeep(activity.object);
498
- output.object = cloneDeep(participant);
499
-
500
- return this.getMembershipEvent(output, SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED);
501
- }
502
- );
503
-
504
- membershipCreatedEventDataArray.forEach((data) => {
505
- if (data) {
506
- debug(`membership "created" payload: ${JSON.stringify(data)}`);
507
- this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED, data);
508
- }
509
- });
510
- break;
511
-
512
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ADD:
513
- const membershipCreatedEventData = this.getMembershipEvent(
514
- activity,
515
- SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED
516
- );
517
-
518
- if (membershipCreatedEventData) {
519
- debug(`membership "created" payload: \
520
- ${JSON.stringify(membershipCreatedEventData)}`);
521
- this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED, membershipCreatedEventData);
522
- }
523
- break;
524
-
525
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.LEAVE:
526
- const membershipDeletedEventData = this.getMembershipEvent(
527
- activity,
528
- SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED
529
- );
530
-
531
- if (membershipDeletedEventData) {
532
- debug(`membership "deleted" payload: \
533
- ${JSON.stringify(membershipDeletedEventData)}`);
534
- this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED, membershipDeletedEventData);
535
- }
536
- break;
537
-
538
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ADD_MODERATOR:
539
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.REMOVE_MODERATOR:
540
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE:
541
- const membershipUpdatedEventData = this.getMembershipEvent(
542
- activity,
543
- SDK_EVENT.EXTERNAL.EVENT_TYPE.UPDATED
544
- );
545
-
546
- if (membershipUpdatedEventData) {
547
- debug(`membership "updated" payload: \
548
- ${JSON.stringify(membershipUpdatedEventData)}`);
549
- this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.UPDATED, membershipUpdatedEventData);
550
- }
551
- break;
552
-
553
- case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE:
554
- const membershipSeenEventData = this.getMembershipEvent(
555
- activity,
556
- SDK_EVENT.EXTERNAL.EVENT_TYPE.SEEN
557
- );
558
-
559
- if (membershipSeenEventData) {
560
- debug(`membership "updated" payload: \
561
- ${JSON.stringify(membershipSeenEventData)}`);
562
- this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.SEEN, membershipSeenEventData);
563
- }
564
- break;
565
-
566
- default:
567
- break;
568
- }
569
- },
570
-
571
- /**
572
- * Constructs the data object for an event on the memberships resource,
573
- * adhering to Hydra's Webhook data structure memberships.
574
- * External users of the SDK should not call this function
575
- * @private
576
- * @memberof Memberships
577
- * @param {Object} activity from mercury
578
- * @param {Object} event type of "webhook" event
579
- * @returns {Object} constructed event
580
- */
581
- getMembershipEvent(activity, event) {
582
- try {
583
- const sdkEvent = cloneDeep(this.eventEnvelope);
584
- const cluster =
585
- activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE
586
- ? getHydraClusterString(this.webex, activity.target.url)
587
- : getHydraClusterString(this.webex, activity.url);
588
- let member;
589
- let space;
590
-
591
- sdkEvent.event = event;
592
- sdkEvent.data.created = activity.published;
593
- sdkEvent.actorId = buildHydraPersonId(activity.actor.entryUUID, cluster);
594
- if (activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE) {
595
- sdkEvent.data.roomId = buildHydraRoomId(activity.target.id, cluster);
596
- sdkEvent.data.roomType = getHydraRoomType(activity.target.tags);
597
- sdkEvent.data.isRoomHidden = false; // any activity unhides a space.
598
- } else {
599
- sdkEvent.data.roomId = buildHydraRoomId(activity.object.id, cluster);
600
- sdkEvent.data.roomType = SDK_EVENT.EXTERNAL.SPACE_TYPE.DIRECT;
601
- // currently hidden attribute is only set on 1-1
602
- sdkEvent.data.isRoomHidden = true;
603
- }
604
- if (activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE) {
605
- if (activity.object.roomProperties && activity.object.roomProperties.isModerator) {
606
- sdkEvent.data.isModerator = true;
607
- } else {
608
- sdkEvent.data.isModerator = false;
609
- }
610
- }
611
- // This is deprecated but still sent in the webhooks
612
- // We won't send it for our new SDK events
613
- // sdkEvent.data.isMonitor = false;
614
-
615
- if (activity.verb === SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE) {
616
- // For a read receipt the person is the "actor" or the one who did the reading
617
- member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.ACTOR;
618
- // The space with the read message is the "target"
619
- space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.TARGET;
620
- // And the "object" is the message that was last seen
621
- sdkEvent.data.lastSeenId = buildHydraMessageId(activity.object.id, cluster);
622
- } else if (activity.verb === SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE) {
623
- // For a hide activity the person is also the "actor"
624
- member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.ACTOR;
625
- // But the space is now the "object"
626
- space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.OBJECT;
627
- } else {
628
- // For most memberships events the person is the 'object"
629
- member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.OBJECT;
630
- // and the space is the "target"
631
- space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.TARGET;
632
- }
633
-
634
- sdkEvent.data.id = buildHydraMembershipId(
635
- activity[member].entryUUID,
636
- activity[space].id,
637
- cluster
638
- );
639
- sdkEvent.data.personId = buildHydraPersonId(activity[member].entryUUID, cluster);
640
- sdkEvent.data.personEmail = activity[member].emailAddress || activity[member].entryEmail;
641
- sdkEvent.data.personDisplayName = activity[member].displayName;
642
- sdkEvent.data.personOrgId = buildHydraOrgId(activity[member].orgId, cluster);
643
-
644
- return sdkEvent;
645
- } catch (e) {
646
- this.webex.logger.error(`Unable to generate SDK event from mercury \
647
- 'socket activity for memberships:${event} event: ${e.message}`);
648
-
649
- return null;
650
- }
651
- },
652
- });
653
-
654
- export default Memberships;
1
+ /*!
2
+ * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
+ */
4
+
5
+ import {
6
+ SDK_EVENT,
7
+ createEventEnvelope,
8
+ ensureMyIdIsAvailable,
9
+ buildHydraMembershipId,
10
+ buildHydraMessageId,
11
+ buildHydraOrgId,
12
+ buildHydraPersonId,
13
+ buildHydraRoomId,
14
+ getHydraClusterString,
15
+ getHydraRoomType,
16
+ deconstructHydraId,
17
+ } from '@webex/common';
18
+ import {WebexPlugin, Page} from '@webex/webex-core';
19
+ import {cloneDeep} from 'lodash';
20
+
21
+ const debug = require('debug')('memberships');
22
+
23
+ /**
24
+ * @typedef {Object} MembershipObject
25
+ * @property {string} id - Unique identifier for the membership
26
+ * @property {string} roomId - The room ID
27
+ * @property {string} personId - The person ID
28
+ * @property {email} personEmail - The email address of the person / room member
29
+ * @property {boolean} isModerator - Indicates whether the specified person should be a room moderator
30
+ * @property {boolean} isMonitor - Indicates whether the specified member is a room monitor
31
+ * @property {isoDate} created - The date and time that this membership was created
32
+ */
33
+
34
+ /**
35
+ * Memberships represent a person's relationship to a room. Use this API to list
36
+ * members of any room that you're in or create memberships to invite someone
37
+ * to a room. Memberships can also be updated to make someone a moderator
38
+ * or deleted to remove them from the room.
39
+ * @class
40
+ * @name Memberships
41
+ */
42
+ const Memberships = WebexPlugin.extend({
43
+ /**
44
+ * Register to listen for incoming membership events
45
+ * This is an alternate approach to registering for membership webhooks.
46
+ * The events passed to any registered handlers will be similar to the webhook JSON,
47
+ * but will omit webhook specific fields such as name, secret, url, etc.
48
+ * To utilize the `listen()` method, the authorization token used
49
+ * will need to have `spark:all` and `spark:kms` scopes enabled.
50
+ * Note that by configuring your application to enable or disable `spark:all`
51
+ * via its configuration page will also enable or disable `spark:kms`.
52
+ * See the <a href="https://webex.github.io/webex-js-sdk/samples/browser-socket/">Sample App</a>
53
+ * for more details.
54
+ * @instance
55
+ * @memberof Memberships
56
+ * @returns {Promise}
57
+ * @example
58
+ * webex.memberships.listen()
59
+ * .then(() => {
60
+ * console.log('listening to membership events');
61
+ * webex.memberships.on('created', (event) => {
62
+ * console.log(`Got a membership:created event:\n${event}`);
63
+ * }
64
+ * webex.memberships.on('updated', (event) => {
65
+ * console.log(`Got a membership:updated event:\n${event}`);
66
+ * }
67
+ * webex.memberships.on('seen', (event) => {
68
+ * // This represents a "read receipt" and will include a
69
+ * // lastSeenId for the message this member has just "read",
70
+ * // There is currently no equivalent webhook for this event.
71
+ * console.log(`Got a membership:seen event:\n${event}`);
72
+ * }
73
+ * webex.memberships.on('deleted', (event) => => {
74
+ * console.log(`Got a membership:created event:\n${event}`);
75
+ * }
76
+ * })
77
+ * .catch((e) => console.error(`Unable to register for membership events: ${e}`));
78
+ * // App logic goes here...
79
+ * // Later when it is time to clean up
80
+ * webex.memberships.stopListening();
81
+ * webex.memberships.off('created');
82
+ * webex.memberships.off('updated');
83
+ * webex.memberships.off('seen');
84
+ * webex.memberships.off('deleted');
85
+
86
+ */
87
+ listen() {
88
+ // Create a common envelope that we will wrap all events in
89
+ return createEventEnvelope(this.webex, SDK_EVENT.EXTERNAL.RESOURCE.MEMBERSHIPS).then(
90
+ (envelope) => {
91
+ this.eventEnvelope = envelope;
92
+
93
+ // Register to listen to events
94
+ return this.webex.internal.mercury.connect().then(() => {
95
+ this.listenTo(this.webex.internal.mercury, SDK_EVENT.INTERNAL.WEBEX_ACTIVITY, (event) =>
96
+ this.onWebexApiEvent(event)
97
+ );
98
+ });
99
+ }
100
+ );
101
+ },
102
+
103
+ /**
104
+ * Adds a person to a room. The person can be added by ID (`personId`) or by
105
+ * Email Address (`personEmail`). The person can be optionally added to the room
106
+ * as a moderator.
107
+ * @instance
108
+ * @memberof Memberships
109
+ * @param {MembershipObject} membership
110
+ * @returns {Promise<MembershipObject>}
111
+ * @example
112
+ * webex.rooms.create({title: 'Create Membership Example'})
113
+ * .then(function(room) {
114
+ * return webex.memberships.create({
115
+ * personEmail: 'alice@example.com',
116
+ * roomId: room.id
117
+ * });
118
+ * })
119
+ * .then(function(membership) {
120
+ * var assert = require('assert');
121
+ * assert(membership.id);
122
+ * assert(membership.roomId);
123
+ * assert(membership.personId);
124
+ * assert(membership.personEmail);
125
+ * assert('isModerator' in membership);
126
+ * assert('isMonitor' in membership);
127
+ * assert(membership.created);
128
+ * return 'success';
129
+ * });
130
+ * // => success
131
+ */
132
+ create(membership) {
133
+ return this.request({
134
+ method: 'POST',
135
+ service: 'hydra',
136
+ resource: 'memberships',
137
+ body: membership,
138
+ }).then((res) => res.body);
139
+ },
140
+
141
+ /**
142
+ * Returns a single membership.
143
+ * @instance
144
+ * @memberof Memberships
145
+ * @param {MembershipObject|uuid} membership
146
+ * @returns {Promise<MembershipObject>}
147
+ * @example
148
+ * var membership;
149
+ * webex.rooms.create({title: 'Get Membership Example'})
150
+ * .then(function(room) {
151
+ * return webex.memberships.create({
152
+ * personEmail: 'alice@example.com',
153
+ * roomId: room.id
154
+ * });
155
+ * })
156
+ * .then(function(m) {
157
+ * membership = m;
158
+ * return webex.memberships.get(m.id);
159
+ * })
160
+ * .then(function(m) {
161
+ * var assert = require('assert');
162
+ * assert.deepEqual(m, membership);
163
+ * return 'success';
164
+ * });
165
+ * // => success
166
+ */
167
+ get(membership) {
168
+ const id = membership.id || membership;
169
+
170
+ return this.request({
171
+ service: 'hydra',
172
+ resource: `memberships/${id}`,
173
+ }).then((res) => res.body.items || res.body);
174
+ },
175
+
176
+ /**
177
+ * Returns a list of memberships. In most cases the results will only contain
178
+ * rooms that the authenticated user is a member of. You can filter the results
179
+ * by room to list people in a room or by person to find rooms that a
180
+ * specific person is a member of.
181
+ * @instance
182
+ * @memberof Memberships
183
+ * @param {Object} options
184
+ * @param {string} options.personId
185
+ * @param {string} options.personEmail
186
+ * @param {string} options.roomId
187
+ * @param {number} options.max
188
+ * @returns {Promise<Page<MembershipObject>>}
189
+ * @example
190
+ * var room;
191
+ * webex.rooms.create({title: 'List Membership Example'})
192
+ * .then(function(r) {
193
+ * room = r;
194
+ * return webex.memberships.create({
195
+ * personEmail: 'alice@example.com',
196
+ * roomId: room.id
197
+ * });
198
+ * })
199
+ * .then(function() {
200
+ * return webex.memberships.list({roomId: room.id});
201
+ * })
202
+ * .then(function(memberships) {
203
+ * var assert = require('assert');
204
+ * assert.equal(memberships.length, 2);
205
+ * for (var i = 0; i < memberships.length; i+= 1) {
206
+ * assert.equal(memberships.items[i].roomId, room.id);
207
+ * }
208
+ * return 'success';
209
+ * });
210
+ * // => success
211
+ */
212
+ list(options) {
213
+ return this.request({
214
+ service: 'hydra',
215
+ resource: 'memberships',
216
+ qs: options,
217
+ }).then((res) => new Page(res, this.webex));
218
+ },
219
+
220
+ /**
221
+ * Returns a list of memberships with details about the lastSeenId for each
222
+ * user, allowing a client to indicate "read status" in a space GUI
223
+ *
224
+ * This differs from the memberships.list() function in the following ways:
225
+ * -- it accepts only a room or object with a valid roomId
226
+ * -- no other options, eg: max, are considered
227
+ * -- results are not paginated
228
+ * -- memberships in the return do not include the
229
+ * "created", "isRoomHidden", fields
230
+ * -- memberships in the return do include the new
231
+ * "lastSeenId", and "lastSeenDate" fields
232
+ * these will not exist if the member has never "seen" the space
233
+ *
234
+ * In general this function should be used only when the
235
+ * client needs to access read status info.
236
+ *
237
+ * This function may be deprecated when this info is provided in the membership
238
+ * objects returned in the list function.
239
+ *
240
+ *
241
+ * @instance
242
+ * @memberof Memberships
243
+ * @param {Object} options
244
+ * @param {string} options.roomId
245
+ * @returns {Promise<MembershipObjectList>}
246
+ */
247
+ listWithReadStatus(options) {
248
+ const deconstructedId = deconstructHydraId(options.roomId);
249
+ const conversation = {
250
+ id: deconstructedId.id,
251
+ cluster: deconstructedId.cluster,
252
+ };
253
+
254
+ return ensureMyIdIsAvailable(this.webex).then(() =>
255
+ this.webex.internal.services.waitForCatalog('postauth').then(() =>
256
+ this.webex.internal.conversation
257
+ .get(conversation, {
258
+ participantAckFilter: 'all', // show lastAck info for each participant
259
+ activitiesLimit: 0, // don't send the whole history of activity
260
+ })
261
+ .then((resp) => {
262
+ try {
263
+ // We keep track of the last read message by each user
264
+ const roomUUID = resp.id;
265
+ const roomId = buildHydraRoomId(roomUUID, conversation.cluster);
266
+ const participants = resp.participants.items;
267
+ const lastReadInfo = {items: []};
268
+ const roomType = getHydraRoomType(resp.tags);
269
+ const myId = this.webex.internal.me.id;
270
+ const isRoomHidden = resp.tags.includes(SDK_EVENT.INTERNAL.ACTIVITY_TAG.HIDDEN);
271
+
272
+ for (let i = 0; i < participants.length; i += 1) {
273
+ const participant = participants[i];
274
+ const participantInfo = {
275
+ id: buildHydraMembershipId(participant.entryUUID, roomUUID, conversation.cluster),
276
+ roomId,
277
+ personId: buildHydraPersonId(participant.entryUUID),
278
+ personEmail: participant.entryEmailAddress || participant.entryEmail,
279
+ personDisplayName: participant.displayName,
280
+ personOrgId: buildHydraOrgId(participant.orgId, conversation.cluster),
281
+ isMonitor: false, // deprecated, but included for completeness
282
+ roomType,
283
+ // created is not available in the conversations payload
284
+ };
285
+
286
+ if (isRoomHidden && participantInfo.personId === myId) {
287
+ participantInfo.isRoomHidden = isRoomHidden;
288
+ }
289
+
290
+ if ('roomProperties' in participant) {
291
+ if ('lastSeenActivityDate' in participant.roomProperties) {
292
+ participantInfo.lastSeenId = buildHydraMessageId(
293
+ participant.roomProperties.lastSeenActivityUUID,
294
+ conversation.cluster
295
+ );
296
+ participantInfo.lastSeenDate = participant.roomProperties.lastSeenActivityDate;
297
+ }
298
+ if ('isModerator' in participant.roomProperties) {
299
+ participantInfo.isModerator = participant.roomProperties.isModerator;
300
+ }
301
+ }
302
+
303
+ lastReadInfo.items.push(participantInfo);
304
+ }
305
+
306
+ return Promise.resolve(lastReadInfo);
307
+ } catch (e) {
308
+ return Promise.reject(e);
309
+ }
310
+ })
311
+ )
312
+ );
313
+ },
314
+
315
+ /**
316
+ * Deletes a single membership.
317
+ * @instance
318
+ * @memberof Memberships
319
+ * @param {MembershipObject|uuid} membership
320
+ * @returns {Promise}
321
+ * @example
322
+ * var membership, room;
323
+ * webex.rooms.create({title: 'Remove Membership Example'})
324
+ * .then(function(r) {
325
+ * room = r;
326
+ * return webex.memberships.create({
327
+ * personEmail: 'alice@example.com',
328
+ * roomId: room.id
329
+ * });
330
+ * })
331
+ * .then(function(m) {
332
+ * membership = m;
333
+ * return webex.memberships.list({roomId: room.id});
334
+ * })
335
+ * .then(function(memberships) {
336
+ * var assert = require('assert');
337
+ * assert.equal(memberships.length, 2);
338
+ * return webex.memberships.remove(membership);
339
+ * })
340
+ * .then(function() {
341
+ * return webex.memberships.list({roomId: room.id});
342
+ * })
343
+ * .then(function(memberships) {
344
+ * var assert = require('assert');
345
+ * assert.equal(memberships.length, 1);
346
+ * return 'success';
347
+ * });
348
+ * // => success
349
+ */
350
+ remove(membership) {
351
+ const id = membership.id || membership;
352
+
353
+ return this.request({
354
+ method: 'DELETE',
355
+ service: 'hydra',
356
+ resource: `memberships/${id}`,
357
+ }).then((res) => {
358
+ // Firefox has some issues with 204s and/or DELETE. This should move to
359
+ // http-core
360
+ if (res.statusCode === 204) {
361
+ return undefined;
362
+ }
363
+
364
+ return res.body;
365
+ });
366
+ },
367
+
368
+ /**
369
+ * Used to update a single membership's properties
370
+ * @instance
371
+ * @memberof Memberships
372
+ * @param {MembershipObject|uuid} membership
373
+ * @returns {Promise<MembershipObject>}
374
+ * @example
375
+ * // Change membership to make user a moderator
376
+ * var membership, room;
377
+ * webex.rooms.create({title: 'Memberships Example'})
378
+ * .then(function(r) {
379
+ * room = r;
380
+ * return webex.memberships.list({roomId: room.id});
381
+ * })
382
+ * .then(function(memberships) {
383
+ * membership = memberships.items[0];
384
+ * var assert = require('assert');
385
+ * assert.equal(membership.isModerator, false);
386
+ * membership.isModerator = true;
387
+ * return webex.memberships.update(membership);
388
+ * })
389
+ * .then(function() {
390
+ * return webex.memberships.get(membership.id);
391
+ * })
392
+ * .then(function(membership) {
393
+ * var assert = require('assert');
394
+ * assert.equal(membership.isModerator, true);
395
+ * return 'success';
396
+ * });
397
+ * // => success
398
+ * @example
399
+ * // Hide a one on one space
400
+ * var assert = require('assert');
401
+ * var membership, myId;
402
+ * webex.people.get('me')
403
+ * .then(function(person) {
404
+ * myId = personId;
405
+ * return webex.messages.create({
406
+ * toPersonEmail: 'otherUser@acme.com',
407
+ * text: 'This message will create a 1-1 space'
408
+ * });
409
+ * })
410
+ * then(function(message) {
411
+ * return webex.memberships.list({
412
+ * roomId: message.roomId,
413
+ * personId: myId
414
+ * });
415
+ * })
416
+ * .then((memberships) => {
417
+ * membership = memberships.items[0];
418
+ * assert.equal(membership.isRoomHidden, false);
419
+ * membership.isRoomHidden = true;
420
+ * // This will generate a memberships:updated event
421
+ * // that will only be seen by this user
422
+ * return webex.memberships.update(membership);
423
+ * })
424
+ * .then(function(membership) {
425
+ * assert.equal(membership.isRoomHidden, true);
426
+ * return 'success';
427
+ * });
428
+ * // => success
429
+ */
430
+ update(membership) {
431
+ const id = membership.id || membership;
432
+
433
+ return this.request({
434
+ method: 'PUT',
435
+ service: 'hydra',
436
+ resource: `memberships/${id}`,
437
+ body: membership,
438
+ }).then((res) => res.body);
439
+ },
440
+
441
+ /**
442
+ * Updates the lastSeenId attribute of a membership.
443
+ * Call this method to send a "read receipt" for a given message.
444
+ * This will update the lastSeenId for the user's membership in
445
+ * space where the message is.
446
+ * @instance
447
+ * @memberof Memberships
448
+ * @param {string} message
449
+ * @returns {Promise<MembershipObject>}
450
+ */
451
+ updateLastSeen(message) {
452
+ const activity = {
453
+ id: deconstructHydraId(message.id).id,
454
+ };
455
+ const deconstructedId = deconstructHydraId(message.roomId);
456
+ const conversation = {
457
+ id: deconstructedId.id,
458
+ cluster: deconstructedId.cluster,
459
+ };
460
+
461
+ return this.webex.internal.services.waitForCatalog('postauth').then(() =>
462
+ this.webex.internal.conversation.acknowledge(conversation, activity).then((ack) => ({
463
+ lastSeenId: buildHydraMessageId(ack.object.id, conversation.cluster),
464
+ id: buildHydraMembershipId(ack.actor.entryUUID, ack.target.id, conversation.cluster),
465
+ personId: buildHydraPersonId(ack.actor.entryUUID, conversation.cluster),
466
+ personEmail: ack.actor.emailAddress || ack.actor.entryEmail,
467
+ personDisplayName: ack.actor.displayName,
468
+ personOrgId: buildHydraOrgId(ack.actor.orgId, conversation.cluster),
469
+ roomId: buildHydraRoomId(ack.target.id, conversation.cluster),
470
+ roomType: getHydraRoomType(ack.target.tags),
471
+ isRoomHidden: false, // any activity unhides a space.
472
+ isMonitor: false, // deprecated, returned for back compat
473
+ created: ack.published,
474
+ }))
475
+ );
476
+ },
477
+
478
+ /**
479
+ * This function is called when an internal membership events fires,
480
+ * if the user registered for these events with the public listen() method.
481
+ * External users of the SDK should not call this function
482
+ * @private
483
+ * @memberof Memberships
484
+ * @param {Object} event
485
+ * @returns {void}
486
+ */
487
+ onWebexApiEvent(event) {
488
+ const {activity} = event.data;
489
+
490
+ /* eslint-disable no-case-declarations */
491
+ switch (activity.verb) {
492
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.CREATE:
493
+ const membershipCreatedEventDataArray = activity.object.participants.items.map(
494
+ (participant) => {
495
+ const output = cloneDeep(activity);
496
+
497
+ output.target = cloneDeep(activity.object);
498
+ output.object = cloneDeep(participant);
499
+
500
+ return this.getMembershipEvent(output, SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED);
501
+ }
502
+ );
503
+
504
+ membershipCreatedEventDataArray.forEach((data) => {
505
+ if (data) {
506
+ debug(`membership "created" payload: ${JSON.stringify(data)}`);
507
+ this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED, data);
508
+ }
509
+ });
510
+ break;
511
+
512
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ADD:
513
+ const membershipCreatedEventData = this.getMembershipEvent(
514
+ activity,
515
+ SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED
516
+ );
517
+
518
+ if (membershipCreatedEventData) {
519
+ debug(`membership "created" payload: \
520
+ ${JSON.stringify(membershipCreatedEventData)}`);
521
+ this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.CREATED, membershipCreatedEventData);
522
+ }
523
+ break;
524
+
525
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.LEAVE:
526
+ const membershipDeletedEventData = this.getMembershipEvent(
527
+ activity,
528
+ SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED
529
+ );
530
+
531
+ if (membershipDeletedEventData) {
532
+ debug(`membership "deleted" payload: \
533
+ ${JSON.stringify(membershipDeletedEventData)}`);
534
+ this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.DELETED, membershipDeletedEventData);
535
+ }
536
+ break;
537
+
538
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ADD_MODERATOR:
539
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.REMOVE_MODERATOR:
540
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE:
541
+ const membershipUpdatedEventData = this.getMembershipEvent(
542
+ activity,
543
+ SDK_EVENT.EXTERNAL.EVENT_TYPE.UPDATED
544
+ );
545
+
546
+ if (membershipUpdatedEventData) {
547
+ debug(`membership "updated" payload: \
548
+ ${JSON.stringify(membershipUpdatedEventData)}`);
549
+ this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.UPDATED, membershipUpdatedEventData);
550
+ }
551
+ break;
552
+
553
+ case SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE:
554
+ const membershipSeenEventData = this.getMembershipEvent(
555
+ activity,
556
+ SDK_EVENT.EXTERNAL.EVENT_TYPE.SEEN
557
+ );
558
+
559
+ if (membershipSeenEventData) {
560
+ debug(`membership "updated" payload: \
561
+ ${JSON.stringify(membershipSeenEventData)}`);
562
+ this.trigger(SDK_EVENT.EXTERNAL.EVENT_TYPE.SEEN, membershipSeenEventData);
563
+ }
564
+ break;
565
+
566
+ default:
567
+ break;
568
+ }
569
+ },
570
+
571
+ /**
572
+ * Constructs the data object for an event on the memberships resource,
573
+ * adhering to Hydra's Webhook data structure memberships.
574
+ * External users of the SDK should not call this function
575
+ * @private
576
+ * @memberof Memberships
577
+ * @param {Object} activity from mercury
578
+ * @param {Object} event type of "webhook" event
579
+ * @returns {Object} constructed event
580
+ */
581
+ getMembershipEvent(activity, event) {
582
+ try {
583
+ const sdkEvent = cloneDeep(this.eventEnvelope);
584
+ const cluster =
585
+ activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE
586
+ ? getHydraClusterString(this.webex, activity.target.url)
587
+ : getHydraClusterString(this.webex, activity.url);
588
+ let member;
589
+ let space;
590
+
591
+ sdkEvent.event = event;
592
+ sdkEvent.data.created = activity.published;
593
+ sdkEvent.actorId = buildHydraPersonId(activity.actor.entryUUID, cluster);
594
+ if (activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE) {
595
+ sdkEvent.data.roomId = buildHydraRoomId(activity.target.id, cluster);
596
+ sdkEvent.data.roomType = getHydraRoomType(activity.target.tags);
597
+ sdkEvent.data.isRoomHidden = false; // any activity unhides a space.
598
+ } else {
599
+ sdkEvent.data.roomId = buildHydraRoomId(activity.object.id, cluster);
600
+ sdkEvent.data.roomType = SDK_EVENT.EXTERNAL.SPACE_TYPE.DIRECT;
601
+ // currently hidden attribute is only set on 1-1
602
+ sdkEvent.data.isRoomHidden = true;
603
+ }
604
+ if (activity.verb !== SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE) {
605
+ if (activity.object.roomProperties && activity.object.roomProperties.isModerator) {
606
+ sdkEvent.data.isModerator = true;
607
+ } else {
608
+ sdkEvent.data.isModerator = false;
609
+ }
610
+ }
611
+ // This is deprecated but still sent in the webhooks
612
+ // We won't send it for our new SDK events
613
+ // sdkEvent.data.isMonitor = false;
614
+
615
+ if (activity.verb === SDK_EVENT.INTERNAL.ACTIVITY_VERB.ACKNOWLEDGE) {
616
+ // For a read receipt the person is the "actor" or the one who did the reading
617
+ member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.ACTOR;
618
+ // The space with the read message is the "target"
619
+ space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.TARGET;
620
+ // And the "object" is the message that was last seen
621
+ sdkEvent.data.lastSeenId = buildHydraMessageId(activity.object.id, cluster);
622
+ } else if (activity.verb === SDK_EVENT.INTERNAL.ACTIVITY_VERB.HIDE) {
623
+ // For a hide activity the person is also the "actor"
624
+ member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.ACTOR;
625
+ // But the space is now the "object"
626
+ space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.OBJECT;
627
+ } else {
628
+ // For most memberships events the person is the 'object"
629
+ member = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.OBJECT;
630
+ // and the space is the "target"
631
+ space = SDK_EVENT.INTERNAL.ACTIVITY_FIELD.TARGET;
632
+ }
633
+
634
+ sdkEvent.data.id = buildHydraMembershipId(
635
+ activity[member].entryUUID,
636
+ activity[space].id,
637
+ cluster
638
+ );
639
+ sdkEvent.data.personId = buildHydraPersonId(activity[member].entryUUID, cluster);
640
+ sdkEvent.data.personEmail = activity[member].emailAddress || activity[member].entryEmail;
641
+ sdkEvent.data.personDisplayName = activity[member].displayName;
642
+ sdkEvent.data.personOrgId = buildHydraOrgId(activity[member].orgId, cluster);
643
+
644
+ return sdkEvent;
645
+ } catch (e) {
646
+ this.webex.logger.error(`Unable to generate SDK event from mercury \
647
+ 'socket activity for memberships:${event} event: ${e.message}`);
648
+
649
+ return null;
650
+ }
651
+ },
652
+ });
653
+
654
+ export default Memberships;