@webex/plugin-meetings 3.8.0-next.20 → 3.8.0-next.22

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.
@@ -16,6 +16,7 @@ export default class Member {
16
16
  isInMeeting: any;
17
17
  isModerator: any;
18
18
  isModeratorAssignmentProhibited: any;
19
+ isPresenterAssignmentProhibited: any;
19
20
  isMutable: any;
20
21
  isNotAdmitted: any;
21
22
  isRecording: any;
@@ -458,7 +458,7 @@ var Webinar = _webexCore.WebexPlugin.extend({
458
458
  }, _callee7);
459
459
  }))();
460
460
  },
461
- version: "3.8.0-next.20"
461
+ version: "3.8.0-next.22"
462
462
  });
463
463
  var _default = exports.default = Webinar;
464
464
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -43,13 +43,13 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.8.0-next.20",
47
- "@webex/plugin-rooms": "3.8.0-next.10",
48
- "@webex/test-helper-chai": "3.8.0-next.9",
49
- "@webex/test-helper-mocha": "3.8.0-next.9",
50
- "@webex/test-helper-mock-webex": "3.8.0-next.9",
51
- "@webex/test-helper-retry": "3.8.0-next.9",
52
- "@webex/test-helper-test-users": "3.8.0-next.9",
46
+ "@webex/plugin-meetings": "3.8.0-next.22",
47
+ "@webex/plugin-rooms": "3.8.0-next.11",
48
+ "@webex/test-helper-chai": "3.8.0-next.10",
49
+ "@webex/test-helper-mocha": "3.8.0-next.10",
50
+ "@webex/test-helper-mock-webex": "3.8.0-next.10",
51
+ "@webex/test-helper-retry": "3.8.0-next.10",
52
+ "@webex/test-helper-test-users": "3.8.0-next.10",
53
53
  "chai": "^4.3.4",
54
54
  "chai-as-promised": "^7.1.1",
55
55
  "eslint": "^8.24.0",
@@ -61,22 +61,22 @@
61
61
  "typescript": "^4.7.4"
62
62
  },
63
63
  "dependencies": {
64
- "@webex/common": "3.8.0-next.9",
64
+ "@webex/common": "3.8.0-next.10",
65
65
  "@webex/event-dictionary-ts": "^1.0.1688",
66
- "@webex/internal-media-core": "2.14.6",
67
- "@webex/internal-plugin-conversation": "3.8.0-next.10",
68
- "@webex/internal-plugin-device": "3.8.0-next.9",
69
- "@webex/internal-plugin-llm": "3.8.0-next.11",
70
- "@webex/internal-plugin-mercury": "3.8.0-next.10",
71
- "@webex/internal-plugin-metrics": "3.8.0-next.9",
72
- "@webex/internal-plugin-support": "3.8.0-next.10",
73
- "@webex/internal-plugin-user": "3.8.0-next.9",
74
- "@webex/internal-plugin-voicea": "3.8.0-next.20",
75
- "@webex/media-helpers": "3.8.0-next.10",
76
- "@webex/plugin-people": "3.8.0-next.10",
77
- "@webex/plugin-rooms": "3.8.0-next.10",
66
+ "@webex/internal-media-core": "2.14.7",
67
+ "@webex/internal-plugin-conversation": "3.8.0-next.11",
68
+ "@webex/internal-plugin-device": "3.8.0-next.10",
69
+ "@webex/internal-plugin-llm": "3.8.0-next.12",
70
+ "@webex/internal-plugin-mercury": "3.8.0-next.11",
71
+ "@webex/internal-plugin-metrics": "3.8.0-next.10",
72
+ "@webex/internal-plugin-support": "3.8.0-next.11",
73
+ "@webex/internal-plugin-user": "3.8.0-next.10",
74
+ "@webex/internal-plugin-voicea": "3.8.0-next.22",
75
+ "@webex/media-helpers": "3.8.0-next.11",
76
+ "@webex/plugin-people": "3.8.0-next.11",
77
+ "@webex/plugin-rooms": "3.8.0-next.11",
78
78
  "@webex/web-capabilities": "^1.4.0",
79
- "@webex/webex-core": "3.8.0-next.9",
79
+ "@webex/webex-core": "3.8.0-next.10",
80
80
  "ampersand-collection": "^2.0.2",
81
81
  "bowser": "^2.11.0",
82
82
  "btoa": "^1.2.1",
@@ -92,5 +92,5 @@
92
92
  "//": [
93
93
  "TODO: upgrade jwt-decode when moving to node 18"
94
94
  ],
95
- "version": "3.8.0-next.20"
95
+ "version": "3.8.0-next.22"
96
96
  }
@@ -1686,6 +1686,33 @@ export default class Meeting extends StatelessWebexPlugin {
1686
1686
  return this.#isoLocalClientMeetingJoinTime;
1687
1687
  }
1688
1688
 
1689
+ /**
1690
+ * Setter - sets isoLocalClientMeetingJoinTime
1691
+ * This will be set once on meeting join, and not updated again
1692
+ * this will always produce an ISO string
1693
+ * If the iso string is invalid, it will fallback to the current system time
1694
+ * @param {string | undefined} time
1695
+ */
1696
+ set isoLocalClientMeetingJoinTime(time: string | undefined) {
1697
+ const fallback = new Date().toISOString();
1698
+ if (!time) {
1699
+ this.#isoLocalClientMeetingJoinTime = fallback;
1700
+ } else {
1701
+ const date = new Date(time);
1702
+
1703
+ // Check if the date is valid
1704
+ if (Number.isNaN(date.getTime())) {
1705
+ LoggerProxy.logger.info(
1706
+ // @ts-ignore
1707
+ `Meeting:index#isoLocalClientMeetingJoinTime --> Invalid date provided: ${time}. Falling back to system clock.`
1708
+ );
1709
+ this.#isoLocalClientMeetingJoinTime = fallback;
1710
+ } else {
1711
+ this.#isoLocalClientMeetingJoinTime = date.toISOString();
1712
+ }
1713
+ }
1714
+ }
1715
+
1689
1716
  /**
1690
1717
  * Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
1691
1718
  * @param {any} info
@@ -5718,8 +5745,6 @@ export default class Meeting extends StatelessWebexPlugin {
5718
5745
  // @ts-ignore
5719
5746
  this.webex.internal.device.meetingStarted();
5720
5747
 
5721
- this.#isoLocalClientMeetingJoinTime = new Date().toISOString();
5722
-
5723
5748
  LoggerProxy.logger.log('Meeting:index#join --> Success');
5724
5749
 
5725
5750
  Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
@@ -180,7 +180,7 @@ const MeetingUtil = {
180
180
  .then((res) => {
181
181
  const parsed = MeetingUtil.parseLocusJoin(res);
182
182
  meeting.setLocus(parsed);
183
-
183
+ meeting.isoLocalClientMeetingJoinTime = res?.headers?.date; // read from header if exist, else fall back to system clock : https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-555657
184
184
  webex.internal.newMetrics.submitClientEvent({
185
185
  name: 'client.locus.join.response',
186
186
  payload: {
@@ -23,6 +23,7 @@ export default class Member {
23
23
  isInMeeting: any;
24
24
  isModerator: any;
25
25
  isModeratorAssignmentProhibited: any;
26
+ isPresenterAssignmentProhibited: any;
26
27
  isMutable: any;
27
28
  isNotAdmitted: any;
28
29
  isRecording: any;
@@ -257,6 +258,14 @@ export default class Member {
257
258
  */
258
259
  this.isModeratorAssignmentProhibited = null;
259
260
 
261
+ /**
262
+ * @instance
263
+ * @type {Boolean}
264
+ * @public
265
+ * @memberof Member
266
+ */
267
+ this.isPresenterAssignmentProhibited = null;
268
+
260
269
  /**
261
270
  * @instance
262
271
  * @type {IExternalRoles}
@@ -309,6 +318,8 @@ export default class Member {
309
318
  this.isModerator = MemberUtil.isModerator(participant);
310
319
  this.isModeratorAssignmentProhibited =
311
320
  MemberUtil.isModeratorAssignmentProhibited(participant);
321
+ this.isPresenterAssignmentProhibited =
322
+ MemberUtil.isPresenterAssignmentProhibited(participant);
312
323
  this.processStatus(participant);
313
324
  this.processRoles(participant as ParticipantWithRoles);
314
325
  // must be done last
@@ -127,6 +127,9 @@ MemberUtil.isDevice = (participant: any) => participant && participant.type ===
127
127
  MemberUtil.isModeratorAssignmentProhibited = (participant) =>
128
128
  participant && participant.moderatorAssignmentNotAllowed;
129
129
 
130
+ MemberUtil.isPresenterAssignmentProhibited = (participant) =>
131
+ participant && participant.presenterAssignmentNotAllowed;
132
+
130
133
  /**
131
134
  * checks to see if the participant id is the same as the passed id
132
135
  * there are multiple ids that can be used
@@ -210,6 +210,7 @@ describe('plugin-meetings', () => {
210
210
  let membersSpy;
211
211
  let meetingRequestSpy;
212
212
  let correlationId;
213
+ let isoLocalClientMeetingJoinTime;
213
214
  let uploadEvent;
214
215
 
215
216
  beforeEach(() => {
@@ -1692,10 +1693,6 @@ describe('plugin-meetings', () => {
1692
1693
  sandbox.stub(MeetingUtil, 'joinMeeting').returns(Promise.resolve(joinMeetingResult));
1693
1694
  });
1694
1695
 
1695
- afterEach(() => {
1696
- assert.exists(meeting.isoLocalClientMeetingJoinTime);
1697
- });
1698
-
1699
1696
  it('should join the meeting and return promise', async () => {
1700
1697
  const join = meeting.join({pstnAudioType: 'dial-in'});
1701
1698
  meeting.config.enableAutomaticLLM = true;
@@ -7530,6 +7527,27 @@ describe('plugin-meetings', () => {
7530
7527
  });
7531
7528
  });
7532
7529
 
7530
+ describe('#setIsoLocalClientMeetingJoinTime', () => {
7531
+ it('should fallback to system clock ISO string when given an undefined value', () => {
7532
+ const currentSystemTime = new Date().toISOString();
7533
+ meeting.isoLocalClientMeetingJoinTime = undefined;
7534
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
7535
+ });
7536
+
7537
+ it('should fallback to system clock ISO string when given an invalid value', () => {
7538
+ const currentSystemTime = new Date().toISOString();
7539
+ meeting.isoLocalClientMeetingJoinTime = 'invalid-date';
7540
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, currentSystemTime);
7541
+ });
7542
+
7543
+ it('should set the isoLocalClientMeetingJoinTime correctly for a valid date string', () => {
7544
+ const validDateString = 'Tue, 01 Apr 2025 13:00:36 GMT';
7545
+ const expectedISOString = new Date(validDateString).toISOString();
7546
+ meeting.isoLocalClientMeetingJoinTime = validDateString;
7547
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, expectedISOString);
7548
+ });
7549
+ });
7550
+
7533
7551
  describe('#updateCallStateForMetrics', () => {
7534
7552
  it('should update the callState, overriding existing values', () => {
7535
7553
  assert.deepEqual(meeting.callStateForMetrics, {correlationId, sessionCorrelationId: ''});
@@ -460,6 +460,50 @@ describe('plugin-meetings', () => {
460
460
  });
461
461
  });
462
462
 
463
+
464
+ it('#Should call `meetingRequest.joinMeeting and handle a date header in the response : isoLocalClientMeetingJoinedTime', async () => {
465
+ meeting.isMultistream = true;
466
+
467
+ const FAKE_REACHABILITY_REPORT = {
468
+ id: 'fake reachability report',
469
+ };
470
+ const FAKE_CLIENT_MEDIA_PREFERENCES = {
471
+ id: 'fake client media preferences',
472
+ };
473
+
474
+ webex.meetings.reachability.getReachabilityReportToAttachToRoap.resolves(FAKE_REACHABILITY_REPORT);
475
+ webex.meetings.reachability.getClientMediaPreferences.resolves(FAKE_CLIENT_MEDIA_PREFERENCES);
476
+
477
+ sinon
478
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV4')
479
+ .get(() => true);
480
+ sinon
481
+ .stub(webex.internal.device.ipNetworkDetector, 'supportsIpV6')
482
+ .get(() => true);
483
+
484
+ meeting.meetingRequest.joinMeeting.resolves({
485
+ headers: {
486
+ date: 'test'
487
+ },
488
+ body: {
489
+ mediaConnections: [{mediaId: 'test'}],
490
+ locus: {
491
+ url: 'test',
492
+ self: {
493
+ id: 'test'
494
+ }
495
+ }
496
+ }
497
+ })
498
+
499
+ await MeetingUtil.joinMeeting(meeting, {
500
+ reachability: 'reachability',
501
+ roapMessage: 'roapMessage',
502
+ });
503
+
504
+ assert.equal(meeting.isoLocalClientMeetingJoinTime, 'test');
505
+ });
506
+
463
507
  it('should handle failed reachability report retrieval', async () => {
464
508
  webex.meetings.reachability.getReachabilityReportToAttachToRoap.rejects(
465
509
  new Error('fake error')
@@ -50,6 +50,13 @@ describe('member', () => {
50
50
 
51
51
  assert.calledOnceWithExactly(MemberUtil.canReclaimHost, participant);
52
52
  });
53
+
54
+ it('checks that processParticipant calls isPresenterAssignmentProhibited', () => {
55
+ sinon.spy(MemberUtil, 'isPresenterAssignmentProhibited');
56
+ member.processParticipant(participant);
57
+
58
+ assert.calledOnceWithExactly(MemberUtil.isPresenterAssignmentProhibited, participant);
59
+ });
53
60
  })
54
61
 
55
62
  describe('#processMember', () => {
@@ -557,6 +557,30 @@ describe('plugin-meetings', () => {
557
557
  testResult(false, undefined, false);
558
558
  });
559
559
  });
560
+
561
+ describe('MemberUtil.isPresenterAssignmentProhibited', () => {
562
+ it('returns true when isPresenterAssignmentProhibited is true', () => {
563
+ const participant = {
564
+ presenterAssignmentNotAllowed: true
565
+ };
566
+
567
+ assert.isTrue(MemberUtil.isPresenterAssignmentProhibited(participant));
568
+ });
569
+
570
+ it('returns false when isPresenterAssignmentProhibited is false', () => {
571
+ const participant = {
572
+ presenterAssignmentNotAllowed: false,
573
+ };
574
+
575
+ assert.isFalse(MemberUtil.isPresenterAssignmentProhibited(participant));
576
+ });
577
+
578
+ it('returns undefined when isPresenterAssignmentProhibited is undefined', () => {
579
+ const participant = {};
580
+
581
+ assert.isUndefined(MemberUtil.isPresenterAssignmentProhibited(participant));
582
+ });
583
+ });
560
584
  });
561
585
 
562
586
  describe('extractMediaStatus', () => {