@webex/plugin-meetings 3.0.0-beta.174 → 3.0.0-beta.175
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/constants.js +11 -2
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +143 -5
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +10 -1
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/constants.d.ts +9 -0
- package/package.json +19 -19
- package/src/constants.ts +9 -0
- package/src/interpretation/README.md +11 -2
- package/src/interpretation/index.ts +140 -4
- package/src/meeting/index.ts +19 -0
- package/test/unit/spec/interpretation/index.ts +250 -9
- package/test/unit/spec/interpretation/siLanguage.ts +2 -0
- package/test/unit/spec/meeting/index.js +43 -2
|
@@ -218,6 +218,7 @@ export declare const EVENT_TRIGGERS: {
|
|
|
218
218
|
MEETING_BREAKOUTS_PRE_ASSIGNMENTS_UPDATE: string;
|
|
219
219
|
MEETING_INTERPRETATION_UPDATE: string;
|
|
220
220
|
MEETING_INTERPRETATION_SUPPORT_LANGUAGES_UPDATE: string;
|
|
221
|
+
MEETING_INTERPRETATION_HANDOFF_REQUESTS_ARRIVED: string;
|
|
221
222
|
MEMBERS_UPDATE: string;
|
|
222
223
|
MEMBERS_CLEAR: string;
|
|
223
224
|
MEMBERS_CONTENT_UPDATE: string;
|
|
@@ -463,7 +464,15 @@ export declare const BREAKOUTS: {
|
|
|
463
464
|
export declare const INTERPRETATION: {
|
|
464
465
|
EVENTS: {
|
|
465
466
|
SUPPORT_LANGUAGES_UPDATE: string;
|
|
467
|
+
HANDOFF_REQUESTS_ARRIVED: string;
|
|
466
468
|
};
|
|
469
|
+
ACTION_TYPE: {
|
|
470
|
+
OFFERED: string;
|
|
471
|
+
ACCEPTED: string;
|
|
472
|
+
REQUESTED: string;
|
|
473
|
+
DECLINED: string;
|
|
474
|
+
};
|
|
475
|
+
RESOURCE_TYPE: string;
|
|
467
476
|
};
|
|
468
477
|
export declare const LOCUSINFO: {
|
|
469
478
|
EVENTS: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webex/plugin-meetings",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.175",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Cisco EULA (https://www.cisco.com/c/en/us/products/end-user-license-agreement.html)",
|
|
6
6
|
"contributors": [
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"build": "yarn run -T tsc --declaration true --declarationDir ./dist/types"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@webex/plugin-meetings": "3.0.0-beta.
|
|
36
|
-
"@webex/test-helper-chai": "3.0.0-beta.
|
|
37
|
-
"@webex/test-helper-mocha": "3.0.0-beta.
|
|
38
|
-
"@webex/test-helper-mock-webex": "3.0.0-beta.
|
|
39
|
-
"@webex/test-helper-retry": "3.0.0-beta.
|
|
40
|
-
"@webex/test-helper-test-users": "3.0.0-beta.
|
|
35
|
+
"@webex/plugin-meetings": "3.0.0-beta.175",
|
|
36
|
+
"@webex/test-helper-chai": "3.0.0-beta.175",
|
|
37
|
+
"@webex/test-helper-mocha": "3.0.0-beta.175",
|
|
38
|
+
"@webex/test-helper-mock-webex": "3.0.0-beta.175",
|
|
39
|
+
"@webex/test-helper-retry": "3.0.0-beta.175",
|
|
40
|
+
"@webex/test-helper-test-users": "3.0.0-beta.175",
|
|
41
41
|
"chai": "^4.3.4",
|
|
42
42
|
"chai-as-promised": "^7.1.1",
|
|
43
43
|
"jsdom-global": "3.0.2",
|
|
@@ -46,19 +46,19 @@
|
|
|
46
46
|
"typescript": "^4.7.4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@webex/common": "3.0.0-beta.
|
|
49
|
+
"@webex/common": "3.0.0-beta.175",
|
|
50
50
|
"@webex/internal-media-core": "1.39.1",
|
|
51
|
-
"@webex/internal-plugin-conversation": "3.0.0-beta.
|
|
52
|
-
"@webex/internal-plugin-device": "3.0.0-beta.
|
|
53
|
-
"@webex/internal-plugin-llm": "3.0.0-beta.
|
|
54
|
-
"@webex/internal-plugin-mercury": "3.0.0-beta.
|
|
55
|
-
"@webex/internal-plugin-metrics": "3.0.0-beta.
|
|
56
|
-
"@webex/internal-plugin-support": "3.0.0-beta.
|
|
57
|
-
"@webex/internal-plugin-user": "3.0.0-beta.
|
|
58
|
-
"@webex/media-helpers": "3.0.0-beta.
|
|
59
|
-
"@webex/plugin-people": "3.0.0-beta.
|
|
60
|
-
"@webex/plugin-rooms": "3.0.0-beta.
|
|
61
|
-
"@webex/webex-core": "3.0.0-beta.
|
|
51
|
+
"@webex/internal-plugin-conversation": "3.0.0-beta.175",
|
|
52
|
+
"@webex/internal-plugin-device": "3.0.0-beta.175",
|
|
53
|
+
"@webex/internal-plugin-llm": "3.0.0-beta.175",
|
|
54
|
+
"@webex/internal-plugin-mercury": "3.0.0-beta.175",
|
|
55
|
+
"@webex/internal-plugin-metrics": "3.0.0-beta.175",
|
|
56
|
+
"@webex/internal-plugin-support": "3.0.0-beta.175",
|
|
57
|
+
"@webex/internal-plugin-user": "3.0.0-beta.175",
|
|
58
|
+
"@webex/media-helpers": "3.0.0-beta.175",
|
|
59
|
+
"@webex/plugin-people": "3.0.0-beta.175",
|
|
60
|
+
"@webex/plugin-rooms": "3.0.0-beta.175",
|
|
61
|
+
"@webex/webex-core": "3.0.0-beta.175",
|
|
62
62
|
"ampersand-collection": "^2.0.2",
|
|
63
63
|
"bowser": "^2.11.0",
|
|
64
64
|
"btoa": "^1.2.1",
|
package/src/constants.ts
CHANGED
|
@@ -319,6 +319,7 @@ export const EVENT_TRIGGERS = {
|
|
|
319
319
|
MEETING_BREAKOUTS_PRE_ASSIGNMENTS_UPDATE: 'meeting:breakouts:preAssignmentsUpdate',
|
|
320
320
|
MEETING_INTERPRETATION_UPDATE: 'meeting:interpretation:update',
|
|
321
321
|
MEETING_INTERPRETATION_SUPPORT_LANGUAGES_UPDATE: 'meeting:interpretation:supportLanguagesUpdate',
|
|
322
|
+
MEETING_INTERPRETATION_HANDOFF_REQUESTS_ARRIVED: 'meeting:interpretation:handoffRequestsArrived',
|
|
322
323
|
MEMBERS_UPDATE: 'members:update',
|
|
323
324
|
MEMBERS_CLEAR: 'members:clear',
|
|
324
325
|
MEMBERS_CONTENT_UPDATE: 'members:content:update',
|
|
@@ -597,7 +598,15 @@ export const BREAKOUTS = {
|
|
|
597
598
|
export const INTERPRETATION = {
|
|
598
599
|
EVENTS: {
|
|
599
600
|
SUPPORT_LANGUAGES_UPDATE: 'SUPPORT_LANGUAGES_UPDATE',
|
|
601
|
+
HANDOFF_REQUESTS_ARRIVED: 'HANDOFF_REQUESTS_ARRIVED',
|
|
600
602
|
},
|
|
603
|
+
ACTION_TYPE: {
|
|
604
|
+
OFFERED: 'OFFERED',
|
|
605
|
+
ACCEPTED: 'ACCEPTED',
|
|
606
|
+
REQUESTED: 'REQUESTED',
|
|
607
|
+
DECLINED: 'DECLINED',
|
|
608
|
+
},
|
|
609
|
+
RESOURCE_TYPE: 'SiHandover',
|
|
601
610
|
};
|
|
602
611
|
|
|
603
612
|
export const LOCUSINFO = {
|
|
@@ -45,7 +45,16 @@ The following are methods available to the interpreters of a meeting.
|
|
|
45
45
|
//Change direction of interpretation for an interpreter participant
|
|
46
46
|
interpretation.changeDirection();
|
|
47
47
|
|
|
48
|
-
//Handoff between interpreters,
|
|
49
|
-
interpretation.
|
|
48
|
+
//Handoff between interpreters, input paramerter participantId is the target to handoff
|
|
49
|
+
interpretation.handoffInterpreter(participantId);
|
|
50
|
+
|
|
51
|
+
//in-active interpreter request to handoff to self
|
|
52
|
+
interpretation.requestHandoff();
|
|
53
|
+
|
|
54
|
+
//accept the request of handoff, input paramter url is from last approval event which generate by server side
|
|
55
|
+
interpretation.acceptRequest(url);
|
|
56
|
+
|
|
57
|
+
//decline the request of handoff, input paramter url is from last approval event which generate by server side
|
|
58
|
+
interpretation.declineRequest(url);
|
|
50
59
|
|
|
51
60
|
```
|
|
@@ -18,6 +18,7 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
18
18
|
|
|
19
19
|
props: {
|
|
20
20
|
locusUrl: 'string', // appears current meeting's locus url
|
|
21
|
+
approvalUrl: 'string', // appears current meeting's approval url for handoff between interpreters
|
|
21
22
|
originalLanguage: 'string', // appears current meeting's original language
|
|
22
23
|
sourceLanguage: 'string', // appears self interpreter's source language
|
|
23
24
|
targetLanguage: 'string', // appears self interpreter's target language
|
|
@@ -27,18 +28,18 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
27
28
|
selfParticipantId: 'string', // appears the self participant id
|
|
28
29
|
canManageInterpreters: 'boolean', // appears the ability to manage interpreters
|
|
29
30
|
supportLanguages: 'array', // appears the support languages
|
|
30
|
-
|
|
31
|
+
hostSIEnabled: 'boolean', // appears the meeting host feature of SI enabled
|
|
31
32
|
},
|
|
32
33
|
derived: {
|
|
33
34
|
shouldQuerySupportLanguages: {
|
|
34
35
|
cache: false,
|
|
35
|
-
deps: ['canManageInterpreters', '
|
|
36
|
+
deps: ['canManageInterpreters', 'hostSIEnabled'],
|
|
36
37
|
/**
|
|
37
38
|
* Returns should query support languages or not
|
|
38
39
|
* @returns {boolean}
|
|
39
40
|
*/
|
|
40
41
|
fn() {
|
|
41
|
-
return !!(this.canManageInterpreters && this.
|
|
42
|
+
return !!(this.canManageInterpreters && this.hostSIEnabled);
|
|
42
43
|
},
|
|
43
44
|
},
|
|
44
45
|
},
|
|
@@ -52,6 +53,7 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
52
53
|
this.querySupportLanguages();
|
|
53
54
|
}
|
|
54
55
|
});
|
|
56
|
+
this.listenToHandoffRequests();
|
|
55
57
|
},
|
|
56
58
|
|
|
57
59
|
/**
|
|
@@ -69,6 +71,14 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
69
71
|
locusUrlUpdate(locusUrl) {
|
|
70
72
|
this.set('locusUrl', locusUrl);
|
|
71
73
|
},
|
|
74
|
+
/**
|
|
75
|
+
* Update the approval url for handoff
|
|
76
|
+
* @param {string} approvalUrl // approval url
|
|
77
|
+
* @returns {void}
|
|
78
|
+
*/
|
|
79
|
+
approvalUrlUpdate(approvalUrl) {
|
|
80
|
+
this.set('approvalUrl', approvalUrl);
|
|
81
|
+
},
|
|
72
82
|
/**
|
|
73
83
|
* Update whether self has capability to manage interpreters (only host can manage it)
|
|
74
84
|
* @param {boolean} canManageInterpreters
|
|
@@ -77,13 +87,20 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
77
87
|
updateCanManageInterpreters(canManageInterpreters) {
|
|
78
88
|
this.set('canManageInterpreters', canManageInterpreters);
|
|
79
89
|
},
|
|
90
|
+
/**
|
|
91
|
+
* Update whether the meeting's host si is enabled or not
|
|
92
|
+
* @param {boolean} hostSIEnabled
|
|
93
|
+
* @returns {void}
|
|
94
|
+
*/
|
|
95
|
+
updateHostSIEnabled(hostSIEnabled) {
|
|
96
|
+
this.set('hostSIEnabled', hostSIEnabled);
|
|
97
|
+
},
|
|
80
98
|
/**
|
|
81
99
|
* Update the interpretation languages channels which user can choose to subscribe
|
|
82
100
|
* @param {Object} interpretation
|
|
83
101
|
* @returns {void}
|
|
84
102
|
*/
|
|
85
103
|
updateInterpretation(interpretation) {
|
|
86
|
-
this.set('siEnabled', !!interpretation);
|
|
87
104
|
this.siLanguages.set(interpretation?.siLanguages || []);
|
|
88
105
|
},
|
|
89
106
|
/**
|
|
@@ -177,6 +194,125 @@ const SimultaneousInterpretation = WebexPlugin.extend({
|
|
|
177
194
|
throw error;
|
|
178
195
|
});
|
|
179
196
|
},
|
|
197
|
+
/**
|
|
198
|
+
* Sets up a listener for handoff requests from mercury
|
|
199
|
+
* @returns {void}
|
|
200
|
+
*/
|
|
201
|
+
listenToHandoffRequests() {
|
|
202
|
+
this.listenTo(this.webex.internal.mercury, 'event:locus.approval_request', (event) => {
|
|
203
|
+
if (event?.data?.approval?.resourceType === INTERPRETATION.RESOURCE_TYPE) {
|
|
204
|
+
const {receivers, initiator, actionType, url} = event.data.approval;
|
|
205
|
+
const receiverId = receivers?.[0]?.participantId;
|
|
206
|
+
const isReceiver = !!receiverId && receiverId === this.selfParticipantId;
|
|
207
|
+
const senderId = initiator?.participantId;
|
|
208
|
+
const isSender = !!senderId && senderId === this.selfParticipantId;
|
|
209
|
+
if (!isReceiver && !isSender) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.trigger(INTERPRETATION.EVENTS.HANDOFF_REQUESTS_ARRIVED, {
|
|
213
|
+
actionType,
|
|
214
|
+
isReceiver,
|
|
215
|
+
isSender,
|
|
216
|
+
senderId,
|
|
217
|
+
receiverId,
|
|
218
|
+
url,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
/**
|
|
224
|
+
* handoff the active interpreter role to another interpreter in same group, only the interpreter is allowed to call this api
|
|
225
|
+
* @param {string} participantId the participant id you want to hand off
|
|
226
|
+
* @returns {Promise}
|
|
227
|
+
*/
|
|
228
|
+
handoffInterpreter(participantId) {
|
|
229
|
+
if (!participantId) {
|
|
230
|
+
return Promise.reject(new Error('Missing target participant id'));
|
|
231
|
+
}
|
|
232
|
+
if (!this.approvalUrl) {
|
|
233
|
+
return Promise.reject(new Error('Missing approval url'));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return this.request({
|
|
237
|
+
method: HTTP_VERBS.POST,
|
|
238
|
+
uri: this.approvalUrl,
|
|
239
|
+
body: {
|
|
240
|
+
actionType: INTERPRETATION.ACTION_TYPE.OFFERED,
|
|
241
|
+
resourceType: INTERPRETATION.RESOURCE_TYPE,
|
|
242
|
+
receivers: [
|
|
243
|
+
{
|
|
244
|
+
participantId,
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
},
|
|
248
|
+
}).catch((error) => {
|
|
249
|
+
LoggerProxy.logger.error('Meeting:interpretation#handoffInterpreter failed', error);
|
|
250
|
+
throw error;
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
/**
|
|
254
|
+
* the in-active interpreter request to hand off the active role to self
|
|
255
|
+
* @returns {Promise}
|
|
256
|
+
*/
|
|
257
|
+
requestHandoff() {
|
|
258
|
+
if (!this.approvalUrl) {
|
|
259
|
+
return Promise.reject(new Error('Missing approval url'));
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return this.request({
|
|
263
|
+
method: HTTP_VERBS.POST,
|
|
264
|
+
uri: this.approvalUrl,
|
|
265
|
+
body: {
|
|
266
|
+
actionType: INTERPRETATION.ACTION_TYPE.REQUESTED,
|
|
267
|
+
resourceType: INTERPRETATION.RESOURCE_TYPE,
|
|
268
|
+
},
|
|
269
|
+
}).catch((error) => {
|
|
270
|
+
LoggerProxy.logger.error('Meeting:interpretation#requestHandoff failed', error);
|
|
271
|
+
throw error;
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
/**
|
|
275
|
+
* accept the request of handoff
|
|
276
|
+
* @param {String} url the url get from last approval event
|
|
277
|
+
* @returns {Promise}
|
|
278
|
+
*/
|
|
279
|
+
acceptRequest(url) {
|
|
280
|
+
if (!url) {
|
|
281
|
+
return Promise.reject(new Error('Missing the url to accept'));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return this.request({
|
|
285
|
+
method: HTTP_VERBS.PUT,
|
|
286
|
+
uri: url,
|
|
287
|
+
body: {
|
|
288
|
+
actionType: INTERPRETATION.ACTION_TYPE.ACCEPTED,
|
|
289
|
+
},
|
|
290
|
+
}).catch((error) => {
|
|
291
|
+
LoggerProxy.logger.error('Meeting:interpretation#acceptRequest failed', error);
|
|
292
|
+
throw error;
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
/**
|
|
296
|
+
* decline the request of handoff
|
|
297
|
+
* @param {String} url the url get from last approval event
|
|
298
|
+
* @returns {Promise}
|
|
299
|
+
*/
|
|
300
|
+
declineRequest(url) {
|
|
301
|
+
if (!url) {
|
|
302
|
+
return Promise.reject(new Error('Missing the url to decline'));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return this.request({
|
|
306
|
+
method: HTTP_VERBS.PUT,
|
|
307
|
+
uri: url,
|
|
308
|
+
body: {
|
|
309
|
+
actionType: INTERPRETATION.ACTION_TYPE.DECLINED,
|
|
310
|
+
},
|
|
311
|
+
}).catch((error) => {
|
|
312
|
+
LoggerProxy.logger.error('Meeting:interpretation#declineRequest failed', error);
|
|
313
|
+
throw error;
|
|
314
|
+
});
|
|
315
|
+
},
|
|
180
316
|
});
|
|
181
317
|
|
|
182
318
|
export default SimultaneousInterpretation;
|
package/src/meeting/index.ts
CHANGED
|
@@ -1608,6 +1608,21 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
1608
1608
|
EVENT_TRIGGERS.MEETING_INTERPRETATION_SUPPORT_LANGUAGES_UPDATE
|
|
1609
1609
|
);
|
|
1610
1610
|
});
|
|
1611
|
+
|
|
1612
|
+
this.simultaneousInterpretation.on(
|
|
1613
|
+
INTERPRETATION.EVENTS.HANDOFF_REQUESTS_ARRIVED,
|
|
1614
|
+
(payload) => {
|
|
1615
|
+
Trigger.trigger(
|
|
1616
|
+
this,
|
|
1617
|
+
{
|
|
1618
|
+
file: 'meeting/index',
|
|
1619
|
+
function: 'setUpInterpretationListener',
|
|
1620
|
+
},
|
|
1621
|
+
EVENT_TRIGGERS.MEETING_INTERPRETATION_HANDOFF_REQUESTS_ARRIVED,
|
|
1622
|
+
payload
|
|
1623
|
+
);
|
|
1624
|
+
}
|
|
1625
|
+
);
|
|
1611
1626
|
}
|
|
1612
1627
|
|
|
1613
1628
|
/**
|
|
@@ -2374,6 +2389,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
2374
2389
|
this.recordingController.setSessionId(this.locusInfo?.fullState?.sessionId);
|
|
2375
2390
|
this.breakouts.breakoutServiceUrlUpdate(payload?.services?.breakout?.url);
|
|
2376
2391
|
this.annotation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
2392
|
+
this.simultaneousInterpretation.approvalUrlUpdate(payload?.services?.approval?.url);
|
|
2377
2393
|
});
|
|
2378
2394
|
}
|
|
2379
2395
|
|
|
@@ -3157,6 +3173,9 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
3157
3173
|
// Need to populate environment when sending CA event
|
|
3158
3174
|
this.environment = locusMeetingObject?.info.channel || webexMeetingInfo?.channel;
|
|
3159
3175
|
}
|
|
3176
|
+
this.simultaneousInterpretation.updateHostSIEnabled(
|
|
3177
|
+
!!webexMeetingInfo?.meetingSiteSetting?.enableHostInterpreterControlSI
|
|
3178
|
+
);
|
|
3160
3179
|
}
|
|
3161
3180
|
|
|
3162
3181
|
/**
|
|
@@ -12,6 +12,7 @@ describe('plugin-meetings', () => {
|
|
|
12
12
|
beforeEach(() => {
|
|
13
13
|
// @ts-ignore
|
|
14
14
|
webex = new MockWebex({});
|
|
15
|
+
webex.internal.mercury.on = sinon.stub();
|
|
15
16
|
interpretation = new SimultaneousInterpretation({}, {parent: webex});
|
|
16
17
|
interpretation.locusUrl = 'locusUrl';
|
|
17
18
|
webex.request = sinon.stub().returns(Promise.resolve('REQUEST_RETURN_VALUE'));
|
|
@@ -50,6 +51,14 @@ describe('plugin-meetings', () => {
|
|
|
50
51
|
});
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
describe('#approvalUrlUpdate', () => {
|
|
55
|
+
it('sets the approval url', () => {
|
|
56
|
+
interpretation.approvalUrlUpdate('newUrl');
|
|
57
|
+
|
|
58
|
+
assert.equal(interpretation.approvalUrl, 'newUrl');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
53
62
|
describe('#updateCanManageInterpreters', () => {
|
|
54
63
|
it('update canManageInterpreters', () => {
|
|
55
64
|
interpretation.updateCanManageInterpreters(true);
|
|
@@ -62,6 +71,18 @@ describe('plugin-meetings', () => {
|
|
|
62
71
|
});
|
|
63
72
|
});
|
|
64
73
|
|
|
74
|
+
describe('#updateHostSIEnabled', () => {
|
|
75
|
+
it('update hostSI feature is on or off', () => {
|
|
76
|
+
interpretation.updateHostSIEnabled(true);
|
|
77
|
+
|
|
78
|
+
assert.equal(interpretation.hostSIEnabled, true);
|
|
79
|
+
|
|
80
|
+
interpretation.updateHostSIEnabled(false);
|
|
81
|
+
|
|
82
|
+
assert.equal(interpretation.hostSIEnabled, false);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
65
86
|
describe('#updateInterpretation', () => {
|
|
66
87
|
const checkSILanguage = (siLanguage, expectResult) => {
|
|
67
88
|
return siLanguage?.languageCode === expectResult.languageCode && siLanguage?.languageName === expectResult.languageName
|
|
@@ -69,15 +90,6 @@ describe('plugin-meetings', () => {
|
|
|
69
90
|
it('update interpretation correctly', () => {
|
|
70
91
|
interpretation.updateInterpretation({siLanguages: [{languageName: 'en', languageCode: 1}]});
|
|
71
92
|
checkSILanguage(interpretation.siLanguages.en, {languageName: 'en', languageCode: 1});
|
|
72
|
-
assert.equal(interpretation.siEnabled, true);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('check siEnable as false if input param interpretation is null/undefined', () => {
|
|
76
|
-
interpretation.updateInterpretation(null);
|
|
77
|
-
assert.equal(interpretation.siEnabled, false);
|
|
78
|
-
|
|
79
|
-
interpretation.updateInterpretation(undefined);
|
|
80
|
-
assert.equal(interpretation.siEnabled, false);
|
|
81
93
|
});
|
|
82
94
|
});
|
|
83
95
|
|
|
@@ -325,5 +337,234 @@ describe('plugin-meetings', () => {
|
|
|
325
337
|
});
|
|
326
338
|
});
|
|
327
339
|
});
|
|
340
|
+
|
|
341
|
+
describe('#listenToHandoffRequests', () => {
|
|
342
|
+
it('triggers handoff update event when the approval is related with self', () => {
|
|
343
|
+
const call = webex.internal.mercury.on.getCall(0);
|
|
344
|
+
const callback = call.args[1];
|
|
345
|
+
|
|
346
|
+
assert.equal(call.args[0], 'event:locus.approval_request');
|
|
347
|
+
interpretation.set('selfParticipantId', 'p123');
|
|
348
|
+
|
|
349
|
+
let called = false;
|
|
350
|
+
const triggerSpy = sinon.spy(interpretation, 'trigger');
|
|
351
|
+
|
|
352
|
+
interpretation.listenTo(interpretation, 'HANDOFF_REQUESTS_ARRIVED', () => {
|
|
353
|
+
called = true;
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
callback({
|
|
357
|
+
data: {
|
|
358
|
+
approval: {
|
|
359
|
+
actionType: 'OFFERED',
|
|
360
|
+
resourceType: 'SiHandover',
|
|
361
|
+
receivers: [{
|
|
362
|
+
participantId: 'p123',
|
|
363
|
+
}],
|
|
364
|
+
initiator: {participantId: 'p123'},
|
|
365
|
+
url: 'testUrl',
|
|
366
|
+
},
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
assert.isTrue(called);
|
|
371
|
+
assert.calledWithExactly(triggerSpy, 'HANDOFF_REQUESTS_ARRIVED', {
|
|
372
|
+
actionType: 'OFFERED',
|
|
373
|
+
isReceiver: true,
|
|
374
|
+
isSender: true,
|
|
375
|
+
senderId: 'p123',
|
|
376
|
+
receiverId: 'p123',
|
|
377
|
+
url: 'testUrl',
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('not triggers handoff update event when the approval is not related with self', () => {
|
|
382
|
+
const call = webex.internal.mercury.on.getCall(0);
|
|
383
|
+
const callback = call.args[1];
|
|
384
|
+
|
|
385
|
+
interpretation.set('selfParticipantId', 'p123');
|
|
386
|
+
|
|
387
|
+
let called = false;
|
|
388
|
+
|
|
389
|
+
interpretation.listenTo(interpretation, 'HANDOFF_REQUESTS_ARRIVED', () => {
|
|
390
|
+
called = true;
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
callback({
|
|
394
|
+
data: {
|
|
395
|
+
approval: {
|
|
396
|
+
actionType: 'OFFERED',
|
|
397
|
+
resourceType: 'SiHandover',
|
|
398
|
+
receivers: [{
|
|
399
|
+
participantId: 'p444',
|
|
400
|
+
}],
|
|
401
|
+
initiator: {participantId: 'p444'},
|
|
402
|
+
url: 'testUrl',
|
|
403
|
+
},
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
assert.isFalse(called);
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
describe('#handoffInterpreter', () => {
|
|
412
|
+
it('makes the request as expected', async () => {
|
|
413
|
+
interpretation.approvalUrlUpdate('approvalUrl');
|
|
414
|
+
await interpretation.handoffInterpreter('participant2');
|
|
415
|
+
assert.calledOnceWithExactly(webex.request, {
|
|
416
|
+
method: 'POST',
|
|
417
|
+
uri: 'approvalUrl',
|
|
418
|
+
body: {
|
|
419
|
+
actionType: 'OFFERED',
|
|
420
|
+
resourceType: 'SiHandover',
|
|
421
|
+
receivers: [
|
|
422
|
+
{
|
|
423
|
+
participantId: 'participant2',
|
|
424
|
+
},
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('rejects with error', async () => {
|
|
431
|
+
const mockError = new Error('something wrong');
|
|
432
|
+
webex.request.returns(Promise.reject(mockError));
|
|
433
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
434
|
+
interpretation.approvalUrlUpdate('approvalUrl');
|
|
435
|
+
|
|
436
|
+
await assert.isRejected(interpretation.handoffInterpreter('p2'), mockError, 'something wrong');
|
|
437
|
+
|
|
438
|
+
assert.calledOnceWithExactly(
|
|
439
|
+
LoggerProxy.logger.error,
|
|
440
|
+
'Meeting:interpretation#handoffInterpreter failed',
|
|
441
|
+
mockError
|
|
442
|
+
);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('rejects error when no target participant id', async () => {
|
|
446
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
447
|
+
|
|
448
|
+
await interpretation.handoffInterpreter().catch((error) => {
|
|
449
|
+
assert.equal(error.toString(), 'Error: Missing target participant id');
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('rejects error when no approval url', async () => {
|
|
454
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
455
|
+
|
|
456
|
+
await interpretation.handoffInterpreter('p2').catch((error) => {
|
|
457
|
+
assert.equal(error.toString(), 'Error: Missing approval url');
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
describe('#requestHandoff', () => {
|
|
463
|
+
it('makes the request as expected', async () => {
|
|
464
|
+
interpretation.approvalUrlUpdate('approvalUrl');
|
|
465
|
+
await interpretation.requestHandoff();
|
|
466
|
+
assert.calledOnceWithExactly(webex.request, {
|
|
467
|
+
method: 'POST',
|
|
468
|
+
uri: 'approvalUrl',
|
|
469
|
+
body: {
|
|
470
|
+
actionType: 'REQUESTED',
|
|
471
|
+
resourceType: 'SiHandover',
|
|
472
|
+
},
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('rejects with error', async () => {
|
|
477
|
+
const mockError = new Error('something wrong');
|
|
478
|
+
webex.request.returns(Promise.reject(mockError));
|
|
479
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
480
|
+
interpretation.approvalUrlUpdate('approvalUrl');
|
|
481
|
+
|
|
482
|
+
await assert.isRejected(interpretation.requestHandoff(), mockError, 'something wrong');
|
|
483
|
+
|
|
484
|
+
assert.calledOnceWithExactly(
|
|
485
|
+
LoggerProxy.logger.error,
|
|
486
|
+
'Meeting:interpretation#requestHandoff failed',
|
|
487
|
+
mockError
|
|
488
|
+
);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it('rejects error when no approval url', async () => {
|
|
492
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
493
|
+
|
|
494
|
+
await interpretation.requestHandoff().catch((error) => {
|
|
495
|
+
assert.equal(error.toString(), 'Error: Missing approval url');
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
describe('#acceptRequest', () => {
|
|
501
|
+
it('makes the request as expected', async () => {
|
|
502
|
+
await interpretation.acceptRequest('testUrl');
|
|
503
|
+
assert.calledOnceWithExactly(webex.request, {
|
|
504
|
+
method: 'PUT',
|
|
505
|
+
uri: 'testUrl',
|
|
506
|
+
body: {
|
|
507
|
+
actionType: 'ACCEPTED',
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
it('rejects with error', async () => {
|
|
513
|
+
const mockError = new Error('something wrong');
|
|
514
|
+
webex.request.returns(Promise.reject(mockError));
|
|
515
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
516
|
+
|
|
517
|
+
await assert.isRejected(interpretation.acceptRequest('testUrl'), mockError, 'something wrong');
|
|
518
|
+
|
|
519
|
+
assert.calledOnceWithExactly(
|
|
520
|
+
LoggerProxy.logger.error,
|
|
521
|
+
'Meeting:interpretation#acceptRequest failed',
|
|
522
|
+
mockError
|
|
523
|
+
);
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('rejects error when no url passed', async () => {
|
|
527
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
528
|
+
|
|
529
|
+
await interpretation.acceptRequest().catch((error) => {
|
|
530
|
+
assert.equal(error.toString(), 'Error: Missing the url to accept');
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
describe('#declineRequest', () => {
|
|
536
|
+
it('makes the request as expected', async () => {
|
|
537
|
+
await interpretation.declineRequest('testUrl');
|
|
538
|
+
assert.calledOnceWithExactly(webex.request, {
|
|
539
|
+
method: 'PUT',
|
|
540
|
+
uri: 'testUrl',
|
|
541
|
+
body: {
|
|
542
|
+
actionType: 'DECLINED',
|
|
543
|
+
},
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it('rejects with error', async () => {
|
|
548
|
+
const mockError = new Error('something wrong');
|
|
549
|
+
webex.request.returns(Promise.reject(mockError));
|
|
550
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
551
|
+
|
|
552
|
+
await assert.isRejected(interpretation.declineRequest('testUrl'), mockError, 'something wrong');
|
|
553
|
+
|
|
554
|
+
assert.calledOnceWithExactly(
|
|
555
|
+
LoggerProxy.logger.error,
|
|
556
|
+
'Meeting:interpretation#declineRequest failed',
|
|
557
|
+
mockError
|
|
558
|
+
);
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
it('rejects error when no url passed', async () => {
|
|
562
|
+
LoggerProxy.logger.error = sinon.stub();
|
|
563
|
+
|
|
564
|
+
await interpretation.declineRequest().catch((error) => {
|
|
565
|
+
assert.equal(error.toString(), 'Error: Missing the url to decline');
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
});
|
|
328
569
|
});
|
|
329
570
|
});
|
|
@@ -2,6 +2,7 @@ import {assert} from '@webex/test-helper-chai';
|
|
|
2
2
|
import SILanguage from '@webex/plugin-meetings/src/interpretation/siLanguage';
|
|
3
3
|
import SimultaneousInterpretation from '@webex/plugin-meetings/src/interpretation';
|
|
4
4
|
import MockWebex from '@webex/test-helper-mock-webex';
|
|
5
|
+
import sinon from 'sinon';
|
|
5
6
|
|
|
6
7
|
describe('plugin-meetings', () => {
|
|
7
8
|
describe('SILanguage', () => {
|
|
@@ -11,6 +12,7 @@ describe('plugin-meetings', () => {
|
|
|
11
12
|
beforeEach(() => {
|
|
12
13
|
// @ts-ignore
|
|
13
14
|
webex = new MockWebex({});
|
|
15
|
+
webex.internal.mercury.on = sinon.stub();
|
|
14
16
|
interpretation = new SimultaneousInterpretation({}, {parent: webex});
|
|
15
17
|
siLanguage = new SILanguage({}, {parent: interpretation});
|
|
16
18
|
});
|