@webex/plugin-meetings 2.38.2 → 2.39.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.
- package/dist/constants.js +5 -1
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js +14 -0
- package/dist/controls-options-manager/constants.js.map +1 -0
- package/dist/controls-options-manager/enums.js +15 -0
- package/dist/controls-options-manager/enums.js.map +1 -0
- package/dist/controls-options-manager/index.js +203 -0
- package/dist/controls-options-manager/index.js.map +1 -0
- package/dist/controls-options-manager/util.js +28 -0
- package/dist/controls-options-manager/util.js.map +1 -0
- package/dist/meeting/in-meeting-actions.js +8 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +54 -7
- package/dist/meeting/index.js.map +1 -1
- package/dist/metrics/config.js +1 -11
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/index.js +3 -25
- package/dist/metrics/index.js.map +1 -1
- package/package.json +17 -17
- package/src/constants.ts +4 -0
- package/src/controls-options-manager/constants.ts +5 -0
- package/src/controls-options-manager/enums.ts +6 -0
- package/src/controls-options-manager/index.ts +183 -0
- package/src/controls-options-manager/util.ts +20 -0
- package/src/meeting/in-meeting-actions.ts +16 -0
- package/src/meeting/index.ts +49 -0
- package/src/metrics/config.ts +0 -10
- package/src/metrics/index.ts +3 -24
- package/test/unit/spec/controls-options-manager/index.js +124 -0
- package/test/unit/spec/controls-options-manager/util.js +66 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +8 -0
- package/test/unit/spec/meeting/index.js +15 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {camelCase} from 'lodash';
|
|
2
|
+
import PermissionError from '../common/errors/permission';
|
|
3
|
+
import {CONTROLS, HTTP_VERBS} from '../constants';
|
|
4
|
+
import MeetingRequest from '../meeting/request';
|
|
5
|
+
import LoggerProxy from '../common/logs/logger-proxy';
|
|
6
|
+
import Setting from './enums';
|
|
7
|
+
import Util from './util';
|
|
8
|
+
import {CAN_SET, CAN_UNSET, ENABLED} from './constants';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* docs
|
|
12
|
+
* https://sqbu-github.cisco.com/pages/WebExSquared/locus/guides/mute.html
|
|
13
|
+
* https://confluence-eng-gpk2.cisco.com/conf/display/LOCUS/Hard+Mute+and+Audio+Privacy#HardMuteandAudioPrivacy-SelfMuteonEntry
|
|
14
|
+
* https://confluence-eng-gpk2.cisco.com/conf/pages/viewpage.action?spaceKey=UC&title=WEBEX-124454%3A+UCF%3A+Hard+mute+support+for+Teams+joining+Webex+meeting
|
|
15
|
+
* https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-180867
|
|
16
|
+
* https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-393351
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @description ControlsOptionsManager is responsible for handling the behavior of participant controls when somebody joins a meeting
|
|
21
|
+
* @export
|
|
22
|
+
* @private
|
|
23
|
+
* @class Recording
|
|
24
|
+
*/
|
|
25
|
+
export default class ControlsOptionsManager {
|
|
26
|
+
/**
|
|
27
|
+
* @instance
|
|
28
|
+
* @type {MeetingRequest}
|
|
29
|
+
* @private
|
|
30
|
+
* @memberof ControlsOptionsManager
|
|
31
|
+
*/
|
|
32
|
+
private request: MeetingRequest;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @instance
|
|
36
|
+
* @type {Array}
|
|
37
|
+
* @private
|
|
38
|
+
* @memberof ControlsOptionsManager
|
|
39
|
+
*/
|
|
40
|
+
private displayHints: Array<string> = [];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @instance
|
|
44
|
+
* @type {string}
|
|
45
|
+
* @private
|
|
46
|
+
* @memberof ControlsOptionsManager
|
|
47
|
+
*/
|
|
48
|
+
private locusUrl: string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @param {MeetingRequest} request
|
|
52
|
+
* @param {Object} options
|
|
53
|
+
* @constructor
|
|
54
|
+
* @memberof ControlsOptionsManager
|
|
55
|
+
*/
|
|
56
|
+
constructor(
|
|
57
|
+
request: MeetingRequest,
|
|
58
|
+
options?: {
|
|
59
|
+
locusUrl: string;
|
|
60
|
+
displayHints?: Array<string>;
|
|
61
|
+
}
|
|
62
|
+
) {
|
|
63
|
+
this.initialize(request);
|
|
64
|
+
this.set(options);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {MeetingRequest} request
|
|
69
|
+
* @returns {void}
|
|
70
|
+
* @private
|
|
71
|
+
* @memberof ControlsOptionsManager
|
|
72
|
+
*/
|
|
73
|
+
private initialize(request: MeetingRequest) {
|
|
74
|
+
this.request = request;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {Object} options
|
|
79
|
+
* @returns {void}
|
|
80
|
+
* @public
|
|
81
|
+
* @memberof ControlsOptionsManager
|
|
82
|
+
*/
|
|
83
|
+
public set(options?: {locusUrl: string; displayHints?: Array<string>}) {
|
|
84
|
+
this.extract(options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {string} url
|
|
89
|
+
* @returns {void}
|
|
90
|
+
* @public
|
|
91
|
+
* @memberof ControlsOptionsManager
|
|
92
|
+
*/
|
|
93
|
+
public setLocusUrl(url: string) {
|
|
94
|
+
this.locusUrl = url;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {Array} hints
|
|
99
|
+
* @returns {void}
|
|
100
|
+
* @public
|
|
101
|
+
* @memberof ControlsOptionsManager
|
|
102
|
+
*/
|
|
103
|
+
public setDisplayHints(hints: Array<string>) {
|
|
104
|
+
this.displayHints = hints;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @returns {string}
|
|
109
|
+
* @public
|
|
110
|
+
* @memberof ControlsOptionsManager
|
|
111
|
+
*/
|
|
112
|
+
public getLocusUrl() {
|
|
113
|
+
return this.locusUrl;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* @returns {Array}
|
|
118
|
+
* @public
|
|
119
|
+
* @memberof ControlsOptionsManager
|
|
120
|
+
*/
|
|
121
|
+
public getDisplayHints() {
|
|
122
|
+
return this.displayHints;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @param {Object} options
|
|
127
|
+
* @returns {void}
|
|
128
|
+
* @private
|
|
129
|
+
* @memberof ControlsOptionsManager
|
|
130
|
+
*/
|
|
131
|
+
private extract(options?: {locusUrl: string; displayHints?: Array<string>}) {
|
|
132
|
+
this.setDisplayHints(options?.displayHints);
|
|
133
|
+
this.setLocusUrl(options?.locusUrl);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @param {Setting} setting
|
|
138
|
+
* @param {boolean} enabled
|
|
139
|
+
* @private
|
|
140
|
+
* @memberof ControlsOptionsManager
|
|
141
|
+
* @returns {Promise}
|
|
142
|
+
*/
|
|
143
|
+
private setControls(setting: Setting, enabled: boolean): Promise<any> {
|
|
144
|
+
LoggerProxy.logger.log(`ControlsOptionsManager:index#setControls --> ${setting} [${enabled}]`);
|
|
145
|
+
|
|
146
|
+
if (Util?.[`${enabled ? CAN_SET : CAN_UNSET}${setting}`](this.displayHints)) {
|
|
147
|
+
// @ts-ignore
|
|
148
|
+
return this.request.request({
|
|
149
|
+
uri: `${this.locusUrl}/${CONTROLS}`,
|
|
150
|
+
body: {
|
|
151
|
+
[camelCase(setting)]: {
|
|
152
|
+
[ENABLED]: enabled,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
method: HTTP_VERBS.PATCH,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return Promise.reject(
|
|
160
|
+
new PermissionError(`${setting} [${enabled}] not allowed, due to moderator property.`)
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* @public
|
|
166
|
+
* @param {boolean} enabled
|
|
167
|
+
* @memberof ControlsOptionsManager
|
|
168
|
+
* @returns {Promise}
|
|
169
|
+
*/
|
|
170
|
+
public setMuteOnEntry(enabled: boolean): Promise<any> {
|
|
171
|
+
return this.setControls(Setting.muteOnEntry, enabled);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @public
|
|
176
|
+
* @param {boolean} enabled
|
|
177
|
+
* @memberof ControlsOptionsManager
|
|
178
|
+
* @returns {Promise}
|
|
179
|
+
*/
|
|
180
|
+
public setDisallowUnmute(enabled: boolean): Promise<any> {
|
|
181
|
+
return this.setControls(Setting.disallowUnmute, enabled);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {DISPLAY_HINTS} from '../constants';
|
|
2
|
+
|
|
3
|
+
const canSetMuteOnEntry = (displayHints: Array<string>): boolean =>
|
|
4
|
+
displayHints.includes(DISPLAY_HINTS.ENABLE_MUTE_ON_ENTRY);
|
|
5
|
+
|
|
6
|
+
const canSetDisallowUnmute = (displayHints: Array<string>): boolean =>
|
|
7
|
+
displayHints.includes(DISPLAY_HINTS.ENABLE_HARD_MUTE);
|
|
8
|
+
|
|
9
|
+
const canUnsetMuteOnEntry = (displayHints: Array<string>): boolean =>
|
|
10
|
+
displayHints.includes(DISPLAY_HINTS.DISABLE_MUTE_ON_ENTRY);
|
|
11
|
+
|
|
12
|
+
const canUnsetDisallowUnmute = (displayHints: Array<string>): boolean =>
|
|
13
|
+
displayHints.includes(DISPLAY_HINTS.DISABLE_HARD_MUTE);
|
|
14
|
+
|
|
15
|
+
export default {
|
|
16
|
+
canSetMuteOnEntry,
|
|
17
|
+
canSetDisallowUnmute,
|
|
18
|
+
canUnsetMuteOnEntry,
|
|
19
|
+
canUnsetDisallowUnmute,
|
|
20
|
+
};
|
|
@@ -13,6 +13,10 @@ interface IInMeetingActions {
|
|
|
13
13
|
canAdmitParticipant?: boolean;
|
|
14
14
|
canLock?: boolean;
|
|
15
15
|
canUnlock?: boolean;
|
|
16
|
+
canSetMuteOnEntry?: boolean;
|
|
17
|
+
canUnsetMuteOnEntry?: boolean;
|
|
18
|
+
canSetDisallowUnmute?: boolean;
|
|
19
|
+
canUnsetDisallowUnmute?: boolean;
|
|
16
20
|
canAssignHost?: boolean;
|
|
17
21
|
canStartRecording?: boolean;
|
|
18
22
|
canPauseRecording?: boolean;
|
|
@@ -57,6 +61,14 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
57
61
|
|
|
58
62
|
canStopRecording = null;
|
|
59
63
|
|
|
64
|
+
canSetMuteOnEntry = null;
|
|
65
|
+
|
|
66
|
+
canUnsetMuteOnEntry = null;
|
|
67
|
+
|
|
68
|
+
canSetDisallowUnmute = null;
|
|
69
|
+
|
|
70
|
+
canUnsetDisallowUnmute = null;
|
|
71
|
+
|
|
60
72
|
canRaiseHand = null;
|
|
61
73
|
|
|
62
74
|
canLowerAllHands = null;
|
|
@@ -93,6 +105,10 @@ export default class InMeetingActions implements IInMeetingActions {
|
|
|
93
105
|
canLock: this.canLock,
|
|
94
106
|
canUnlock: this.canUnlock,
|
|
95
107
|
canAssignHost: this.canAssignHost,
|
|
108
|
+
canSetMuteOnEntry: this.canSetMuteOnEntry,
|
|
109
|
+
canUnsetMuteOnEntry: this.canUnsetMuteOnEntry,
|
|
110
|
+
canSetDisallowUnmute: this.canSetDisallowUnmute,
|
|
111
|
+
canUnsetDisallowUnmute: this.canUnsetDisallowUnmute,
|
|
96
112
|
canStartRecording: this.canStartRecording,
|
|
97
113
|
canPauseRecording: this.canPauseRecording,
|
|
98
114
|
canResumeRecording: this.canResumeRecording,
|
package/src/meeting/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ import MeetingRequest from './request';
|
|
|
31
31
|
import Members from '../members/index';
|
|
32
32
|
import MeetingUtil from './util';
|
|
33
33
|
import RecordingUtil from '../recording-controller/util';
|
|
34
|
+
import ControlsOptionsUtil from '../controls-options-manager/util';
|
|
34
35
|
import MediaUtil from '../media/util';
|
|
35
36
|
import Transcription from '../transcription';
|
|
36
37
|
import PasswordError from '../common/errors/password-error';
|
|
@@ -90,6 +91,7 @@ import {Reaction, ReactionType, SkinToneType} from '../reactions/reactions.type'
|
|
|
90
91
|
|
|
91
92
|
import InMeetingActions from './in-meeting-actions';
|
|
92
93
|
import RecordingController from '../recording-controller';
|
|
94
|
+
import ControlsOptionsManager from '../controls-options-manager';
|
|
93
95
|
|
|
94
96
|
const {isBrowser} = BrowserDetection();
|
|
95
97
|
|
|
@@ -455,6 +457,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
455
457
|
queuedMediaUpdates: any[];
|
|
456
458
|
recording: any;
|
|
457
459
|
recordingController: RecordingController;
|
|
460
|
+
controlsOptionsManager: ControlsOptionsManager;
|
|
458
461
|
requiredCaptcha: any;
|
|
459
462
|
shareStatus: string;
|
|
460
463
|
statsAnalyzer: StatsAnalyzer;
|
|
@@ -1002,6 +1005,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1002
1005
|
displayHints: [],
|
|
1003
1006
|
});
|
|
1004
1007
|
|
|
1008
|
+
/**
|
|
1009
|
+
* The class that helps to control recording functions: start, stop, pause, resume, etc
|
|
1010
|
+
* @instance
|
|
1011
|
+
* @type {ControlsOptionsManager}
|
|
1012
|
+
* @public
|
|
1013
|
+
* @memberof Meeting
|
|
1014
|
+
*/
|
|
1015
|
+
this.controlsOptionsManager = new ControlsOptionsManager(this.meetingRequest, {
|
|
1016
|
+
locusUrl: this.locusInfo?.url,
|
|
1017
|
+
displayHints: [],
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1005
1020
|
this.setUpLocusInfoListeners();
|
|
1006
1021
|
this.locusInfo.init(attrs.locus ? attrs.locus : {});
|
|
1007
1022
|
this.hasJoinedOnce = false;
|
|
@@ -2020,6 +2035,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2020
2035
|
this.locusUrl = payload;
|
|
2021
2036
|
this.locusId = this.locusUrl?.split('/').pop();
|
|
2022
2037
|
this.recordingController.setLocusUrl(this.locusUrl);
|
|
2038
|
+
this.controlsOptionsManager.setLocusUrl(this.locusUrl);
|
|
2023
2039
|
});
|
|
2024
2040
|
}
|
|
2025
2041
|
|
|
@@ -2085,6 +2101,16 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2085
2101
|
canAdmitParticipant: MeetingUtil.canAdmitParticipant(payload.info.userDisplayHints),
|
|
2086
2102
|
canLock: MeetingUtil.canUserLock(payload.info.userDisplayHints),
|
|
2087
2103
|
canUnlock: MeetingUtil.canUserUnlock(payload.info.userDisplayHints),
|
|
2104
|
+
canSetDisallowUnmute: ControlsOptionsUtil.canSetDisallowUnmute(
|
|
2105
|
+
payload.info.userDisplayHints
|
|
2106
|
+
),
|
|
2107
|
+
canUnsetDisallowUnmute: ControlsOptionsUtil.canUnsetDisallowUnmute(
|
|
2108
|
+
payload.info.userDisplayHints
|
|
2109
|
+
),
|
|
2110
|
+
canSetMuteOnEntry: ControlsOptionsUtil.canSetMuteOnEntry(payload.info.userDisplayHints),
|
|
2111
|
+
canUnsetMuteOnEntry: ControlsOptionsUtil.canUnsetMuteOnEntry(
|
|
2112
|
+
payload.info.userDisplayHints
|
|
2113
|
+
),
|
|
2088
2114
|
canStartRecording: RecordingUtil.canUserStart(payload.info.userDisplayHints),
|
|
2089
2115
|
canStopRecording: RecordingUtil.canUserStop(payload.info.userDisplayHints),
|
|
2090
2116
|
canPauseRecording: RecordingUtil.canUserPause(payload.info.userDisplayHints),
|
|
@@ -2113,6 +2139,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2113
2139
|
});
|
|
2114
2140
|
|
|
2115
2141
|
this.recordingController.setDisplayHints(payload.info.userDisplayHints);
|
|
2142
|
+
this.controlsOptionsManager.setDisplayHints(payload.info.userDisplayHints);
|
|
2116
2143
|
|
|
2117
2144
|
if (changed) {
|
|
2118
2145
|
Trigger.trigger(
|
|
@@ -5526,6 +5553,28 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5526
5553
|
return this.recordingController.startRecording();
|
|
5527
5554
|
}
|
|
5528
5555
|
|
|
5556
|
+
/**
|
|
5557
|
+
* set the mute on entry flag for participants if you're the host
|
|
5558
|
+
* @returns {Promise}
|
|
5559
|
+
* @param {boolean} enabled
|
|
5560
|
+
* @public
|
|
5561
|
+
* @memberof Meeting
|
|
5562
|
+
*/
|
|
5563
|
+
public setMuteOnEntry(enabled: boolean) {
|
|
5564
|
+
return this.controlsOptionsManager.setMuteOnEntry(enabled);
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5567
|
+
/**
|
|
5568
|
+
* set the disallow unmute flag for participants if you're the host
|
|
5569
|
+
* @returns {Promise}
|
|
5570
|
+
* @param {boolean} enabled
|
|
5571
|
+
* @public
|
|
5572
|
+
* @memberof Meeting
|
|
5573
|
+
*/
|
|
5574
|
+
public setDisallowUnmute(enabled: boolean) {
|
|
5575
|
+
return this.controlsOptionsManager.setDisallowUnmute(enabled);
|
|
5576
|
+
}
|
|
5577
|
+
|
|
5529
5578
|
/**
|
|
5530
5579
|
* End the recording of this meeting
|
|
5531
5580
|
* @returns {Promise}
|
package/src/metrics/config.ts
CHANGED
|
@@ -481,15 +481,5 @@ export const errorObjects = {
|
|
|
481
481
|
|
|
482
482
|
export const UNKNOWN = 'unknown';
|
|
483
483
|
|
|
484
|
-
export const OS_NAME = {
|
|
485
|
-
WINDOWS: 'windows',
|
|
486
|
-
MAC: 'mac',
|
|
487
|
-
IOS: 'ios',
|
|
488
|
-
ANDROID: 'android',
|
|
489
|
-
CHROME: 'chrome',
|
|
490
|
-
LINUX: 'linux',
|
|
491
|
-
OTHERS: 'other',
|
|
492
|
-
};
|
|
493
|
-
|
|
494
484
|
export const CLIENT_NAME = 'webex-js-sdk';
|
|
495
485
|
export const PLATFORM = 'Web';
|
package/src/metrics/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ import uuid from 'uuid';
|
|
|
8
8
|
import window from 'global/window';
|
|
9
9
|
import anonymize from 'ip-anonymize';
|
|
10
10
|
|
|
11
|
+
import {getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
11
12
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
12
13
|
import {MEETING_ERRORS} from '../constants';
|
|
13
14
|
import BrowserDetection from '../common/browser-detection';
|
|
@@ -16,22 +17,11 @@ import {
|
|
|
16
17
|
error,
|
|
17
18
|
eventType,
|
|
18
19
|
errorCodes as ERROR_CODE,
|
|
19
|
-
OS_NAME,
|
|
20
20
|
UNKNOWN,
|
|
21
21
|
CLIENT_NAME,
|
|
22
22
|
mediaType,
|
|
23
23
|
} from './config';
|
|
24
24
|
|
|
25
|
-
const OSMap = {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
'Chrome OS': OS_NAME.chrome,
|
|
28
|
-
macOS: OS_NAME.MAC,
|
|
29
|
-
Windows: OS_NAME.WINDOWS,
|
|
30
|
-
iOS: OS_NAME.IOS,
|
|
31
|
-
Android: OS_NAME.ANDROID,
|
|
32
|
-
Linux: OS_NAME.LINUX,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
25
|
const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
36
26
|
|
|
37
27
|
// Apply a CIDR /28 format to the IPV4 and /96 to the IPV6 addresses
|
|
@@ -205,7 +195,7 @@ class Metrics {
|
|
|
205
195
|
localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
|
|
206
196
|
osVersion: getOSVersion() || 'unknown',
|
|
207
197
|
subClientType: options.subClientType,
|
|
208
|
-
os:
|
|
198
|
+
os: getOSNameInternal(),
|
|
209
199
|
browser: getBrowserName(),
|
|
210
200
|
browserVersion: getBrowserVersion(),
|
|
211
201
|
},
|
|
@@ -256,17 +246,6 @@ class Metrics {
|
|
|
256
246
|
return payload;
|
|
257
247
|
}
|
|
258
248
|
|
|
259
|
-
/**
|
|
260
|
-
* returns metrics friendly OS versions
|
|
261
|
-
* @param {String} osName Os name
|
|
262
|
-
* @returns {String}
|
|
263
|
-
* @private
|
|
264
|
-
* @memberof Metrics
|
|
265
|
-
*/
|
|
266
|
-
private getOsName() {
|
|
267
|
-
return OSMap[getOSName()] ?? OS_NAME.OTHERS;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
249
|
/**
|
|
271
250
|
* get the payload specific for a media quality event through call analyzer
|
|
272
251
|
* @param {String} eventType the event name
|
|
@@ -311,7 +290,7 @@ class Metrics {
|
|
|
311
290
|
clientType: options.clientType, // TODO: Only clientType: 'TEAMS_CLIENT' is whitelisted
|
|
312
291
|
clientVersion: `${CLIENT_NAME}/${this.webex.version}`,
|
|
313
292
|
localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
|
|
314
|
-
os:
|
|
293
|
+
os: getOSNameInternal(),
|
|
315
294
|
osVersion: getOSVersion() || UNKNOWN,
|
|
316
295
|
subClientType: options.subClientType,
|
|
317
296
|
browser: getBrowserName(),
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import ControlsOptionsManager from '@webex/plugin-meetings/src/controls-options-manager';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import {assert} from '@webex/test-helper-chai';
|
|
4
|
+
import { HTTP_VERBS } from '@webex/plugin-meetings/src/constants';
|
|
5
|
+
|
|
6
|
+
describe('plugin-meetings', () => {
|
|
7
|
+
describe('controls-options-manager tests', () => {
|
|
8
|
+
describe('index', () => {
|
|
9
|
+
let request;
|
|
10
|
+
|
|
11
|
+
describe('class tests', () => {
|
|
12
|
+
it('can set and extract new values later on', () => {
|
|
13
|
+
const manager = new ControlsOptionsManager({});
|
|
14
|
+
assert.isUndefined(manager.getLocusUrl());
|
|
15
|
+
manager.set({
|
|
16
|
+
locusUrl: 'test/id',
|
|
17
|
+
})
|
|
18
|
+
assert(manager.getLocusUrl(), 'test/id');
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('Mute On Entry', () => {
|
|
23
|
+
let manager;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
request = {
|
|
27
|
+
request: sinon.stub().returns(Promise.resolve()),
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
manager = new ControlsOptionsManager(request);
|
|
31
|
+
|
|
32
|
+
manager.set({
|
|
33
|
+
locusUrl: 'test/id',
|
|
34
|
+
displayHints: [],
|
|
35
|
+
})
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('setMuteOnEntry', () => {
|
|
39
|
+
it('rejects when correct display hint is not present enabled=false', () => {
|
|
40
|
+
const result = manager.setMuteOnEntry(false);
|
|
41
|
+
|
|
42
|
+
assert.notCalled(request.request);
|
|
43
|
+
|
|
44
|
+
assert.isRejected(result);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('rejects when correct display hint is not present enabled=true', () => {
|
|
48
|
+
const result = manager.setMuteOnEntry(true);
|
|
49
|
+
|
|
50
|
+
assert.notCalled(request.request);
|
|
51
|
+
|
|
52
|
+
assert.isRejected(result);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('can set mute on entry when the display hint is available enabled=true', () => {
|
|
56
|
+
manager.setDisplayHints(['ENABLE_MUTE_ON_ENTRY']);
|
|
57
|
+
|
|
58
|
+
const result = manager.setMuteOnEntry(true);
|
|
59
|
+
|
|
60
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
61
|
+
body: { muteOnEntry: { enabled: true } },
|
|
62
|
+
method: HTTP_VERBS.PATCH});
|
|
63
|
+
|
|
64
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('can set mute on entry when the display hint is available enabled=false', () => {
|
|
68
|
+
manager.setDisplayHints(['DISABLE_MUTE_ON_ENTRY']);
|
|
69
|
+
|
|
70
|
+
const result = manager.setMuteOnEntry(false);
|
|
71
|
+
|
|
72
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
73
|
+
body: { muteOnEntry: { enabled: false } },
|
|
74
|
+
method: HTTP_VERBS.PATCH});
|
|
75
|
+
|
|
76
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('setDisallowUnmute', () => {
|
|
81
|
+
it('rejects when correct display hint is not present enabled=false', () => {
|
|
82
|
+
const result = manager.setDisallowUnmute(false);
|
|
83
|
+
|
|
84
|
+
assert.notCalled(request.request);
|
|
85
|
+
|
|
86
|
+
assert.isRejected(result);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('rejects when correct display hint is not present enabled=true', () => {
|
|
90
|
+
const result = manager.setDisallowUnmute(true);
|
|
91
|
+
|
|
92
|
+
assert.notCalled(request.request);
|
|
93
|
+
|
|
94
|
+
assert.isRejected(result);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('can set mute on entry when the display hint is available enabled=true', () => {
|
|
98
|
+
manager.setDisplayHints(['ENABLE_HARD_MUTE']);
|
|
99
|
+
|
|
100
|
+
const result = manager.setDisallowUnmute(true);
|
|
101
|
+
|
|
102
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
103
|
+
body: { disallowUnmute: { enabled: true } },
|
|
104
|
+
method: HTTP_VERBS.PATCH});
|
|
105
|
+
|
|
106
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('can set mute on entry when the display hint is available enabled=false', () => {
|
|
110
|
+
manager.setDisplayHints(['DISABLE_HARD_MUTE']);
|
|
111
|
+
|
|
112
|
+
const result = manager.setDisallowUnmute(false);
|
|
113
|
+
|
|
114
|
+
assert.calledWith(request.request, { uri: 'test/id/controls',
|
|
115
|
+
body: { disallowUnmute: { enabled: false } },
|
|
116
|
+
method: HTTP_VERBS.PATCH});
|
|
117
|
+
|
|
118
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import ControlsOptionsUtil from '@webex/plugin-meetings/src/controls-options-manager/util';
|
|
2
|
+
import { assert } from 'chai';
|
|
3
|
+
|
|
4
|
+
describe('plugin-meetings', () => {
|
|
5
|
+
describe('controls-option-manager tests', () => {
|
|
6
|
+
describe('util tests', () => {
|
|
7
|
+
|
|
8
|
+
let locusInfo;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
locusInfo = {
|
|
12
|
+
parsedLocus: {
|
|
13
|
+
info: {
|
|
14
|
+
userDisplayHints: [],
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe('canUserSetMuteOnEntry', () => {
|
|
21
|
+
it('can set mute on entry enable', () => {
|
|
22
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('ENABLE_MUTE_ON_ENTRY');
|
|
23
|
+
|
|
24
|
+
assert.equal(ControlsOptionsUtil.canSetMuteOnEntry(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('can set mute on entry disable', () => {
|
|
28
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('DISABLE_MUTE_ON_ENTRY');
|
|
29
|
+
|
|
30
|
+
assert.equal(ControlsOptionsUtil.canUnsetMuteOnEntry(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('rejects when correct display hint is not present for setting mute on entry', () => {
|
|
34
|
+
assert.equal(ControlsOptionsUtil.canSetMuteOnEntry(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('rejects when correct display hint is not present for unsetting mute on entry', () => {
|
|
38
|
+
assert.equal(ControlsOptionsUtil.canUnsetMuteOnEntry(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('canSetDisallowUnmute', () => {
|
|
43
|
+
it('can set disallow unmute enable', () => {
|
|
44
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('ENABLE_HARD_MUTE');
|
|
45
|
+
|
|
46
|
+
assert.equal(ControlsOptionsUtil.canSetDisallowUnmute(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('can set disallow unmute disable', () => {
|
|
50
|
+
locusInfo.parsedLocus.info.userDisplayHints.push('DISABLE_HARD_MUTE');
|
|
51
|
+
|
|
52
|
+
assert.equal(ControlsOptionsUtil.canUnsetDisallowUnmute(locusInfo.parsedLocus.info.userDisplayHints), true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('rejects when correct display hint is not present', () => {
|
|
56
|
+
assert.equal(ControlsOptionsUtil.canSetDisallowUnmute(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('rejects when correct display hint is not present', () => {
|
|
60
|
+
assert.equal(ControlsOptionsUtil.canUnsetDisallowUnmute(locusInfo.parsedLocus.info.userDisplayHints), false);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -13,6 +13,10 @@ describe('plugin-meetings', () => {
|
|
|
13
13
|
canStartRecording: null,
|
|
14
14
|
canPauseRecording: null,
|
|
15
15
|
canResumeRecording: null,
|
|
16
|
+
canSetMuteOnEntry: null,
|
|
17
|
+
canUnsetMuteOnEntry: null,
|
|
18
|
+
canSetDisallowUnmute: null,
|
|
19
|
+
canUnsetDisallowUnmute: null,
|
|
16
20
|
canStopRecording: null,
|
|
17
21
|
canRaiseHand: null,
|
|
18
22
|
canLowerAllHands: null,
|
|
@@ -49,6 +53,10 @@ describe('plugin-meetings', () => {
|
|
|
49
53
|
'canPauseRecording',
|
|
50
54
|
'canResumeRecording',
|
|
51
55
|
'canStopRecording',
|
|
56
|
+
'canSetMuteOnEntry',
|
|
57
|
+
'canUnsetMuteOnEntry',
|
|
58
|
+
'canSetDisallowUnmute',
|
|
59
|
+
'canUnsetDisallowUnmute',
|
|
52
60
|
'canRaiseHand',
|
|
53
61
|
'canLowerAllHands',
|
|
54
62
|
'canLowerSomeoneElsesHand',
|