@webex/plugin-meetings 3.0.0-beta.112 → 3.0.0-beta.114
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/README.md +45 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/meeting/request.js +12 -8
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +3 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +40 -19
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -0
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/types/meeting/request.d.ts +4 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +9 -2
- package/package.json +19 -19
- package/src/meeting/request.ts +15 -5
- package/src/meeting/util.ts +2 -0
- package/src/meeting-info/meeting-info-v2.ts +47 -17
- package/src/meeting-info/utilv2.ts +1 -0
- package/test/unit/spec/meeting/request.js +19 -0
- package/test/unit/spec/meeting/utils.js +20 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +112 -4
|
@@ -156,14 +156,38 @@ export default class MeetingInfoV2 {
|
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Raises a MeetingInfoV2PolicyError for policy error codes
|
|
161
|
+
* @param {any} err the error from the request
|
|
162
|
+
* @returns {void}
|
|
163
|
+
*/
|
|
164
|
+
handlePolicyError = (err) => {
|
|
165
|
+
if (!err.body) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (POLICY_ERROR_CODES.includes(err.body?.code)) {
|
|
170
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_INFO_POLICY_ERROR, {
|
|
171
|
+
code: err.body?.code,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
throw new MeetingInfoV2PolicyError(
|
|
175
|
+
err.body?.code,
|
|
176
|
+
err.body?.data?.meetingInfo,
|
|
177
|
+
err.body?.message
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
159
182
|
/**
|
|
160
183
|
* Creates adhoc space meetings for a space by fetching the conversation infomation
|
|
161
184
|
* @param {String} conversationUrl conversationUrl to start adhoc meeting on
|
|
185
|
+
* @param {String} installedOrgID org ID of user's machine
|
|
162
186
|
* @returns {Promise} returns a meeting info object
|
|
163
187
|
* @public
|
|
164
188
|
* @memberof MeetingInfo
|
|
165
189
|
*/
|
|
166
|
-
async createAdhocSpaceMeeting(conversationUrl: string) {
|
|
190
|
+
async createAdhocSpaceMeeting(conversationUrl: string, installedOrgID?: string) {
|
|
167
191
|
if (!this.webex.meetings.preferredWebexSite) {
|
|
168
192
|
throw Error('No preferred webex site found');
|
|
169
193
|
}
|
|
@@ -185,7 +209,14 @@ export default class MeetingInfoV2 {
|
|
|
185
209
|
return this.webex.internal.conversation
|
|
186
210
|
.get({url: conversationUrl}, {includeParticipants: true, disableTransform: true})
|
|
187
211
|
.then((conversation) => {
|
|
188
|
-
const body
|
|
212
|
+
const body: {
|
|
213
|
+
title: string;
|
|
214
|
+
spaceUrl: string;
|
|
215
|
+
keyUrl: string;
|
|
216
|
+
kroUrl: string;
|
|
217
|
+
invitees: any[];
|
|
218
|
+
installedOrgID?: string;
|
|
219
|
+
} = {
|
|
189
220
|
title: conversation.displayName,
|
|
190
221
|
spaceUrl: conversation.url,
|
|
191
222
|
keyUrl: conversation.encryptionKeyUrl,
|
|
@@ -193,19 +224,28 @@ export default class MeetingInfoV2 {
|
|
|
193
224
|
invitees: getInvitees(conversation.participants?.items),
|
|
194
225
|
};
|
|
195
226
|
|
|
227
|
+
if (installedOrgID) {
|
|
228
|
+
body.installedOrgID = installedOrgID;
|
|
229
|
+
}
|
|
230
|
+
|
|
196
231
|
const uri = this.webex.meetings.preferredWebexSite
|
|
197
232
|
? `https://${this.webex.meetings.preferredWebexSite}/wbxappapi/v2/meetings/spaceInstant`
|
|
198
233
|
: '';
|
|
199
234
|
|
|
200
|
-
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
201
|
-
|
|
202
235
|
return this.webex.request({
|
|
203
236
|
method: HTTP_VERBS.POST,
|
|
204
237
|
uri,
|
|
205
238
|
body,
|
|
206
239
|
});
|
|
207
240
|
})
|
|
241
|
+
.then((requestResult) => {
|
|
242
|
+
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
243
|
+
|
|
244
|
+
return requestResult;
|
|
245
|
+
})
|
|
208
246
|
.catch((err) => {
|
|
247
|
+
this.handlePolicyError(err);
|
|
248
|
+
|
|
209
249
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ADHOC_MEETING_FAILURE, {
|
|
210
250
|
reason: err.message,
|
|
211
251
|
stack: err.stack,
|
|
@@ -222,7 +262,7 @@ export default class MeetingInfoV2 {
|
|
|
222
262
|
* @param {Object} captchaInfo
|
|
223
263
|
* @param {String} captchaInfo.code
|
|
224
264
|
* @param {String} captchaInfo.id
|
|
225
|
-
* @param {String} installedOrgID
|
|
265
|
+
* @param {String} installedOrgID org ID of user's machine
|
|
226
266
|
* @param {String} locusId
|
|
227
267
|
* @param {Object} extraParams
|
|
228
268
|
* @param {Object} options
|
|
@@ -256,7 +296,7 @@ export default class MeetingInfoV2 {
|
|
|
256
296
|
this.webex.config.meetings.experimental.enableAdhocMeetings &&
|
|
257
297
|
this.webex.meetings.preferredWebexSite
|
|
258
298
|
) {
|
|
259
|
-
return this.createAdhocSpaceMeeting(destinationType.destination);
|
|
299
|
+
return this.createAdhocSpaceMeeting(destinationType.destination, installedOrgID);
|
|
260
300
|
}
|
|
261
301
|
|
|
262
302
|
const body = await MeetingInfoUtil.getRequestBody({
|
|
@@ -318,17 +358,7 @@ export default class MeetingInfoV2 {
|
|
|
318
358
|
}
|
|
319
359
|
|
|
320
360
|
if (err?.statusCode === 403) {
|
|
321
|
-
|
|
322
|
-
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.MEETING_INFO_POLICY_ERROR, {
|
|
323
|
-
code: err.body?.code,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
throw new MeetingInfoV2PolicyError(
|
|
327
|
-
err.body?.code,
|
|
328
|
-
err.body?.data?.meetingInfo,
|
|
329
|
-
err.body?.message
|
|
330
|
-
);
|
|
331
|
-
}
|
|
361
|
+
this.handlePolicyError(err);
|
|
332
362
|
|
|
333
363
|
Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR, {
|
|
334
364
|
reason: err.message,
|
|
@@ -221,6 +221,7 @@ MeetingInfoUtil.getDestinationType = async (from) => {
|
|
|
221
221
|
* Helper function to build up a correct locus url depending on the value passed
|
|
222
222
|
* @param {Object} options type and value to fetch meeting info
|
|
223
223
|
* @param {String} options.type One of [SIP_URI, PERSONAL_ROOM, MEETING_ID, CONVERSATION_URL, LOCUS_ID, MEETING_LINK]
|
|
224
|
+
* @param {String} options.installedOrgID org ID of user's machine
|
|
224
225
|
* @param {Object} options.destination ?? value.value
|
|
225
226
|
* @returns {Object} returns an object with {resource, method}
|
|
226
227
|
*/
|
|
@@ -226,6 +226,25 @@ describe('plugin-meetings', () => {
|
|
|
226
226
|
|
|
227
227
|
});
|
|
228
228
|
|
|
229
|
+
it('adds deviceCapabilities and locale to request when they are provided', async () => {
|
|
230
|
+
await meetingsRequest.joinMeeting({
|
|
231
|
+
locale: 'en_UK',
|
|
232
|
+
deviceCapabilities: ['SERVER_AUDIO_ANNOUNCEMENT_SUPPORTED']
|
|
233
|
+
});
|
|
234
|
+
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
235
|
+
|
|
236
|
+
assert.deepEqual(requestParams.body.deviceCapabilities, ['SERVER_AUDIO_ANNOUNCEMENT_SUPPORTED']);
|
|
237
|
+
assert.deepEqual(requestParams.body.locale, 'en_UK');
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('does not add deviceCapabilities and locale to request when they are not provided', async () => {
|
|
241
|
+
await meetingsRequest.joinMeeting({});
|
|
242
|
+
const requestParams = meetingsRequest.request.getCall(0).args[0];
|
|
243
|
+
|
|
244
|
+
assert.deepEqual(requestParams.body.deviceCapabilities, undefined);
|
|
245
|
+
assert.deepEqual(requestParams.body.locale, undefined);
|
|
246
|
+
});
|
|
247
|
+
|
|
229
248
|
it('includes joinCookie correctly', async () => {
|
|
230
249
|
const locusUrl = 'locusURL';
|
|
231
250
|
const deviceUrl = 'deviceUrl';
|
|
@@ -193,6 +193,26 @@ describe('plugin-meetings', () => {
|
|
|
193
193
|
assert.equal(parameter.breakoutsSupported, true);
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
+
it('#Should call meetingRequest.joinMeeting with locale=en_UK, deviceCapabilities=["TEST"] when they are passed in as those values', async () => {
|
|
197
|
+
const meeting = {
|
|
198
|
+
meetingRequest: {
|
|
199
|
+
joinMeeting: sinon.stub().returns(Promise.resolve({body: {}, headers: {}})),
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
MeetingUtil.parseLocusJoin = sinon.stub();
|
|
204
|
+
await MeetingUtil.joinMeeting(meeting, {
|
|
205
|
+
locale: 'en_UK',
|
|
206
|
+
deviceCapabilities: ['TEST'],
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
assert.calledOnce(meeting.meetingRequest.joinMeeting);
|
|
210
|
+
const parameter = meeting.meetingRequest.joinMeeting.getCall(0).args[0];
|
|
211
|
+
|
|
212
|
+
assert.equal(parameter.locale, 'en_UK');
|
|
213
|
+
assert.deepEqual(parameter.deviceCapabilities, ['TEST']);
|
|
214
|
+
});
|
|
215
|
+
|
|
196
216
|
it('#Should call meetingRequest.joinMeeting with preferTranscoding=false when multistream is enabled', async () => {
|
|
197
217
|
const meeting = {
|
|
198
218
|
isMultistream: true,
|
|
@@ -304,6 +304,29 @@ describe('plugin-meetings', () => {
|
|
|
304
304
|
meetingInfo.createAdhocSpaceMeeting.restore();
|
|
305
305
|
});
|
|
306
306
|
|
|
307
|
+
it('create adhoc meeting when conversationUrl and installedOrgID passed with enableAdhocMeetings toggle', async () => {
|
|
308
|
+
sinon.stub(meetingInfo, 'createAdhocSpaceMeeting').returns(Promise.resolve());
|
|
309
|
+
|
|
310
|
+
const installedOrgID = '12345'
|
|
311
|
+
|
|
312
|
+
await meetingInfo.fetchMeetingInfo(
|
|
313
|
+
'conversationUrl',
|
|
314
|
+
_CONVERSATION_URL_,
|
|
315
|
+
null,
|
|
316
|
+
null,
|
|
317
|
+
installedOrgID
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
assert.calledOnceWithExactly(
|
|
321
|
+
meetingInfo.createAdhocSpaceMeeting,
|
|
322
|
+
'conversationUrl',
|
|
323
|
+
installedOrgID
|
|
324
|
+
);
|
|
325
|
+
assert.notCalled(webex.request);
|
|
326
|
+
meetingInfo.createAdhocSpaceMeeting.restore();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
|
|
307
330
|
it('should not call createAdhocSpaceMeeting if enableAdhocMeetings toggle is off', async () => {
|
|
308
331
|
webex.config.meetings.experimental.enableAdhocMeetings = false;
|
|
309
332
|
sinon.stub(meetingInfo, 'createAdhocSpaceMeeting').returns(Promise.resolve());
|
|
@@ -329,7 +352,7 @@ describe('plugin-meetings', () => {
|
|
|
329
352
|
it('should throw an error MeetingInfoV2AdhocMeetingError if not able to start adhoc meeting for a conversation', async () => {
|
|
330
353
|
webex.config.meetings.experimental.enableAdhocMeetings = true;
|
|
331
354
|
|
|
332
|
-
webex.request = sinon.stub().rejects({statusCode: 403, body: {code: 400000}});
|
|
355
|
+
webex.request = sinon.stub().rejects({stack: 'a stack', message: 'a message', statusCode: 403, body: {code: 400000}});
|
|
333
356
|
try {
|
|
334
357
|
await meetingInfo.createAdhocSpaceMeeting('conversationUrl');
|
|
335
358
|
} catch (err) {
|
|
@@ -339,6 +362,12 @@ describe('plugin-meetings', () => {
|
|
|
339
362
|
'Failed starting the adhoc meeting, Please contact support team , code=400000'
|
|
340
363
|
);
|
|
341
364
|
assert.equal(err.wbxAppApiCode, 400000);
|
|
365
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
366
|
+
assert.calledWith(
|
|
367
|
+
Metrics.sendBehavioralMetric,
|
|
368
|
+
BEHAVIORAL_METRICS.ADHOC_MEETING_FAILURE,
|
|
369
|
+
{reason: 'a message', stack: 'a stack'}
|
|
370
|
+
);
|
|
342
371
|
}
|
|
343
372
|
});
|
|
344
373
|
|
|
@@ -563,8 +592,10 @@ describe('plugin-meetings', () => {
|
|
|
563
592
|
});
|
|
564
593
|
|
|
565
594
|
describe('createAdhocSpaceMeeting', () => {
|
|
566
|
-
|
|
567
|
-
|
|
595
|
+
const conversationUrl = 'https://conversationUrl/xxx';
|
|
596
|
+
const installedOrgID = '12345';
|
|
597
|
+
|
|
598
|
+
const setup = () => {
|
|
568
599
|
const invitee = [];
|
|
569
600
|
|
|
570
601
|
invitee.push({
|
|
@@ -577,7 +608,13 @@ describe('plugin-meetings', () => {
|
|
|
577
608
|
ciUserUuid: conversation.participants.items[1].entryUUID,
|
|
578
609
|
});
|
|
579
610
|
|
|
580
|
-
|
|
611
|
+
return {invitee}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
it('Make a request to /spaceInstant when conversationUrl', async () => {
|
|
615
|
+
const {invitee} = setup();
|
|
616
|
+
|
|
617
|
+
const result = await meetingInfo.createAdhocSpaceMeeting(conversationUrl);
|
|
581
618
|
|
|
582
619
|
assert.calledWith(
|
|
583
620
|
webex.internal.conversation.get,
|
|
@@ -598,7 +635,78 @@ describe('plugin-meetings', () => {
|
|
|
598
635
|
});
|
|
599
636
|
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
600
637
|
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
638
|
+
assert.deepEqual(result, {
|
|
639
|
+
body: {},
|
|
640
|
+
statusCode: 200
|
|
641
|
+
});
|
|
601
642
|
});
|
|
643
|
+
|
|
644
|
+
it('Make a request to /spaceInstant when conversationUrl with installed org ID', async () => {
|
|
645
|
+
const {invitee} = setup();
|
|
646
|
+
|
|
647
|
+
await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
|
|
648
|
+
|
|
649
|
+
assert.calledWith(
|
|
650
|
+
webex.internal.conversation.get,
|
|
651
|
+
{url: conversationUrl},
|
|
652
|
+
{includeParticipants: true, disableTransform: true}
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
assert.calledWith(webex.request, {
|
|
656
|
+
method: 'POST',
|
|
657
|
+
uri: 'https://go.webex.com/wbxappapi/v2/meetings/spaceInstant',
|
|
658
|
+
body: {
|
|
659
|
+
title: conversation.displayName,
|
|
660
|
+
spaceUrl: conversation.url,
|
|
661
|
+
keyUrl: conversation.encryptionKeyUrl,
|
|
662
|
+
kroUrl: conversation.kmsResourceObjectUrl,
|
|
663
|
+
invitees: invitee,
|
|
664
|
+
installedOrgID,
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
668
|
+
assert.calledWith(Metrics.sendBehavioralMetric, BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
|
|
672
|
+
forEach(
|
|
673
|
+
[
|
|
674
|
+
{errorCode: 403049},
|
|
675
|
+
{errorCode: 403104},
|
|
676
|
+
{errorCode: 403103},
|
|
677
|
+
{errorCode: 403048},
|
|
678
|
+
{errorCode: 403102},
|
|
679
|
+
{errorCode: 403101},
|
|
680
|
+
],
|
|
681
|
+
({errorCode}) => {
|
|
682
|
+
it(`should throw a MeetingInfoV2PolicyError for error code ${errorCode}`, async () => {
|
|
683
|
+
const message = 'a message';
|
|
684
|
+
const meetingInfoData = 'meeting info';
|
|
685
|
+
|
|
686
|
+
webex.request = sinon.stub().rejects({
|
|
687
|
+
statusCode: 403,
|
|
688
|
+
body: {message, code: errorCode, data: {meetingInfo: meetingInfoData}},
|
|
689
|
+
});
|
|
690
|
+
try {
|
|
691
|
+
await meetingInfo.createAdhocSpaceMeeting(conversationUrl, installedOrgID);
|
|
692
|
+
assert.fail('createAdhocSpaceMeeting should have thrown, but has not done that');
|
|
693
|
+
} catch (err) {
|
|
694
|
+
assert.instanceOf(err, MeetingInfoV2PolicyError);
|
|
695
|
+
assert.deepEqual(err.message, `${message}, code=${errorCode}`);
|
|
696
|
+
assert.equal(err.wbxAppApiCode, errorCode);
|
|
697
|
+
assert.deepEqual(err.meetingInfo, meetingInfoData);
|
|
698
|
+
|
|
699
|
+
assert(Metrics.sendBehavioralMetric.calledOnce);
|
|
700
|
+
assert.calledWith(
|
|
701
|
+
Metrics.sendBehavioralMetric,
|
|
702
|
+
BEHAVIORAL_METRICS.MEETING_INFO_POLICY_ERROR,
|
|
703
|
+
{code: errorCode}
|
|
704
|
+
);
|
|
705
|
+
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
);
|
|
602
710
|
});
|
|
603
711
|
});
|
|
604
712
|
});
|