@webex/plugin-meetings 3.0.0-beta.181 → 3.0.0-beta.183

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.
@@ -11,6 +11,7 @@ import {
11
11
  DISPLAY_HINTS,
12
12
  FULL_STATE,
13
13
  SELF_POLICY,
14
+ EVENT_TRIGGERS,
14
15
  } from '../constants';
15
16
  import IntentToJoinError from '../common/errors/intent-to-join';
16
17
  import JoinMeetingError from '../common/errors/join-meeting';
@@ -18,6 +19,7 @@ import ParameterError from '../common/errors/parameter';
18
19
  import PermissionError from '../common/errors/permission';
19
20
  import PasswordError from '../common/errors/password-error';
20
21
  import CaptchaError from '../common/errors/captcha-error';
22
+ import Trigger from '../common/events/trigger-proxy';
21
23
 
22
24
  const MeetingUtil = {
23
25
  parseLocusJoin: (response) => {
@@ -566,6 +568,47 @@ const MeetingUtil = {
566
568
 
567
569
  return userPolicies[feature];
568
570
  },
571
+
572
+ parseInterpretationInfo: (meeting, meetingInfo) => {
573
+ if (!meeting || !meetingInfo) {
574
+ return;
575
+ }
576
+ const siInfo = meetingInfo.simultaneousInterpretation;
577
+ meeting.simultaneousInterpretation.updateMeetingSIEnabled(
578
+ !!meetingInfo.turnOnSimultaneousInterpretation,
579
+ !!siInfo?.currentSIInterpreter
580
+ );
581
+ const hostSIEnabled = !!(
582
+ meetingInfo.turnOnSimultaneousInterpretation &&
583
+ meetingInfo?.meetingSiteSetting?.enableHostInterpreterControlSI
584
+ );
585
+ meeting.simultaneousInterpretation.updateHostSIEnabled(hostSIEnabled);
586
+
587
+ function renameKey(obj, oldKey, newKey) {
588
+ if (oldKey in obj) {
589
+ obj[newKey] = obj[oldKey];
590
+ delete obj[oldKey];
591
+ }
592
+ }
593
+ if (siInfo) {
594
+ const lanuagesInfo = cloneDeep(siInfo.siLanguages);
595
+ for (const language of lanuagesInfo) {
596
+ renameKey(language, 'languageCode', 'languageName');
597
+ renameKey(language, 'languageGroupId', 'languageCode');
598
+ }
599
+ if (!meeting.simultaneousInterpretation?.siLanguages?.length) {
600
+ meeting.simultaneousInterpretation.updateInterpretation(lanuagesInfo);
601
+ }
602
+ }
603
+ Trigger.trigger(
604
+ this,
605
+ {
606
+ file: 'meeting/util',
607
+ function: 'parseInterpretationInfo',
608
+ },
609
+ EVENT_TRIGGERS.MEETING_INTERPRETATION_UPDATE
610
+ );
611
+ },
569
612
  };
570
613
 
571
614
  export default MeetingUtil;
@@ -364,8 +364,8 @@ MemberUtil.extractMediaStatus = (participant: any): IMediaStatus => {
364
364
  }
365
365
 
366
366
  return {
367
- audio: participant.status.audioStatus,
368
- video: participant.status.videoStatus,
367
+ audio: participant.status?.audioStatus,
368
+ video: participant.status?.videoStatus,
369
369
  };
370
370
  };
371
371
 
@@ -83,6 +83,25 @@ describe('plugin-meetings', () => {
83
83
  });
84
84
  });
85
85
 
86
+ describe('#updateMeetingSIEnabled', () => {
87
+ it('update meeting SI feature is on or off, and self is scheduled interpreter or not', () => {
88
+ interpretation.updateMeetingSIEnabled(true, false);
89
+
90
+ assert.equal(interpretation.meetingSIEnabled, true);
91
+ assert.equal(interpretation.selfIsInterpreter, false);
92
+
93
+ interpretation.updateMeetingSIEnabled(true, true);
94
+
95
+ assert.equal(interpretation.meetingSIEnabled, true);
96
+ assert.equal(interpretation.selfIsInterpreter, true);
97
+
98
+ interpretation.updateMeetingSIEnabled(false, false);
99
+
100
+ assert.equal(interpretation.meetingSIEnabled, false);
101
+ assert.equal(interpretation.selfIsInterpreter, false);
102
+ });
103
+ });
104
+
86
105
  describe('#updateInterpretation', () => {
87
106
  const checkSILanguage = (siLanguage, expectResult) => {
88
107
  return siLanguage?.languageCode === expectResult.languageCode && siLanguage?.languageName === expectResult.languageName
@@ -1648,12 +1648,39 @@ describe('plugin-meetings', () => {
1648
1648
  sandbox.stub(locusInfo, 'updateParticipants');
1649
1649
  sandbox.stub(locusInfo, 'isMeetingActive');
1650
1650
  sandbox.stub(locusInfo, 'handleOneOnOneEvent');
1651
+ sandbox.stub(locusParser, 'isNewFullLocus').returns(true);
1651
1652
 
1652
1653
  locusInfo.onFullLocus(fakeLocus, eventType);
1653
1654
 
1654
1655
  assert.equal(fakeLocus, locusParser.workingCopy);
1655
1656
  });
1656
1657
 
1658
+ it('onFullLocus() does not do anything if the incoming full locus DTO is old', () => {
1659
+ const eventType = 'fakeEvent';
1660
+
1661
+ locusParser.workingCopy = {};
1662
+
1663
+ const oldWorkingCopy = locusParser.workingCopy;
1664
+
1665
+ const spies = [
1666
+ sandbox.stub(locusInfo, 'updateParticipantDeltas'),
1667
+ sandbox.stub(locusInfo, 'updateLocusInfo'),
1668
+ sandbox.stub(locusInfo, 'updateParticipants'),
1669
+ sandbox.stub(locusInfo, 'isMeetingActive'),
1670
+ sandbox.stub(locusInfo, 'handleOneOnOneEvent'),
1671
+ ];
1672
+
1673
+ sandbox.stub(locusParser, 'isNewFullLocus').returns(false);
1674
+
1675
+ locusInfo.onFullLocus(fakeLocus, eventType);
1676
+
1677
+ spies.forEach((spy) => {
1678
+ assert.notCalled(spy);
1679
+ })
1680
+
1681
+ assert.equal(oldWorkingCopy, locusParser.workingCopy);
1682
+ });
1683
+
1657
1684
  it('onDeltaAction applies locus delta data to meeting', () => {
1658
1685
  const action = 'fake action';
1659
1686
  const parsedLoci = 'fake loci';
@@ -238,6 +238,68 @@ describe('locus-info/parser', () => {
238
238
  });
239
239
  });
240
240
 
241
+ describe('Full Locus handling', () => {
242
+ describe('isNewFullLocus', () => {
243
+ let parser;
244
+
245
+ beforeEach(() => {
246
+ parser = new LocusDeltaParser();
247
+ })
248
+ it('returns false if incoming Locus is not valid', () => {
249
+ const fakeInvalidIncomingLocus = {};
250
+
251
+ parser.workingCopy = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [1]}};
252
+
253
+ assert.isFalse(parser.isNewFullLocus(fakeInvalidIncomingLocus));
254
+ });
255
+
256
+ const runCheck = (incomingSequence, currentSequence, expectedResult) => {
257
+ parser.workingCopy = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [1, 2, currentSequence]}};
258
+
259
+ const fakeIncomingLocus = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [1, 10, incomingSequence]}};
260
+
261
+ assert.strictEqual(parser.isNewFullLocus(fakeIncomingLocus), expectedResult);
262
+ }
263
+ it('returns true if there is no working copy', () => {
264
+ const fakeIncomingLocus = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [10]}};
265
+
266
+ // sanity check that we initially have no working copy
267
+ assert.isNull(parser.workingCopy);
268
+
269
+ assert.isTrue(parser.isNewFullLocus(fakeIncomingLocus));
270
+ });
271
+
272
+ it('returns true if new sequence is higher than existing one', () => {
273
+ runCheck(101, 100, true);
274
+ });
275
+
276
+ it('returns false if new sequence is same than existing one', () => {
277
+ runCheck(100, 100, false);
278
+ });
279
+
280
+ it('returns false if new sequence is older than existing one', () => {
281
+ runCheck(99, 100, false);
282
+ });
283
+
284
+ it('returns true if incoming Locus has empty sequence', () => {
285
+ parser.workingCopy = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [1, 2, 3]}};
286
+
287
+ const fakeIncomingLocus = { sequence: {rangeStart: 0, rangeEnd: 0, entries: []}};
288
+
289
+ assert.isTrue(parser.isNewFullLocus(fakeIncomingLocus));
290
+ });
291
+
292
+ it('returns true if working copy has empty sequence', () => {
293
+ parser.workingCopy = { sequence: {rangeStart: 0, rangeEnd: 0, entries: []}};
294
+
295
+ const fakeIncomingLocus = { sequence: {rangeStart: 0, rangeEnd: 0, entries: [1,2,3]}};
296
+
297
+ assert.isTrue(parser.isNewFullLocus(fakeIncomingLocus));
298
+ });
299
+
300
+ })
301
+ });
302
+
241
303
  describe('Invalid Locus objects', () => {
242
304
  let sandbox = null;
243
305
  let parser;
@@ -5531,25 +5531,27 @@ describe('plugin-meetings', () => {
5531
5531
 
5532
5532
  checkParseMeetingInfo(expectedInfoToParse);
5533
5533
  });
5534
- it('should set hostSIEnabled correctly depend on the toggle statue in site setting', () => {
5535
- const updateHostSIEnabledSpy = sinon.spy(meeting.simultaneousInterpretation, 'updateHostSIEnabled');
5534
+ it('should parse interpretation info correctly', () => {
5535
+ const parseInterpretationInfo = sinon.spy(MeetingUtil, 'parseInterpretationInfo');
5536
5536
  const mockToggleOnData = {
5537
5537
  body: {
5538
5538
  meetingSiteSetting: {
5539
5539
  enableHostInterpreterControlSI: true,
5540
+ },
5541
+ turnOnSimultaneousInterpretation: true,
5542
+ simultaneousInterpretation: {
5543
+ currentSIInterpreter: false,
5544
+ siLanguages: [
5545
+ {
5546
+ languageCode: "ar",
5547
+ languageGroupId: 4,
5548
+ },
5549
+ ]
5540
5550
  }
5541
5551
  }
5542
5552
  };
5543
5553
  meeting.parseMeetingInfo(mockToggleOnData);
5544
- assert.calledWith(updateHostSIEnabledSpy, true);
5545
-
5546
- const mockToggleOffData = {
5547
- body: {
5548
- meetingSiteSetting: {}
5549
- }
5550
- };
5551
- meeting.parseMeetingInfo(mockToggleOffData);
5552
- assert.calledWith(updateHostSIEnabledSpy, false);
5554
+ assert.calledOnceWithExactly(parseInterpretationInfo, meeting, mockToggleOnData.body);
5553
5555
  });
5554
5556
  });
5555
5557
 
@@ -740,5 +740,67 @@ describe('plugin-meetings', () => {
740
740
  assert.deepEqual(MeetingUtil.isBreakoutPreassignmentsEnabled([]), true);
741
741
  });
742
742
  });
743
+
744
+
745
+ describe('parseInterpretationInfo', () => {
746
+ let meetingInfo = {};
747
+ beforeEach(() => {
748
+ meeting.simultaneousInterpretation = {
749
+ updateMeetingSIEnabled: sinon.stub(),
750
+ updateHostSIEnabled: sinon.stub(),
751
+ updateInterpretation: sinon.stub(),
752
+ siLanguages: [],
753
+ };
754
+ });
755
+ it('should update simultaneous interpretation settings with SI and host enabled', () => {
756
+ meetingInfo.turnOnSimultaneousInterpretation = true;
757
+ meetingInfo.meetingSiteSetting = {
758
+ enableHostInterpreterControlSI: true,
759
+ };
760
+ meetingInfo.simultaneousInterpretation = {
761
+ currentSIInterpreter: true,
762
+ siLanguages: [
763
+ { languageCode: 'en', languageGroupId: 1 },
764
+ { languageCode: 'es', languageGroupId: 2 },
765
+ ],
766
+ };
767
+
768
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
769
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, true, true);
770
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, true);
771
+ assert.calledWith(meeting.simultaneousInterpretation.updateInterpretation, [
772
+ { languageName: 'en', languageCode: 1 },
773
+ { languageName: 'es', languageCode: 2 },
774
+ ]);
775
+ });
776
+
777
+ it('should update simultaneous interpretation settings with host SI disabled', () => {
778
+ meetingInfo.meetingSiteSetting.enableHostInterpreterControlSI = false;
779
+ meetingInfo.simultaneousInterpretation.currentSIInterpreter = false;
780
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
781
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, true, false);
782
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, false);
783
+ assert.calledWith(meeting.simultaneousInterpretation.updateInterpretation, [
784
+ { languageName: 'en', languageCode: 1 },
785
+ { languageName: 'es', languageCode: 2 },
786
+ ]);
787
+ });
788
+ it('should update simultaneous interpretation settings with SI disabled', () => {
789
+ meetingInfo.turnOnSimultaneousInterpretation = false;
790
+ MeetingUtil.parseInterpretationInfo(meeting, meetingInfo);
791
+ assert.calledWith(meeting.simultaneousInterpretation.updateMeetingSIEnabled, false, false);
792
+ assert.calledWith(meeting.simultaneousInterpretation.updateHostSIEnabled, false);
793
+ });
794
+
795
+ it('should not update simultaneous interpretation settings for invalid input', () => {
796
+ // Call the function with invalid inputs
797
+ MeetingUtil.parseInterpretationInfo(null, null);
798
+
799
+ // Ensure that the update functions are not called
800
+ assert.notCalled(meeting.simultaneousInterpretation.updateMeetingSIEnabled);
801
+ assert.notCalled(meeting.simultaneousInterpretation.updateHostSIEnabled);
802
+ assert.notCalled(meeting.simultaneousInterpretation.updateInterpretation);
803
+ });
804
+ });
743
805
  });
744
806
  });
@@ -1085,7 +1085,7 @@ describe('plugin-meetings', () => {
1085
1085
  assert.calledOnce(webex.meetings.meetingInfo.fetchMeetingInfo);
1086
1086
  assert.calledOnce(MeetingsUtil.getMeetingAddedType);
1087
1087
  assert.notCalled(setTimeoutSpy);
1088
- assert.calledThrice(TriggerProxy.trigger);
1088
+ assert.callCount(TriggerProxy.trigger, 4);
1089
1089
  assert.calledWith(webex.meetings.meetingInfo.fetchMeetingInfo, destination, type, null, null, undefined, undefined, extraParams, {meetingId: meeting.id});
1090
1090
  assert.calledWith(MeetingsUtil.getMeetingAddedType, 'test type');
1091
1091