@webex/plugin-meetings 3.8.0-next.3 → 3.8.0-next.30
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/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +4 -4
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/meeting/index.js +89 -5
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +21 -5
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/util.js +4 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +359 -60
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +60 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +10 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +3 -0
- package/dist/member/util.js.map +1 -1
- package/dist/metrics/constants.js +9 -0
- package/dist/metrics/constants.js.map +1 -1
- package/dist/reachability/clusterReachability.js +52 -8
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +70 -45
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -0
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/request.js +19 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/recording-controller/util.js +5 -5
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/meeting/index.d.ts +30 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +80 -0
- package/dist/types/meetings/index.d.ts +29 -0
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/metrics/constants.d.ts +9 -0
- package/dist/types/reachability/clusterReachability.d.ts +13 -1
- package/dist/types/reachability/index.d.ts +2 -1
- package/dist/types/reachability/reachability.types.d.ts +5 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +22 -22
- package/src/config.ts +1 -0
- package/src/constants.ts +1 -0
- package/src/interpretation/index.ts +3 -3
- package/src/locus-info/controlsUtils.ts +2 -2
- package/src/meeting/index.ts +85 -7
- package/src/meeting/locusMediaRequest.ts +27 -4
- package/src/meeting/util.ts +2 -1
- package/src/meeting-info/meeting-info-v2.ts +247 -6
- package/src/meetings/index.ts +72 -1
- package/src/member/index.ts +11 -0
- package/src/member/util.ts +3 -0
- package/src/metrics/constants.ts +9 -0
- package/src/reachability/clusterReachability.ts +47 -1
- package/src/reachability/index.ts +15 -0
- package/src/reachability/reachability.types.ts +6 -0
- package/src/reachability/request.ts +7 -0
- package/src/recording-controller/util.ts +17 -13
- package/test/unit/spec/interpretation/index.ts +39 -1
- package/test/unit/spec/locus-info/controlsUtils.js +8 -0
- package/test/unit/spec/meeting/index.js +200 -108
- package/test/unit/spec/meeting/locusMediaRequest.ts +96 -58
- package/test/unit/spec/meeting/utils.js +55 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +443 -114
- package/test/unit/spec/meetings/index.js +78 -1
- package/test/unit/spec/member/index.js +7 -0
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/reachability/clusterReachability.ts +47 -1
- package/test/unit/spec/reachability/index.ts +12 -0
- package/test/unit/spec/reachability/request.js +47 -2
|
@@ -206,8 +206,8 @@ ControlsUtils.getControls = (oldControls: any, newControls: any) => {
|
|
|
206
206
|
),
|
|
207
207
|
|
|
208
208
|
hasPracticeSessionEnabledChanged: !isEqual(
|
|
209
|
-
previous?.practiceSession?.enabled,
|
|
210
|
-
current?.practiceSession?.enabled
|
|
209
|
+
!!previous?.practiceSession?.enabled,
|
|
210
|
+
!!current?.practiceSession?.enabled
|
|
211
211
|
),
|
|
212
212
|
|
|
213
213
|
hasStageViewChanged: !isEqual(previous?.videoLayout, current?.videoLayout),
|
package/src/meeting/index.ts
CHANGED
|
@@ -241,6 +241,8 @@ export type CallStateForMetrics = {
|
|
|
241
241
|
sessionCorrelationId?: string;
|
|
242
242
|
joinTrigger?: string;
|
|
243
243
|
loginType?: string;
|
|
244
|
+
userNameInput?: string;
|
|
245
|
+
emailInput?: string;
|
|
244
246
|
};
|
|
245
247
|
|
|
246
248
|
export const MEDIA_UPDATE_TYPE = {
|
|
@@ -1627,6 +1629,38 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1627
1629
|
this.callStateForMetrics.correlationId = correlationId;
|
|
1628
1630
|
}
|
|
1629
1631
|
|
|
1632
|
+
/**
|
|
1633
|
+
* Getter - Returns callStateForMetrics.userNameInput
|
|
1634
|
+
* @returns {string}
|
|
1635
|
+
*/
|
|
1636
|
+
get userNameInput() {
|
|
1637
|
+
return this.callStateForMetrics?.userNameInput;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
/**
|
|
1641
|
+
* Setter - sets callStateForMetrics.userNameInput
|
|
1642
|
+
* @param {string} userNameInput
|
|
1643
|
+
*/
|
|
1644
|
+
set userNameInput(userNameInput: string) {
|
|
1645
|
+
this.callStateForMetrics.userNameInput = userNameInput;
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
/**
|
|
1649
|
+
* Getter - Returns callStateForMetrics.emailInput
|
|
1650
|
+
* @returns {string}
|
|
1651
|
+
*/
|
|
1652
|
+
get emailInput() {
|
|
1653
|
+
return this.callStateForMetrics?.emailInput;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
/**
|
|
1657
|
+
* Setter - sets callStateForMetrics.emailInput
|
|
1658
|
+
* @param {string} emailInput
|
|
1659
|
+
*/
|
|
1660
|
+
set emailInput(emailInput: string) {
|
|
1661
|
+
this.callStateForMetrics.emailInput = emailInput;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1630
1664
|
/**
|
|
1631
1665
|
* Getter - Returns callStateForMetrics.sessionCorrelationId
|
|
1632
1666
|
* @returns {string}
|
|
@@ -1652,6 +1686,33 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1652
1686
|
return this.#isoLocalClientMeetingJoinTime;
|
|
1653
1687
|
}
|
|
1654
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
|
+
|
|
1655
1716
|
/**
|
|
1656
1717
|
* Set meeting info and trigger `MEETING_INFO_AVAILABLE` event
|
|
1657
1718
|
* @param {any} info
|
|
@@ -5684,8 +5745,6 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
5684
5745
|
// @ts-ignore
|
|
5685
5746
|
this.webex.internal.device.meetingStarted();
|
|
5686
5747
|
|
|
5687
|
-
this.#isoLocalClientMeetingJoinTime = new Date().toISOString();
|
|
5688
|
-
|
|
5689
5748
|
LoggerProxy.logger.log('Meeting:index#join --> Success');
|
|
5690
5749
|
|
|
5691
5750
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.JOIN_SUCCESS, {
|
|
@@ -6146,10 +6205,18 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6146
6205
|
},
|
|
6147
6206
|
options: {meetingId: this.id, rawError: error},
|
|
6148
6207
|
});
|
|
6149
|
-
} else if (
|
|
6150
|
-
error
|
|
6151
|
-
|
|
6152
|
-
|
|
6208
|
+
} else if (error instanceof Errors.SdpOfferHandlingError) {
|
|
6209
|
+
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.correlationId);
|
|
6210
|
+
|
|
6211
|
+
// @ts-ignore
|
|
6212
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
6213
|
+
name: 'client.media-engine.remote-sdp-received',
|
|
6214
|
+
payload: {
|
|
6215
|
+
canProceed: false,
|
|
6216
|
+
},
|
|
6217
|
+
options: {meetingId: this.id, rawError: error},
|
|
6218
|
+
});
|
|
6219
|
+
} else if (error instanceof Errors.SdpAnswerHandlingError) {
|
|
6153
6220
|
sendBehavioralMetric(BEHAVIORAL_METRICS.PEERCONNECTION_FAILURE, error, this.correlationId);
|
|
6154
6221
|
|
|
6155
6222
|
// @ts-ignore
|
|
@@ -6160,6 +6227,13 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6160
6227
|
},
|
|
6161
6228
|
options: {meetingId: this.id, rawError: error},
|
|
6162
6229
|
});
|
|
6230
|
+
|
|
6231
|
+
if (this.deferSDPAnswer) {
|
|
6232
|
+
clearTimeout(this.sdpResponseTimer);
|
|
6233
|
+
this.sdpResponseTimer = undefined;
|
|
6234
|
+
|
|
6235
|
+
this.deferSDPAnswer.reject();
|
|
6236
|
+
}
|
|
6163
6237
|
} else if (error instanceof Errors.SdpError) {
|
|
6164
6238
|
// this covers also the case of Errors.IceGatheringError which extends Errors.SdpError
|
|
6165
6239
|
sendBehavioralMetric(BEHAVIORAL_METRICS.INVALID_ICE_CANDIDATE, error, this.correlationId);
|
|
@@ -8681,6 +8755,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8681
8755
|
LoggerProxy.logger.log(
|
|
8682
8756
|
`Meeting:index#handleShareVideoStreamMuteStateChange --> Share video stream mute state changed to muted ${muted}`
|
|
8683
8757
|
);
|
|
8758
|
+
|
|
8759
|
+
const shareVideoStreamSettings = this.mediaProperties?.shareVideoStream?.getSettings();
|
|
8760
|
+
|
|
8684
8761
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_SHARE_VIDEO_MUTE_STATE_CHANGE, {
|
|
8685
8762
|
correlationId: this.correlationId,
|
|
8686
8763
|
muted,
|
|
@@ -8689,8 +8766,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
8689
8766
|
// SDK to TypeScript 5, which may affect other packages, use bracket notation for now, since
|
|
8690
8767
|
// all we're doing here is adding metrics.
|
|
8691
8768
|
// eslint-disable-next-line dot-notation
|
|
8692
|
-
displaySurface:
|
|
8769
|
+
displaySurface: shareVideoStreamSettings?.['displaySurface'],
|
|
8693
8770
|
isMultistream: this.isMultistream,
|
|
8771
|
+
frameRate: shareVideoStreamSettings?.frameRate,
|
|
8694
8772
|
});
|
|
8695
8773
|
};
|
|
8696
8774
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable valid-jsdoc */
|
|
2
2
|
import {defer} from 'lodash';
|
|
3
|
-
import {Defer} from '@webex/common';
|
|
3
|
+
import {Defer, transferEvents} from '@webex/common';
|
|
4
|
+
import {EventEmitter} from 'events';
|
|
4
5
|
import {WebexPlugin} from '@webex/webex-core';
|
|
5
6
|
import {MEDIA, HTTP_VERBS, ROAP} from '../constants';
|
|
6
7
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
@@ -250,12 +251,19 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
|
250
251
|
this.confluenceState = 'creation in progress';
|
|
251
252
|
}
|
|
252
253
|
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
const upload = new EventEmitter();
|
|
255
|
+
const download = new EventEmitter();
|
|
256
|
+
|
|
257
|
+
const options = {
|
|
255
258
|
method: HTTP_VERBS.PUT,
|
|
256
259
|
uri,
|
|
257
260
|
body,
|
|
258
|
-
|
|
261
|
+
upload,
|
|
262
|
+
download,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
const promise = this.request(options)
|
|
259
267
|
.then((result) => {
|
|
260
268
|
if (isRequestAffectingConfluenceState(request)) {
|
|
261
269
|
this.confluenceState = 'created';
|
|
@@ -294,6 +302,21 @@ export class LocusMediaRequest extends WebexPlugin {
|
|
|
294
302
|
|
|
295
303
|
throw e;
|
|
296
304
|
});
|
|
305
|
+
|
|
306
|
+
if (request.type === 'RoapMessage') {
|
|
307
|
+
const setupProgressListener = (direction: string, eventEmitter: EventEmitter) => {
|
|
308
|
+
eventEmitter.on('progress', (progressEvent: ProgressEvent) => {
|
|
309
|
+
LoggerProxy.logger.info(
|
|
310
|
+
`${request.type}: ${direction} Progress, Timestamp: ${progressEvent.timeStamp}, Progress: ${progressEvent.loaded}/${progressEvent.total}`
|
|
311
|
+
);
|
|
312
|
+
});
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
setupProgressListener('Upload', options.upload);
|
|
316
|
+
setupProgressListener('Download', options.download);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return promise;
|
|
297
320
|
}
|
|
298
321
|
|
|
299
322
|
/**
|
package/src/meeting/util.ts
CHANGED
|
@@ -176,11 +176,12 @@ const MeetingUtil = {
|
|
|
176
176
|
deviceCapabilities: options.deviceCapabilities,
|
|
177
177
|
liveAnnotationSupported: options.liveAnnotationSupported,
|
|
178
178
|
clientMediaPreferences,
|
|
179
|
+
alias: options.alias,
|
|
179
180
|
})
|
|
180
181
|
.then((res) => {
|
|
181
182
|
const parsed = MeetingUtil.parseLocusJoin(res);
|
|
182
183
|
meeting.setLocus(parsed);
|
|
183
|
-
|
|
184
|
+
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
185
|
webex.internal.newMetrics.submitClientEvent({
|
|
185
186
|
name: 'client.locus.join.response',
|
|
186
187
|
payload: {
|
|
@@ -16,6 +16,9 @@ const CAPTCHA_ERROR_DEFAULT_MESSAGE =
|
|
|
16
16
|
'Captcha required. Call fetchMeetingInfo() with captchaInfo argument';
|
|
17
17
|
const ADHOC_MEETING_DEFAULT_ERROR =
|
|
18
18
|
'Failed starting the adhoc meeting, Please contact support team ';
|
|
19
|
+
const MEETING_IS_IN_PROGRESS_MESSAGE = 'Meeting is in progress';
|
|
20
|
+
const STATIC_MEETING_LINK_ALREADY_EXISTS_MESSAGE = 'Static meeting link already exists';
|
|
21
|
+
const FETCH_STATIC_MEETING_LINK = 'Meeting link does not exists for conversation';
|
|
19
22
|
const CAPTCHA_ERROR_REQUIRES_PASSWORD_CODES = [423005, 423006];
|
|
20
23
|
const CAPTCHA_ERROR_REQUIRES_REGISTRATION_ID_CODES = [423007];
|
|
21
24
|
|
|
@@ -193,6 +196,77 @@ export class MeetingInfoV2JoinForbiddenError extends Error {
|
|
|
193
196
|
}
|
|
194
197
|
}
|
|
195
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Error fetching static link for a conversation when it does not exist
|
|
201
|
+
*/
|
|
202
|
+
export class MeetingInfoV2StaticLinkDoesNotExistError extends Error {
|
|
203
|
+
sdkMessage: any;
|
|
204
|
+
wbxAppApiCode: any;
|
|
205
|
+
body: any;
|
|
206
|
+
/**
|
|
207
|
+
*
|
|
208
|
+
* @constructor
|
|
209
|
+
* @param {Number} [wbxAppApiErrorCode]
|
|
210
|
+
* @param {String} [message]
|
|
211
|
+
*/
|
|
212
|
+
constructor(wbxAppApiErrorCode?: number, message: string = FETCH_STATIC_MEETING_LINK) {
|
|
213
|
+
super(`${message}, code=${wbxAppApiErrorCode}`);
|
|
214
|
+
this.name = 'MeetingInfoV2StaticLinkDoesNotExistError';
|
|
215
|
+
this.sdkMessage = message;
|
|
216
|
+
this.stack = new Error().stack;
|
|
217
|
+
this.wbxAppApiCode = wbxAppApiErrorCode;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Error enabling/disabling static meeting link
|
|
223
|
+
*/
|
|
224
|
+
export class MeetingInfoV2MeetingIsInProgressError extends Error {
|
|
225
|
+
sdkMessage: any;
|
|
226
|
+
wbxAppApiCode: any;
|
|
227
|
+
body: any;
|
|
228
|
+
/**
|
|
229
|
+
*
|
|
230
|
+
* @constructor
|
|
231
|
+
* @param {Number} [wbxAppApiErrorCode]
|
|
232
|
+
* @param {String} [message]
|
|
233
|
+
* @param {Boolean} [enable]
|
|
234
|
+
*/
|
|
235
|
+
constructor(
|
|
236
|
+
wbxAppApiErrorCode?: number,
|
|
237
|
+
message = MEETING_IS_IN_PROGRESS_MESSAGE,
|
|
238
|
+
enable = false
|
|
239
|
+
) {
|
|
240
|
+
super(`${message}, code=${wbxAppApiErrorCode}, enable=${enable}`);
|
|
241
|
+
this.name = 'MeetingInfoV2MeetingIsInProgressError';
|
|
242
|
+
this.sdkMessage = message;
|
|
243
|
+
this.stack = new Error().stack;
|
|
244
|
+
this.wbxAppApiCode = wbxAppApiErrorCode;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Error enabling/disabling static meeting link
|
|
250
|
+
*/
|
|
251
|
+
export class MeetingInfoV2StaticMeetingLinkAlreadyExists extends Error {
|
|
252
|
+
sdkMessage: any;
|
|
253
|
+
wbxAppApiCode: any;
|
|
254
|
+
body: any;
|
|
255
|
+
/**
|
|
256
|
+
*
|
|
257
|
+
* @constructor
|
|
258
|
+
* @param {Number} [wbxAppApiErrorCode]
|
|
259
|
+
* @param {String} [message]
|
|
260
|
+
*/
|
|
261
|
+
constructor(wbxAppApiErrorCode?: number, message = STATIC_MEETING_LINK_ALREADY_EXISTS_MESSAGE) {
|
|
262
|
+
super(`${message}, code=${wbxAppApiErrorCode}`);
|
|
263
|
+
this.name = 'MeetingInfoV2StaticMeetingLinkAlreadyExists';
|
|
264
|
+
this.sdkMessage = message;
|
|
265
|
+
this.stack = new Error().stack;
|
|
266
|
+
this.wbxAppApiCode = wbxAppApiErrorCode;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
196
270
|
/**
|
|
197
271
|
* @class MeetingInfo
|
|
198
272
|
*/
|
|
@@ -293,17 +367,20 @@ export default class MeetingInfoV2 {
|
|
|
293
367
|
};
|
|
294
368
|
|
|
295
369
|
/**
|
|
296
|
-
*
|
|
370
|
+
* helper function to either create an adhoc space meeting or enable static meeting link
|
|
297
371
|
* @param {String} conversationUrl conversationUrl to start adhoc meeting on
|
|
298
372
|
* @param {String} installedOrgID org ID of user's machine
|
|
373
|
+
* @param {Boolean} enableStaticMeetingLink whether or not to enable static meeting link
|
|
299
374
|
* @returns {Promise} returns a meeting info object
|
|
300
375
|
* @public
|
|
301
376
|
* @memberof MeetingInfo
|
|
302
377
|
*/
|
|
303
|
-
async
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
378
|
+
async createAdhocSpaceMeetingOrEnableStaticMeetingLink(
|
|
379
|
+
conversationUrl: string,
|
|
380
|
+
installedOrgID?: string,
|
|
381
|
+
// setting this to true enables static meeting link
|
|
382
|
+
enableStaticMeetingLink = false
|
|
383
|
+
) {
|
|
307
384
|
const getInvitees = (particpants = []) => {
|
|
308
385
|
const invitees = [];
|
|
309
386
|
|
|
@@ -329,6 +406,7 @@ export default class MeetingInfoV2 {
|
|
|
329
406
|
kroUrl: conversation.kmsResourceObjectUrl,
|
|
330
407
|
invitees: getInvitees(conversation.participants?.items),
|
|
331
408
|
installedOrgID,
|
|
409
|
+
schedule: enableStaticMeetingLink,
|
|
332
410
|
};
|
|
333
411
|
|
|
334
412
|
if (installedOrgID) {
|
|
@@ -344,7 +422,23 @@ export default class MeetingInfoV2 {
|
|
|
344
422
|
uri,
|
|
345
423
|
body,
|
|
346
424
|
});
|
|
347
|
-
})
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Creates adhoc space meetings for a space by fetching the conversation infomation
|
|
430
|
+
* @param {String} conversationUrl conversationUrl to start adhoc meeting on
|
|
431
|
+
* @param {String} installedOrgID org ID of user's machine
|
|
432
|
+
* @returns {Promise} returns a meeting info object
|
|
433
|
+
* @public
|
|
434
|
+
* @memberof MeetingInfo
|
|
435
|
+
*/
|
|
436
|
+
async createAdhocSpaceMeeting(conversationUrl: string, installedOrgID?: string) {
|
|
437
|
+
if (!this.webex.meetings.preferredWebexSite) {
|
|
438
|
+
throw Error('No preferred webex site found');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return this.createAdhocSpaceMeetingOrEnableStaticMeetingLink(conversationUrl, installedOrgID)
|
|
348
442
|
.then((requestResult) => {
|
|
349
443
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
350
444
|
|
|
@@ -363,6 +457,153 @@ export default class MeetingInfoV2 {
|
|
|
363
457
|
});
|
|
364
458
|
}
|
|
365
459
|
|
|
460
|
+
/**
|
|
461
|
+
* Fetches details for static meeting link
|
|
462
|
+
* @param {String} conversationUrl conversationUrl that's required to find static meeting link if it exists
|
|
463
|
+
* @returns {Promise} returns a Promise
|
|
464
|
+
* @public
|
|
465
|
+
* @memberof MeetingInfo
|
|
466
|
+
*/
|
|
467
|
+
async fetchStaticMeetingLink(conversationUrl: string) {
|
|
468
|
+
if (!this.webex.meetings.preferredWebexSite) {
|
|
469
|
+
throw Error('No preferred webex site found');
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const body = {
|
|
473
|
+
spaceUrl: conversationUrl,
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const uri = this.webex.meetings.preferredWebexSite
|
|
477
|
+
? `https://${this.webex.meetings.preferredWebexSite}/wbxappapi/v2/meetings/spaceInstant/query`
|
|
478
|
+
: '';
|
|
479
|
+
|
|
480
|
+
return this.webex
|
|
481
|
+
.request({
|
|
482
|
+
method: HTTP_VERBS.POST,
|
|
483
|
+
uri,
|
|
484
|
+
body,
|
|
485
|
+
})
|
|
486
|
+
.then((requestResult) => {
|
|
487
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.FETCH_STATIC_MEETING_LINK_SUCCESS);
|
|
488
|
+
|
|
489
|
+
return requestResult;
|
|
490
|
+
})
|
|
491
|
+
.catch((err) => {
|
|
492
|
+
if (err?.statusCode === 403) {
|
|
493
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_LINK_DOES_NOT_EXIST_ERROR, {
|
|
494
|
+
reason: err.message,
|
|
495
|
+
stack: err.stack,
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
throw new MeetingInfoV2StaticLinkDoesNotExistError(err.body?.code, err.body?.message);
|
|
499
|
+
}
|
|
500
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.FETCH_STATIC_MEETING_LINK_FAILURE, {
|
|
501
|
+
reason: err.message,
|
|
502
|
+
stack: err.stack,
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
throw err;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Enables static meeting link
|
|
511
|
+
* @param {String} conversationUrl conversationUrl that's required to enable static meeting link
|
|
512
|
+
* @returns {Promise} returns a Promise
|
|
513
|
+
* @public
|
|
514
|
+
* @memberof MeetingInfo
|
|
515
|
+
*/
|
|
516
|
+
async enableStaticMeetingLink(conversationUrl: string) {
|
|
517
|
+
if (!this.webex.meetings.preferredWebexSite) {
|
|
518
|
+
throw Error('No preferred webex site found');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
return this.createAdhocSpaceMeetingOrEnableStaticMeetingLink(conversationUrl, undefined, true)
|
|
522
|
+
.then((requestResult) => {
|
|
523
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ENABLE_STATIC_METTING_LINK_SUCCESS);
|
|
524
|
+
|
|
525
|
+
return requestResult;
|
|
526
|
+
})
|
|
527
|
+
.catch((err) => {
|
|
528
|
+
if (err?.statusCode === 403) {
|
|
529
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_IS_IN_PROGRESS_ERROR, {
|
|
530
|
+
reason: err.message,
|
|
531
|
+
stack: err.stack,
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
throw new MeetingInfoV2MeetingIsInProgressError(err.body?.code, err.body?.message, true);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (err?.statusCode === 409) {
|
|
538
|
+
Metrics.sendBehavioralMetric(
|
|
539
|
+
BEHAVIORAL_METRICS.STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR,
|
|
540
|
+
{
|
|
541
|
+
reason: err.message,
|
|
542
|
+
stack: err.stack,
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
throw new MeetingInfoV2StaticMeetingLinkAlreadyExists(err.body?.code, err.body?.message);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ENABLE_STATIC_METTING_LINK_FAILURE, {
|
|
550
|
+
reason: err.message,
|
|
551
|
+
stack: err.stack,
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
throw err;
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Disables static meeting link for given conversation url
|
|
560
|
+
* @param {String} conversationUrl conversationUrl that's required to disable static meeting link if it exists
|
|
561
|
+
* @returns {Promise} returns a Promise
|
|
562
|
+
* @public
|
|
563
|
+
* @memberof MeetingInfo
|
|
564
|
+
*/
|
|
565
|
+
async disableStaticMeetingLink(conversationUrl: string) {
|
|
566
|
+
if (!this.webex.meetings.preferredWebexSite) {
|
|
567
|
+
throw Error('No preferred webex site found');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
const body = {
|
|
571
|
+
spaceUrl: conversationUrl,
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const uri = this.webex.meetings.preferredWebexSite
|
|
575
|
+
? `https://${this.webex.meetings.preferredWebexSite}/wbxappapi/v2/meetings/spaceInstant/deletePersistentMeeting`
|
|
576
|
+
: '';
|
|
577
|
+
|
|
578
|
+
return this.webex
|
|
579
|
+
.request({
|
|
580
|
+
method: HTTP_VERBS.POST,
|
|
581
|
+
uri,
|
|
582
|
+
body,
|
|
583
|
+
})
|
|
584
|
+
.then((requestResult) => {
|
|
585
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.DISABLE_STATIC_MEETING_LINK_SUCCESS);
|
|
586
|
+
|
|
587
|
+
return requestResult;
|
|
588
|
+
})
|
|
589
|
+
.catch((err) => {
|
|
590
|
+
if (err?.statusCode === 403) {
|
|
591
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_IS_IN_PROGRESS_ERROR, {
|
|
592
|
+
reason: err.message,
|
|
593
|
+
stack: err.stack,
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
throw new MeetingInfoV2MeetingIsInProgressError(err.body?.code, err.body?.message);
|
|
597
|
+
}
|
|
598
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.DISABLE_STATIC_MEETING_LINK_FAILURE, {
|
|
599
|
+
reason: err.message,
|
|
600
|
+
stack: err.stack,
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
throw err;
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
|
|
366
607
|
/**
|
|
367
608
|
* Fetches meeting info from the server
|
|
368
609
|
* @param {String} destination one of many different types of destinations to look up info for
|
package/src/meetings/index.ts
CHANGED
|
@@ -854,7 +854,7 @@ export default class Meetings extends WebexPlugin {
|
|
|
854
854
|
this.executeRegistrationStep(
|
|
855
855
|
() =>
|
|
856
856
|
this.startReachability('registration').catch((error) => {
|
|
857
|
-
LoggerProxy.logger.
|
|
857
|
+
LoggerProxy.logger.warn(`Meetings:index#register --> startReachability failed:`, error);
|
|
858
858
|
}),
|
|
859
859
|
'startReachability'
|
|
860
860
|
),
|
|
@@ -1217,6 +1217,29 @@ export default class Meetings extends WebexPlugin {
|
|
|
1217
1217
|
);
|
|
1218
1218
|
}
|
|
1219
1219
|
|
|
1220
|
+
/**
|
|
1221
|
+
* Fetch static meeting link for given conversation url.
|
|
1222
|
+
*
|
|
1223
|
+
* @param {string} conversationUrl - url for conversation
|
|
1224
|
+
* @returns {Promise}
|
|
1225
|
+
* @public
|
|
1226
|
+
* @memberof Meetings
|
|
1227
|
+
*/
|
|
1228
|
+
public fetchStaticMeetingLink(conversationUrl: string): Promise<any> {
|
|
1229
|
+
return (
|
|
1230
|
+
this.meetingInfo
|
|
1231
|
+
.fetchStaticMeetingLink(conversationUrl)
|
|
1232
|
+
// Catch a failure to fetch static meeting link.
|
|
1233
|
+
.catch((error) => {
|
|
1234
|
+
LoggerProxy.logger.error(
|
|
1235
|
+
`Meetings:index#fetchStaticMeetingLink --> ERROR, unable to fetch persistent meeting link: ${error.message}`
|
|
1236
|
+
);
|
|
1237
|
+
|
|
1238
|
+
return Promise.reject(error);
|
|
1239
|
+
})
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1220
1243
|
/**
|
|
1221
1244
|
* Create a meeting or return an existing meeting.
|
|
1222
1245
|
*
|
|
@@ -1369,6 +1392,54 @@ export default class Meetings extends WebexPlugin {
|
|
|
1369
1392
|
);
|
|
1370
1393
|
}
|
|
1371
1394
|
|
|
1395
|
+
/**
|
|
1396
|
+
* Enable static meeting links for given conversation url.
|
|
1397
|
+
*
|
|
1398
|
+
*
|
|
1399
|
+
* @param {string} conversationUrl - url for conversation
|
|
1400
|
+
* @returns {Promise}
|
|
1401
|
+
* @public
|
|
1402
|
+
* @memberof Meetings
|
|
1403
|
+
*/
|
|
1404
|
+
public enableStaticMeetingLink(conversationUrl: string): Promise<any> {
|
|
1405
|
+
return (
|
|
1406
|
+
this.meetingInfo
|
|
1407
|
+
.enableStaticMeetingLink(conversationUrl)
|
|
1408
|
+
// Catch a failure to enable static meeting link.
|
|
1409
|
+
.catch((error) => {
|
|
1410
|
+
LoggerProxy.logger.error(
|
|
1411
|
+
`Meetings:index#enableStaticMeetingLink --> ERROR, unable to enable static meeting link: ${error.message}`
|
|
1412
|
+
);
|
|
1413
|
+
|
|
1414
|
+
return Promise.reject(error);
|
|
1415
|
+
})
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* Disable static meeting links for given conversation url.
|
|
1421
|
+
*
|
|
1422
|
+
*
|
|
1423
|
+
* @param {string} conversationUrl - url for conversation
|
|
1424
|
+
* @returns {Promise}
|
|
1425
|
+
* @public
|
|
1426
|
+
* @memberof Meetings
|
|
1427
|
+
*/
|
|
1428
|
+
public disableStaticMeetingLink(conversationUrl: string): Promise<any> {
|
|
1429
|
+
return (
|
|
1430
|
+
this.meetingInfo
|
|
1431
|
+
.disableStaticMeetingLink(conversationUrl)
|
|
1432
|
+
// Catch a failure to disable static meeting link.
|
|
1433
|
+
.catch((error) => {
|
|
1434
|
+
LoggerProxy.logger.error(
|
|
1435
|
+
`Meetings:index#disableStaticMeetingLink --> ERROR, unable to disable static meeting link: ${error.message}`
|
|
1436
|
+
);
|
|
1437
|
+
|
|
1438
|
+
return Promise.reject(error);
|
|
1439
|
+
})
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1372
1443
|
/**
|
|
1373
1444
|
* Create meeting
|
|
1374
1445
|
*
|
package/src/member/index.ts
CHANGED
|
@@ -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
|
package/src/member/util.ts
CHANGED
|
@@ -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
|
package/src/metrics/constants.ts
CHANGED
|
@@ -48,10 +48,19 @@ const BEHAVIORAL_METRICS = {
|
|
|
48
48
|
UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',
|
|
49
49
|
UPLOAD_LOGS_SUCCESS: 'js_sdk_upload_logs_success',
|
|
50
50
|
RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',
|
|
51
|
+
MEETING_IS_IN_PROGRESS_ERROR: 'js_sdk_meeting_is_in_progress_error',
|
|
52
|
+
STATIC_MEETING_LINK_ALREADY_EXISTS_ERROR: 'js_sdk_static_meeting_link_already_exists_error',
|
|
51
53
|
FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',
|
|
52
54
|
FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',
|
|
55
|
+
ENABLE_STATIC_METTING_LINK_SUCCESS: 'js_sdk_enable_static_meeting_link_success',
|
|
56
|
+
ENABLE_STATIC_METTING_LINK_FAILURE: 'js_sdk_enable_static_meeting_link_failure',
|
|
57
|
+
DISABLE_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_disable_static_meeting_link_success',
|
|
58
|
+
DISABLE_STATIC_MEETING_LINK_FAILURE: 'js_sdk_disable_static_meeting_link_failure',
|
|
53
59
|
ADHOC_MEETING_SUCCESS: 'js_sdk_adhoc_meeting_success',
|
|
54
60
|
ADHOC_MEETING_FAILURE: 'js_sdk_adhoc_meeting_failure',
|
|
61
|
+
FETCH_STATIC_MEETING_LINK_SUCCESS: 'js_sdk_fetch_static_meeting_link_success',
|
|
62
|
+
FETCH_STATIC_MEETING_LINK_FAILURE: 'js_sdk_fetch_static_meeting_link_failure',
|
|
63
|
+
MEETING_LINK_DOES_NOT_EXIST_ERROR: 'js_sdk_meeting_link_does_not_exist_error',
|
|
55
64
|
VERIFY_PASSWORD_SUCCESS: 'js_sdk_verify_password_success',
|
|
56
65
|
VERIFY_PASSWORD_ERROR: 'js_sdk_verify_password_error',
|
|
57
66
|
VERIFY_CAPTCHA_ERROR: 'js_sdk_verify_captcha_error',
|