@webex/plugin-meetings 3.9.0-next.13 → 3.9.0-next.15
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/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +11 -4
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +13 -0
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +25 -0
- package/dist/meeting/request.js.map +1 -1
- package/dist/member/types.js.map +1 -1
- package/dist/members/collection.js +13 -0
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +39 -18
- package/dist/members/index.js.map +1 -1
- package/dist/types/locus-info/index.d.ts +2 -1
- package/dist/types/meeting/index.d.ts +8 -0
- package/dist/types/meeting/request.d.ts +9 -0
- package/dist/types/member/types.d.ts +1 -0
- package/dist/types/members/collection.d.ts +6 -0
- package/dist/types/members/index.d.ts +10 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +1 -1
- package/src/locus-info/index.ts +16 -4
- package/src/meeting/index.ts +16 -0
- package/src/meeting/request.ts +23 -0
- package/src/member/types.ts +1 -0
- package/src/members/collection.ts +11 -0
- package/src/members/index.ts +29 -3
- package/test/unit/spec/locus-info/index.js +11 -8
- package/test/unit/spec/meeting/index.js +26 -0
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +42 -1
package/src/members/index.ts
CHANGED
@@ -74,7 +74,11 @@ import {Invitee} from '../meeting/type';
|
|
74
74
|
* @memberof Members
|
75
75
|
*/
|
76
76
|
|
77
|
-
type UpdatedMembers = {
|
77
|
+
type UpdatedMembers = {
|
78
|
+
added: Array<Member>;
|
79
|
+
updated: Array<Member>;
|
80
|
+
removedIds?: Array<string>; // removed member ids
|
81
|
+
};
|
78
82
|
/**
|
79
83
|
* @class Members
|
80
84
|
*/
|
@@ -384,12 +388,18 @@ export default class Members extends StatelessWebexPlugin {
|
|
384
388
|
* when new participant updates come in, both delta and full participants, update them in members collection
|
385
389
|
* delta object in the event will have {updated, added} and full will be the full membersCollection
|
386
390
|
* @param {Object} payload
|
387
|
-
* @param {Object} payload.participants
|
391
|
+
* @param {Object} payload.participants new/updated participants
|
392
|
+
* @param {Boolean} payload.isReplace whether to replace the whole members collection
|
393
|
+
* @param {Object} payload.removedParticipantIds ids of the removed participants
|
388
394
|
* @returns {undefined}
|
389
395
|
* @private
|
390
396
|
* @memberof Members
|
391
397
|
*/
|
392
|
-
locusParticipantsUpdate(payload: {
|
398
|
+
locusParticipantsUpdate(payload: {
|
399
|
+
participants: object;
|
400
|
+
isReplace?: boolean;
|
401
|
+
removedParticipantIds?: Array<string>;
|
402
|
+
}) {
|
393
403
|
if (payload) {
|
394
404
|
if (payload.isReplace) {
|
395
405
|
this.clearMembers();
|
@@ -547,10 +557,22 @@ export default class Members extends StatelessWebexPlugin {
|
|
547
557
|
private handleMembersUpdate(membersUpdate: UpdatedMembers) {
|
548
558
|
this.constructMembers(membersUpdate.updated, true);
|
549
559
|
this.constructMembers(membersUpdate.added, false);
|
560
|
+
this.removeMembers(membersUpdate.removedIds);
|
550
561
|
|
551
562
|
return this.membersCollection.getAll();
|
552
563
|
}
|
553
564
|
|
565
|
+
/**
|
566
|
+
* removes members from the collection
|
567
|
+
* @param {Array<string>} removedMembers removed members ids
|
568
|
+
* @returns {void}
|
569
|
+
*/
|
570
|
+
private removeMembers(removedMembers: Array<string>) {
|
571
|
+
removedMembers.forEach((memberId) => {
|
572
|
+
this.membersCollection.remove(memberId);
|
573
|
+
});
|
574
|
+
}
|
575
|
+
|
554
576
|
/**
|
555
577
|
* set members to the member collection from each updated/added lists as passed in
|
556
578
|
* @param {Array} list
|
@@ -600,6 +622,10 @@ export default class Members extends StatelessWebexPlugin {
|
|
600
622
|
}
|
601
623
|
const memberUpdate = this.update(payload.participants);
|
602
624
|
|
625
|
+
// this code depends on memberIds being the same as participantIds
|
626
|
+
// if MemberUtil.extractId() ever changes, this will need to be updated
|
627
|
+
memberUpdate.removedIds = payload.removedParticipantIds || [];
|
628
|
+
|
603
629
|
return memberUpdate;
|
604
630
|
}
|
605
631
|
|
@@ -772,7 +772,7 @@ describe('plugin-meetings', () => {
|
|
772
772
|
},
|
773
773
|
};
|
774
774
|
locusInfo.emitScoped = sinon.stub();
|
775
|
-
locusInfo.updateParticipants({});
|
775
|
+
locusInfo.updateParticipants({}, []);
|
776
776
|
|
777
777
|
// if this assertion fails, double-check the attributes used in
|
778
778
|
// the updateParticipants function in locus-info/index.js
|
@@ -790,6 +790,7 @@ describe('plugin-meetings', () => {
|
|
790
790
|
selfId: '2',
|
791
791
|
hostId: '3',
|
792
792
|
isReplace: undefined,
|
793
|
+
removedParticipantIds: [],
|
793
794
|
}
|
794
795
|
);
|
795
796
|
// note: in a real use case, recordingId, selfId, and hostId would all be the same
|
@@ -814,7 +815,7 @@ describe('plugin-meetings', () => {
|
|
814
815
|
};
|
815
816
|
|
816
817
|
locusInfo.emitScoped = sinon.stub();
|
817
|
-
locusInfo.updateParticipants({}, true);
|
818
|
+
locusInfo.updateParticipants({}, [], true);
|
818
819
|
|
819
820
|
assert.calledWith(
|
820
821
|
locusInfo.emitScoped,
|
@@ -830,6 +831,7 @@ describe('plugin-meetings', () => {
|
|
830
831
|
selfId: '2',
|
831
832
|
hostId: '3',
|
832
833
|
isReplace: true,
|
834
|
+
removedParticipantIds: [],
|
833
835
|
}
|
834
836
|
);
|
835
837
|
});
|
@@ -847,7 +849,7 @@ describe('plugin-meetings', () => {
|
|
847
849
|
];
|
848
850
|
|
849
851
|
locusInfo.emitScoped = sinon.stub();
|
850
|
-
locusInfo.updateParticipants(failureParticipant);
|
852
|
+
locusInfo.updateParticipants(failureParticipant, []);
|
851
853
|
assert.calledWith(
|
852
854
|
locusInfo.emitScoped,
|
853
855
|
{
|
@@ -2050,7 +2052,7 @@ describe('plugin-meetings', () => {
|
|
2050
2052
|
|
2051
2053
|
fakeLocus = {
|
2052
2054
|
meeting: true,
|
2053
|
-
participants:
|
2055
|
+
participants: [],
|
2054
2056
|
url: 'newLocusUrl',
|
2055
2057
|
syncUrl: 'newSyncUrl',
|
2056
2058
|
};
|
@@ -2525,7 +2527,7 @@ describe('plugin-meetings', () => {
|
|
2525
2527
|
});
|
2526
2528
|
|
2527
2529
|
it('onDeltaLocus handle delta data', () => {
|
2528
|
-
fakeLocus.participants =
|
2530
|
+
fakeLocus.participants = [];
|
2529
2531
|
const fakeBreakout = {
|
2530
2532
|
sessionId: 'sessionId',
|
2531
2533
|
groupId: 'groupId',
|
@@ -2542,11 +2544,11 @@ describe('plugin-meetings', () => {
|
|
2542
2544
|
};
|
2543
2545
|
locusInfo.updateParticipants = sinon.stub();
|
2544
2546
|
locusInfo.onDeltaLocus(fakeLocus);
|
2545
|
-
assert.calledWith(locusInfo.updateParticipants,
|
2547
|
+
assert.calledWith(locusInfo.updateParticipants, [], undefined, false);
|
2546
2548
|
|
2547
2549
|
fakeLocus.controls.breakout.sessionId = 'sessionId2';
|
2548
2550
|
locusInfo.onDeltaLocus(fakeLocus);
|
2549
|
-
assert.calledWith(locusInfo.updateParticipants,
|
2551
|
+
assert.calledWith(locusInfo.updateParticipants, [], undefined, true);
|
2550
2552
|
});
|
2551
2553
|
|
2552
2554
|
it('onDeltaLocus merges delta participants with existing participants', () => {
|
@@ -2563,7 +2565,7 @@ describe('plugin-meetings', () => {
|
|
2563
2565
|
existingParticipants,
|
2564
2566
|
FAKE_DELTA_PARTICIPANTS
|
2565
2567
|
);
|
2566
|
-
assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, false);
|
2568
|
+
assert.calledWith(locusInfo.updateParticipants, FAKE_DELTA_PARTICIPANTS, undefined, false);
|
2567
2569
|
});
|
2568
2570
|
|
2569
2571
|
[true, false].forEach((isDelta) =>
|
@@ -3074,6 +3076,7 @@ describe('plugin-meetings', () => {
|
|
3074
3076
|
id: 'test person id',
|
3075
3077
|
},
|
3076
3078
|
},
|
3079
|
+
participants: [],
|
3077
3080
|
});
|
3078
3081
|
|
3079
3082
|
updateLocusInfoStub.resetHistory();
|
@@ -14819,4 +14819,30 @@ describe('plugin-meetings', () => {
|
|
14819
14819
|
);
|
14820
14820
|
});
|
14821
14821
|
});
|
14822
|
+
|
14823
|
+
describe('#notifyHost', () => {
|
14824
|
+
beforeEach(() => {
|
14825
|
+
meeting.meetingRequest.notifyHost = sinon.stub().returns(Promise.resolve());
|
14826
|
+
});
|
14827
|
+
|
14828
|
+
it('sends the expected request', async () => {
|
14829
|
+
meeting.meetingInfo.siteFullUrl = `convergedats.webex.com`;
|
14830
|
+
const meetingUuid = 'meeting-uuid';
|
14831
|
+
const displayName = ['Test', 'User'];
|
14832
|
+
meeting.locusId = 'locusId';
|
14833
|
+
|
14834
|
+
const notifyHostPromise = meeting.notifyHost(meetingUuid, displayName);
|
14835
|
+
|
14836
|
+
assert.exists(notifyHostPromise.then);
|
14837
|
+
await notifyHostPromise;
|
14838
|
+
|
14839
|
+
assert.calledOnceWithExactly(
|
14840
|
+
meeting.meetingRequest.notifyHost,
|
14841
|
+
meeting.meetingInfo.siteFullUrl,
|
14842
|
+
meeting.locusId,
|
14843
|
+
meetingUuid,
|
14844
|
+
displayName,
|
14845
|
+
);
|
14846
|
+
});
|
14847
|
+
});
|
14822
14848
|
});
|
@@ -897,4 +897,25 @@ describe('plugin-meetings', () => {
|
|
897
897
|
});
|
898
898
|
});
|
899
899
|
});
|
900
|
+
|
901
|
+
describe('#notifyHost', () => {
|
902
|
+
it('check locus status', async () => {
|
903
|
+
const siteFullUrl = 'ats062222cvg.webex.com';
|
904
|
+
const locusId = 'locusId';
|
905
|
+
const meetingUuid = 'meetingUuid';
|
906
|
+
const displayName = ['user1', 'user2'];
|
907
|
+
await meetingsRequest.notifyHost(siteFullUrl, locusId, meetingUuid, displayName);
|
908
|
+
assert.deepEqual(meetingsRequest.request.getCall(0).args[0], {
|
909
|
+
method: 'POST',
|
910
|
+
uri: `https://${siteFullUrl}/wbxappapi/v1/meetings/${meetingUuid}/notifyhost`,
|
911
|
+
body: {
|
912
|
+
displayName,
|
913
|
+
size: displayName?.length,
|
914
|
+
},
|
915
|
+
headers: {
|
916
|
+
locusId,
|
917
|
+
}
|
918
|
+
});
|
919
|
+
});
|
920
|
+
});
|
900
921
|
});
|
@@ -0,0 +1,120 @@
|
|
1
|
+
const { default: MembersCollection } = require("../../../../src/members/collection");
|
2
|
+
const { default: Member } = require("../../../../src/member");
|
3
|
+
const { assert } = require('@webex/test-helper-chai');
|
4
|
+
|
5
|
+
|
6
|
+
describe('plugin-meetings', () => {
|
7
|
+
describe('MembersCollection', () => {
|
8
|
+
let collection;
|
9
|
+
let member1;
|
10
|
+
let member2;
|
11
|
+
const participant1 = { controls: {}, status: {} };
|
12
|
+
const participant2 = { controls: {}, status: {} };
|
13
|
+
|
14
|
+
beforeEach(() => {
|
15
|
+
collection = new MembersCollection();
|
16
|
+
member1 = new Member(participant1);
|
17
|
+
member2 = new Member(participant2);
|
18
|
+
});
|
19
|
+
|
20
|
+
it('starts with no members', () => {
|
21
|
+
assert.equal(Object.keys(collection.getAll()).length, 0);
|
22
|
+
});
|
23
|
+
|
24
|
+
it('can add members', () => {
|
25
|
+
collection.set('member1', member1);
|
26
|
+
assert.equal(Object.keys(collection.getAll()).length, 1);
|
27
|
+
assert.equal(collection.get('member1'), member1);
|
28
|
+
|
29
|
+
collection.set('member2', member2);
|
30
|
+
assert.equal(Object.keys(collection.getAll()).length, 2);
|
31
|
+
assert.equal(collection.get('member2'), member2);
|
32
|
+
});
|
33
|
+
|
34
|
+
it('can remove members', () => {
|
35
|
+
// Add some members first
|
36
|
+
collection.set('member1', member1);
|
37
|
+
collection.set('member2', member2);
|
38
|
+
assert.equal(Object.keys(collection.getAll()).length, 2);
|
39
|
+
|
40
|
+
// Remove one member
|
41
|
+
collection.remove('member1');
|
42
|
+
assert.equal(Object.keys(collection.getAll()).length, 1);
|
43
|
+
assert.equal(collection.get('member1'), undefined);
|
44
|
+
assert.equal(collection.get('member2'), member2);
|
45
|
+
|
46
|
+
// Remove another member
|
47
|
+
collection.remove('member2');
|
48
|
+
assert.equal(Object.keys(collection.getAll()).length, 0);
|
49
|
+
assert.equal(collection.get('member2'), undefined);
|
50
|
+
|
51
|
+
// Removing non-existent member should not cause errors
|
52
|
+
collection.remove('nonExistent');
|
53
|
+
assert.equal(Object.keys(collection.getAll()).length, 0);
|
54
|
+
});
|
55
|
+
|
56
|
+
describe('reset', () => {
|
57
|
+
it('removes all members', () => {
|
58
|
+
// Add some members first
|
59
|
+
collection.set('member1', member1);
|
60
|
+
collection.set('member2', member2);
|
61
|
+
assert.equal(Object.keys(collection.getAll()).length, 2);
|
62
|
+
|
63
|
+
// Reset should clear all members
|
64
|
+
collection.reset();
|
65
|
+
assert.equal(Object.keys(collection.getAll()).length, 0);
|
66
|
+
assert.equal(collection.get('member1'), undefined);
|
67
|
+
assert.equal(collection.get('member2'), undefined);
|
68
|
+
});
|
69
|
+
});
|
70
|
+
|
71
|
+
describe('setAll', () => {
|
72
|
+
it('replaces all members with new collection', () => {
|
73
|
+
// Add initial member
|
74
|
+
collection.set('member1', member1);
|
75
|
+
assert.equal(Object.keys(collection.getAll()).length, 1);
|
76
|
+
|
77
|
+
// Set all with new collection
|
78
|
+
const newMembers = {
|
79
|
+
'member2': member2,
|
80
|
+
'member3': new Member(participant1)
|
81
|
+
};
|
82
|
+
collection.setAll(newMembers);
|
83
|
+
|
84
|
+
assert.equal(Object.keys(collection.getAll()).length, 2);
|
85
|
+
assert.equal(collection.get('member1'), undefined);
|
86
|
+
assert.equal(collection.get('member2'), member2);
|
87
|
+
assert.exists(collection.get('member3'));
|
88
|
+
});
|
89
|
+
});
|
90
|
+
|
91
|
+
describe('get', () => {
|
92
|
+
it('returns undefined for non-existent members', () => {
|
93
|
+
assert.equal(collection.get('nonExistent'), undefined);
|
94
|
+
});
|
95
|
+
|
96
|
+
it('returns correct member for existing id', () => {
|
97
|
+
collection.set('member1', member1);
|
98
|
+
assert.equal(collection.get('member1'), member1);
|
99
|
+
});
|
100
|
+
});
|
101
|
+
|
102
|
+
describe('getAll', () => {
|
103
|
+
it('returns empty object when no members', () => {
|
104
|
+
const allMembers = collection.getAll();
|
105
|
+
assert.isObject(allMembers);
|
106
|
+
assert.equal(Object.keys(allMembers).length, 0);
|
107
|
+
});
|
108
|
+
|
109
|
+
it('returns all members', () => {
|
110
|
+
collection.set('member1', member1);
|
111
|
+
collection.set('member2', member2);
|
112
|
+
|
113
|
+
const allMembers = collection.getAll();
|
114
|
+
assert.equal(Object.keys(allMembers).length, 2);
|
115
|
+
assert.equal(allMembers.member1, member1);
|
116
|
+
assert.equal(allMembers.member2, member2);
|
117
|
+
});
|
118
|
+
});
|
119
|
+
});
|
120
|
+
});
|
@@ -320,9 +320,18 @@ describe('plugin-meetings', () => {
|
|
320
320
|
EVENT_TRIGGERS.MEMBERS_CLEAR,
|
321
321
|
{}
|
322
322
|
);
|
323
|
+
sinon.restore();
|
323
324
|
});
|
324
325
|
});
|
325
326
|
describe('#locusParticipantsUpdate', () => {
|
327
|
+
beforeEach(() => {
|
328
|
+
sinon.stub(Trigger, 'trigger');
|
329
|
+
});
|
330
|
+
|
331
|
+
afterEach(() => {
|
332
|
+
sinon.restore();
|
333
|
+
});
|
334
|
+
|
326
335
|
it('should send member update event with session info', () => {
|
327
336
|
const members = createMembers({url: url1});
|
328
337
|
const fakePayload = {
|
@@ -343,13 +352,45 @@ describe('plugin-meetings', () => {
|
|
343
352
|
},
|
344
353
|
EVENT_TRIGGERS.MEMBERS_UPDATE,
|
345
354
|
{
|
346
|
-
delta: {added: [], updated: []},
|
355
|
+
delta: {added: [], updated: [], removedIds: []},
|
347
356
|
full: {},
|
348
357
|
isReplace: true,
|
349
358
|
}
|
350
359
|
);
|
351
360
|
});
|
352
361
|
|
362
|
+
it('should handle participants being removed', () => {
|
363
|
+
const members = createMembers({url: url1});
|
364
|
+
|
365
|
+
// setup the collection with a fake member
|
366
|
+
members.membersCollection.setAll(fakeMembersCollection);
|
367
|
+
assert.equal(Object.keys(members.membersCollection.getAll()).length, 1);
|
368
|
+
|
369
|
+
// remove the member
|
370
|
+
members.locusParticipantsUpdate({
|
371
|
+
participants: [],
|
372
|
+
removedParticipantIds: ['test1'],
|
373
|
+
});
|
374
|
+
|
375
|
+
assert.equal(Object.keys(members.membersCollection.getAll()).length, 0);
|
376
|
+
|
377
|
+
// check that the event was emitted
|
378
|
+
assert.calledWith(
|
379
|
+
Trigger.trigger,
|
380
|
+
members,
|
381
|
+
{
|
382
|
+
file: 'members',
|
383
|
+
function: 'locusParticipantsUpdate',
|
384
|
+
},
|
385
|
+
EVENT_TRIGGERS.MEMBERS_UPDATE,
|
386
|
+
{
|
387
|
+
delta: {added: [], updated: [], removedIds: ['test1']},
|
388
|
+
full: {},
|
389
|
+
isReplace: false,
|
390
|
+
}
|
391
|
+
);
|
392
|
+
});
|
393
|
+
|
353
394
|
describe('handles members with paired devices correctly', () => {
|
354
395
|
const runCheck = (propsForUpdate, expectedPropsOnPairedMember) => {
|
355
396
|
const members = createMembers({url: url1});
|