@webex/plugin-meetings 3.0.0-beta.169 → 3.0.0-beta.170

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,5 +1,6 @@
1
1
  import uuid from 'uuid';
2
2
  import {cloneDeep, isEqual, defer, isEmpty} from 'lodash';
3
+ import jwt from 'jsonwebtoken';
3
4
  // @ts-ignore - Fix this
4
5
  import {StatelessWebexPlugin} from '@webex/webex-core';
5
6
  import {ClientEvent, CALL_DIAGNOSTIC_CONFIG} from '@webex/internal-plugin-metrics';
@@ -508,6 +509,7 @@ export default class Meeting extends StatelessWebexPlugin {
508
509
  controlsOptionsManager: ControlsOptionsManager;
509
510
  requiredCaptcha: any;
510
511
  receiveSlotManager: ReceiveSlotManager;
512
+ selfUserPolicies: any;
511
513
  shareStatus: string;
512
514
  statsAnalyzer: StatsAnalyzer;
513
515
  transcription: Transcription;
@@ -2426,10 +2428,22 @@ export default class Meeting extends StatelessWebexPlugin {
2426
2428
  ),
2427
2429
  canSetMuted: ControlsOptionsUtil.canSetMuted(payload.info.userDisplayHints),
2428
2430
  canUnsetMuted: ControlsOptionsUtil.canUnsetMuted(payload.info.userDisplayHints),
2429
- canStartRecording: RecordingUtil.canUserStart(payload.info.userDisplayHints),
2430
- canStopRecording: RecordingUtil.canUserStop(payload.info.userDisplayHints),
2431
- canPauseRecording: RecordingUtil.canUserPause(payload.info.userDisplayHints),
2432
- canResumeRecording: RecordingUtil.canUserResume(payload.info.userDisplayHints),
2431
+ canStartRecording: RecordingUtil.canUserStart(
2432
+ payload.info.userDisplayHints,
2433
+ this.selfUserPolicies
2434
+ ),
2435
+ canStopRecording: RecordingUtil.canUserStop(
2436
+ payload.info.userDisplayHints,
2437
+ this.selfUserPolicies
2438
+ ),
2439
+ canPauseRecording: RecordingUtil.canUserPause(
2440
+ payload.info.userDisplayHints,
2441
+ this.selfUserPolicies
2442
+ ),
2443
+ canResumeRecording: RecordingUtil.canUserResume(
2444
+ payload.info.userDisplayHints,
2445
+ this.selfUserPolicies
2446
+ ),
2433
2447
  canRaiseHand: MeetingUtil.canUserRaiseHand(payload.info.userDisplayHints),
2434
2448
  canLowerAllHands: MeetingUtil.canUserLowerAllHands(payload.info.userDisplayHints),
2435
2449
  canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(
@@ -2564,6 +2578,7 @@ export default class Meeting extends StatelessWebexPlugin {
2564
2578
  });
2565
2579
 
2566
2580
  this.recordingController.setDisplayHints(payload.info.userDisplayHints);
2581
+ this.recordingController.setUserPolicy(this.selfUserPolicies);
2567
2582
  this.controlsOptionsManager.setDisplayHints(payload.info.userDisplayHints);
2568
2583
 
2569
2584
  if (changed) {
@@ -3128,11 +3143,21 @@ export default class Meeting extends StatelessWebexPlugin {
3128
3143
  webexMeetingInfo?.hostId ||
3129
3144
  this.owner;
3130
3145
  this.permissionToken = webexMeetingInfo?.permissionToken;
3146
+ this.setSelfUserPolicies(this.permissionToken);
3131
3147
  // Need to populate environment when sending CA event
3132
3148
  this.environment = locusMeetingObject?.info.channel || webexMeetingInfo?.channel;
3133
3149
  }
3134
3150
  }
3135
3151
 
3152
+ /**
3153
+ * Sets the self user policies based on the contents of the permission token
3154
+ * @param {String} permissionToken
3155
+ * @returns {void}
3156
+ */
3157
+ setSelfUserPolicies(permissionToken: string) {
3158
+ this.selfUserPolicies = jwt.decode(permissionToken)?.permission?.userPolicies;
3159
+ }
3160
+
3136
3161
  /**
3137
3162
  * Sets the sip uri on the class instance
3138
3163
  * uses meeting info as precedence
@@ -10,6 +10,7 @@ import {
10
10
  PASSWORD_STATUS,
11
11
  DISPLAY_HINTS,
12
12
  FULL_STATE,
13
+ SELF_POLICY,
13
14
  } from '../constants';
14
15
  import IntentToJoinError from '../common/errors/intent-to-join';
15
16
  import JoinMeetingError from '../common/errors/join-meeting';
@@ -557,6 +558,14 @@ const MeetingUtil = {
557
558
 
558
559
  return locusDeltaRequest;
559
560
  },
561
+
562
+ selfSupportsFeature: (feature: SELF_POLICY, userPolicies: Record<SELF_POLICY, boolean>) => {
563
+ if (!userPolicies) {
564
+ return true;
565
+ }
566
+
567
+ return userPolicies[feature];
568
+ },
560
569
  };
561
570
 
562
571
  export default MeetingUtil;
@@ -1,5 +1,5 @@
1
1
  import PermissionError from '../common/errors/permission';
2
- import {CONTROLS, HTTP_VERBS} from '../constants';
2
+ import {CONTROLS, HTTP_VERBS, SELF_POLICY} from '../constants';
3
3
  import MeetingRequest from '../meeting/request';
4
4
  import RecordingAction from './enums';
5
5
  import Util from './util';
@@ -28,6 +28,14 @@ export default class RecordingController {
28
28
  */
29
29
  private displayHints: Array<string> = [];
30
30
 
31
+ /**
32
+ * @instance
33
+ * @type {Object}
34
+ * @private
35
+ * @memberof RecordingInfo
36
+ */
37
+ private selfUserPolicies: Record<SELF_POLICY, boolean>;
38
+
31
39
  /**
32
40
  * @instance
33
41
  * @type {string}
@@ -126,6 +134,16 @@ export default class RecordingController {
126
134
  this.displayHints = hints;
127
135
  }
128
136
 
137
+ /**
138
+ * @param {Object} selfUserPolicies
139
+ * @returns {void}
140
+ * @public
141
+ * @memberof RecordingController
142
+ */
143
+ public setUserPolicy(selfUserPolicies: Record<SELF_POLICY, boolean>) {
144
+ this.selfUserPolicies = selfUserPolicies;
145
+ }
146
+
129
147
  /**
130
148
  * @param {string} id
131
149
  * @returns {void}
@@ -264,7 +282,7 @@ export default class RecordingController {
264
282
  );
265
283
 
266
284
  // assumes action is proper cased (i.e., Example)
267
- if (Util?.[`canUser${action}`](this.displayHints)) {
285
+ if (Util?.[`canUser${action}`](this.displayHints, this.selfUserPolicies)) {
268
286
  if (this.serviceUrl) {
269
287
  return this.recordingService(action);
270
288
  }
@@ -1,17 +1,34 @@
1
- import {DISPLAY_HINTS} from '../constants';
1
+ import {DISPLAY_HINTS, SELF_POLICY} from '../constants';
2
2
  import RecordingAction from './enums';
3
+ import MeetingUtil from '../meeting/util';
3
4
 
4
- const canUserStart = (displayHints: Array<string>): boolean =>
5
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START);
5
+ const canUserStart = (
6
+ displayHints: Array<string>,
7
+ userPolicies: Record<SELF_POLICY, boolean>
8
+ ): boolean =>
9
+ displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START) &&
10
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
6
11
 
7
- const canUserPause = (displayHints: Array<string>): boolean =>
8
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE);
12
+ const canUserPause = (
13
+ displayHints: Array<string>,
14
+ userPolicies: Record<SELF_POLICY, boolean>
15
+ ): boolean =>
16
+ displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE) &&
17
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
9
18
 
10
- const canUserResume = (displayHints: Array<string>): boolean =>
11
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME);
19
+ const canUserResume = (
20
+ displayHints: Array<string>,
21
+ userPolicies: Record<SELF_POLICY, boolean>
22
+ ): boolean =>
23
+ displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME) &&
24
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
12
25
 
13
- const canUserStop = (displayHints: Array<string>): boolean =>
14
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP);
26
+ const canUserStop = (
27
+ displayHints: Array<string>,
28
+ userPolicies: Record<SELF_POLICY, boolean>
29
+ ): boolean =>
30
+ displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP) &&
31
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
15
32
 
16
33
  const extractLocusId = (url: string) => {
17
34
  return url?.split('/').pop();
@@ -2,6 +2,7 @@
2
2
  * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
3
3
  */
4
4
  import 'jsdom-global/register';
5
+ import jwt from 'jsonwebtoken';
5
6
  import {cloneDeep, forEach, isEqual} from 'lodash';
6
7
  import sinon from 'sinon';
7
8
  import * as internalMediaModule from '@webex/internal-media-core';
@@ -5107,6 +5108,56 @@ describe('plugin-meetings', () => {
5107
5108
  assert.equal(meeting.sipUri, test1);
5108
5109
  });
5109
5110
  });
5111
+
5112
+ describe('#setSelfUserPolicies', () => {
5113
+ it('sets correctly when policy data is present in token', () => {
5114
+ assert.notOk(meeting.selfUserPolicies);
5115
+
5116
+ const dummyToken = 'some data';
5117
+ const policyData = {permission: {userPolicies: {a: true}}};
5118
+
5119
+ sinon.stub(jwt, 'decode').returns(policyData);
5120
+
5121
+ meeting.setSelfUserPolicies(dummyToken);
5122
+
5123
+ assert.deepEqual(meeting.selfUserPolicies, {a: true});
5124
+ });
5125
+
5126
+ it('handles missing permission data', () => {
5127
+ assert.notOk(meeting.selfUserPolicies);
5128
+
5129
+ const dummyToken = 'some data';
5130
+ const policyData = {};
5131
+
5132
+ sinon.stub(jwt, 'decode').returns(policyData);
5133
+
5134
+ meeting.setSelfUserPolicies(dummyToken);
5135
+
5136
+ assert.deepEqual(meeting.selfUserPolicies, undefined);
5137
+ });
5138
+
5139
+ it('handles missing policy data', () => {
5140
+ assert.notOk(meeting.selfUserPolicies);
5141
+
5142
+ const dummyToken = 'some data';
5143
+ const policyData = {permission: {}};
5144
+
5145
+ sinon.stub(jwt, 'decode').returns(policyData);
5146
+
5147
+ meeting.setSelfUserPolicies(dummyToken);
5148
+
5149
+ assert.deepEqual(meeting.selfUserPolicies, undefined);
5150
+ });
5151
+
5152
+ it('handles missing token', () => {
5153
+ assert.notOk(meeting.selfUserPolicies);
5154
+
5155
+ meeting.setSelfUserPolicies();
5156
+
5157
+ assert.deepEqual(meeting.selfUserPolicies, undefined);
5158
+ });
5159
+ });
5160
+
5110
5161
  describe('#unsetRemoteTracks', () => {
5111
5162
  it('should unset the remote tracks and return null', () => {
5112
5163
  meeting.mediaProperties.unsetRemoteTracks = sinon.stub().returns(true);
@@ -5142,6 +5193,7 @@ describe('plugin-meetings', () => {
5142
5193
  assert.calledOnce(meeting.mediaProperties.unsetPeerConnection);
5143
5194
  });
5144
5195
  });
5196
+
5145
5197
  describe('#parseMeetingInfo', () => {
5146
5198
  const checkParseMeetingInfo = (expectedInfoToParse) => {
5147
5199
  assert.equal(meeting.conversationUrl, expectedInfoToParse.conversationUrl);
@@ -5151,6 +5203,7 @@ describe('plugin-meetings', () => {
5151
5203
  assert.equal(meeting.meetingJoinUrl, expectedInfoToParse.meetingJoinUrl);
5152
5204
  assert.equal(meeting.owner, expectedInfoToParse.owner);
5153
5205
  assert.equal(meeting.permissionToken, expectedInfoToParse.permissionToken);
5206
+ assert.deepEqual(meeting.selfUserPolicies, expectedInfoToParse.selfUserPolicies);
5154
5207
  };
5155
5208
 
5156
5209
  it('should parse meeting info from api return when locus meeting object is not available, set values, and return null', () => {
@@ -5162,7 +5215,8 @@ describe('plugin-meetings', () => {
5162
5215
  locusUrl: url1,
5163
5216
  meetingJoinUrl: url2,
5164
5217
  meetingNumber: '12345',
5165
- permissionToken: 'abc',
5218
+ permissionToken:
5219
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX0sImlhdCI6MTY4OTE2NDEwMn0.9uL_U7QUdYyMerrgHC_gCKOax2j_bz04u8Ikbv9KiXU',
5166
5220
  sipMeetingUri: test1,
5167
5221
  sipUrl: test1,
5168
5222
  owner: test2,
@@ -5177,7 +5231,9 @@ describe('plugin-meetings', () => {
5177
5231
  meetingNumber: '12345',
5178
5232
  meetingJoinUrl: url2,
5179
5233
  owner: test2,
5180
- permissionToken: 'abc',
5234
+ selfUserPolicies: {a: true},
5235
+ permissionToken:
5236
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwZXJtaXNzaW9uIjp7InVzZXJQb2xpY2llcyI6eyJhIjp0cnVlfX0sImlhdCI6MTY4OTE2NDEwMn0.9uL_U7QUdYyMerrgHC_gCKOax2j_bz04u8Ikbv9KiXU',
5181
5237
  };
5182
5238
 
5183
5239
  checkParseMeetingInfo(expectedInfoToParse);
@@ -5398,6 +5454,9 @@ describe('plugin-meetings', () => {
5398
5454
  const restorableHasHints = ControlsOptionsUtil.hasHints;
5399
5455
  ControlsOptionsUtil.hasHints = sinon.stub().returns(true);
5400
5456
 
5457
+ const setUserPolicySpy = sinon.spy(meeting.recordingController, 'setUserPolicy');
5458
+ meeting.selfUserPolicies = {a: true};
5459
+
5401
5460
  meeting.setUpLocusInfoMeetingInfoListener();
5402
5461
 
5403
5462
  assert.calledThrice(locusInfoOnSpy);
@@ -5509,6 +5568,8 @@ describe('plugin-meetings', () => {
5509
5568
  displayHints: payload.info.userDisplayHints,
5510
5569
  });
5511
5570
 
5571
+ assert.calledWith(setUserPolicySpy, {a: true});
5572
+
5512
5573
  assert.calledWith(
5513
5574
  TriggerProxy.trigger,
5514
5575
  meeting,
@@ -3,6 +3,8 @@ import {assert} from '@webex/test-helper-chai';
3
3
  import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
4
4
  import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
5
5
  import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
6
+ import Metrics from '@webex/plugin-meetings/src/metrics/index';
7
+ import {SELF_POLICY} from '@webex/plugin-meetings/src/constants';
6
8
  import {DISPLAY_HINTS} from '@webex/plugin-meetings/src/constants';
7
9
  import MockWebex from '@webex/test-helper-mock-webex';
8
10
 
@@ -269,6 +271,33 @@ describe('plugin-meetings', () => {
269
271
 
270
272
  });
271
273
 
274
+ describe('selfSupportsFeature', () => {
275
+ it('returns true if there are no user policies', () => {
276
+ assert.equal(
277
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, undefined),
278
+ true
279
+ );
280
+ });
281
+
282
+ it('returns true if policy is true', () => {
283
+ assert.equal(
284
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, {
285
+ [SELF_POLICY.SUPPORT_ANNOTATION]: true
286
+ }),
287
+ true
288
+ );
289
+ });
290
+
291
+ it('returns false if policy is false', () => {
292
+ assert.equal(
293
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_ANNOTATION, {
294
+ [SELF_POLICY.SUPPORT_ANNOTATION]: false,
295
+ }),
296
+ false
297
+ );
298
+ });
299
+ });
300
+
272
301
  describe('remoteUpdateAudioVideo', () => {
273
302
  it('#Should call meetingRequest.locusMediaRequest with correct parameters', async () => {
274
303
  const meeting = {