@wazo/sdk 0.38.5 → 0.38.8
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 +1 -1
- package/dist/wazo-sdk.js +2 -2
- package/esm/__tests__/api-client.test.js +148 -2
- package/esm/__tests__/web-rtc-client.test.js +303 -26
- package/esm/api/calld.js +14 -0
- package/esm/api/confd.js +134 -2
- package/esm/api/ctid-ng.js +6 -0
- package/esm/api-client.js +148 -2
- package/esm/checker/Checker.js +212 -26
- package/esm/checker/checks/aor.js +148 -2
- package/esm/checker/checks/api.js +148 -2
- package/esm/checker/checks/index.js +212 -26
- package/esm/checker/checks/wazo-websocket.js +2 -0
- package/esm/checker/checks/webrtc-transport.js +210 -26
- package/esm/checker/checks/webrtc.js +210 -26
- package/esm/domain/AdHocAPIConference.js +148 -2
- package/esm/domain/Call.js +6 -0
- package/esm/domain/CallSession.js +1 -1
- package/esm/domain/Features.js +148 -2
- package/esm/domain/Meeting.js +18 -0
- package/esm/domain/MeetingAuthorization.js +70 -0
- package/esm/domain/Phone/CTIPhone.js +149 -3
- package/esm/domain/Phone/WebRTCPhone.js +3 -3
- package/esm/domain/__tests__/Call.test.js +6 -0
- package/esm/domain/__tests__/CallSession.test.js +1 -1
- package/esm/domain/__tests__/IndirectTransfer.test.js +1 -1
- package/esm/domain/__tests__/Meeting.test.js +87 -1
- package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
- package/esm/domain/__tests__/Room.test.js +1 -1
- package/esm/index.js +258 -32
- package/esm/lib/WazoSessionDescriptionHandler.js +22 -1
- package/esm/service/CallApi.js +148 -2
- package/esm/service/getApiClient.js +148 -2
- package/esm/simple/Auth.js +258 -32
- package/esm/simple/Configuration.js +258 -32
- package/esm/simple/Directory.js +148 -2
- package/esm/simple/Phone.js +258 -32
- package/esm/simple/Websocket.js +3 -0
- package/esm/simple/index.js +258 -32
- package/esm/simple/room/LocalParticipant.js +258 -32
- package/esm/simple/room/Participant.js +258 -32
- package/esm/simple/room/RemoteParticipant.js +258 -32
- package/esm/simple/room/Room.js +258 -32
- package/esm/simple/room/SipRoom.js +258 -32
- package/esm/simple/room/Stream.js +258 -32
- package/esm/simple/room/__tests__/Participant.test.js +14747 -0
- package/esm/simple/room/__tests__/RemoteParticipant.test.js +258 -32
- package/esm/simple/utils.js +258 -32
- package/esm/utils/__tests__/object.test.js +57 -0
- package/esm/utils/__tests__/sdp.test.js +50 -0
- package/esm/utils/__tests__/string.test.js +30 -0
- package/esm/utils/object.js +24 -0
- package/esm/utils/sdp.js +19 -1
- package/esm/utils/string.js +10 -0
- package/esm/web-rtc-client.js +210 -26
- package/esm/websocket-client.js +3 -1
- package/lib/__tests__/api-client.test.js +148 -2
- package/lib/__tests__/web-rtc-client.test.js +303 -26
- package/lib/api/calld.js +14 -0
- package/lib/api/confd.js +134 -2
- package/lib/api/ctid-ng.js +6 -0
- package/lib/api-client.js +148 -2
- package/lib/checker/Checker.js +212 -26
- package/lib/checker/checks/aor.js +148 -2
- package/lib/checker/checks/api.js +148 -2
- package/lib/checker/checks/index.js +212 -26
- package/lib/checker/checks/wazo-websocket.js +2 -0
- package/lib/checker/checks/webrtc-transport.js +210 -26
- package/lib/checker/checks/webrtc.js +210 -26
- package/lib/domain/AdHocAPIConference.js +148 -2
- package/lib/domain/Call.js +6 -0
- package/lib/domain/CallSession.js +1 -1
- package/lib/domain/Features.js +148 -2
- package/lib/domain/Meeting.js +18 -0
- package/lib/domain/MeetingAuthorization.js +79 -0
- package/lib/domain/Phone/CTIPhone.js +149 -3
- package/lib/domain/Phone/WebRTCPhone.js +3 -3
- package/lib/domain/__tests__/Call.test.js +6 -0
- package/lib/domain/__tests__/CallSession.test.js +1 -1
- package/lib/domain/__tests__/IndirectTransfer.test.js +1 -1
- package/lib/domain/__tests__/Meeting.test.js +87 -1
- package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
- package/lib/domain/__tests__/Room.test.js +1 -1
- package/lib/index.js +258 -32
- package/lib/lib/WazoSessionDescriptionHandler.js +22 -1
- package/lib/service/CallApi.js +148 -2
- package/lib/service/getApiClient.js +148 -2
- package/lib/simple/Auth.js +258 -32
- package/lib/simple/Configuration.js +258 -32
- package/lib/simple/Directory.js +148 -2
- package/lib/simple/Phone.js +258 -32
- package/lib/simple/Websocket.js +3 -0
- package/lib/simple/index.js +258 -32
- package/lib/simple/room/LocalParticipant.js +258 -32
- package/lib/simple/room/Participant.js +258 -32
- package/lib/simple/room/RemoteParticipant.js +258 -32
- package/lib/simple/room/Room.js +258 -32
- package/lib/simple/room/SipRoom.js +258 -32
- package/lib/simple/room/Stream.js +258 -32
- package/lib/simple/room/__tests__/Participant.test.js +14757 -0
- package/lib/simple/room/__tests__/RemoteParticipant.test.js +258 -32
- package/lib/simple/utils.js +258 -32
- package/lib/utils/__tests__/object.test.js +59 -0
- package/lib/utils/__tests__/sdp.test.js +50 -0
- package/lib/utils/__tests__/string.test.js +32 -0
- package/lib/utils/object.js +28 -0
- package/lib/utils/sdp.js +19 -0
- package/lib/utils/string.js +14 -0
- package/lib/web-rtc-client.js +210 -26
- package/lib/websocket-client.js +3 -0
- package/package.json +2 -2
- package/src/__tests__/web-rtc-client.test.js +93 -0
- package/src/api/calld.js +8 -0
- package/src/api/confd.js +43 -2
- package/src/domain/Call.js +6 -0
- package/src/domain/CallSession.js +1 -1
- package/src/domain/Meeting.js +20 -0
- package/src/domain/MeetingAuthorization.js +67 -0
- package/src/domain/Phone/WebRTCPhone.js +2 -2
- package/src/domain/__tests__/Meeting.test.js +70 -1
- package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
- package/src/lib/WazoSessionDescriptionHandler.js +5 -2
- package/src/simple/room/Participant.js +40 -0
- package/src/simple/room/Room.js +2 -2
- package/src/simple/room/SipRoom.js +1 -1
- package/src/simple/room/__tests__/Participant.test.js +81 -0
- package/src/types/WebSocketMessage.js +7 -1
- package/src/utils/__tests__/object.test.js +35 -0
- package/src/utils/__tests__/sdp.test.js +33 -1
- package/src/utils/__tests__/string.test.js +23 -0
- package/src/utils/object.js +15 -0
- package/src/utils/sdp.js +18 -0
- package/src/utils/string.js +8 -0
- package/src/web-rtc-client.js +40 -23
- package/src/websocket-client.js +2 -0
package/src/api/confd.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/* @flow */
|
|
2
2
|
import ApiRequester from '../utils/api-requester';
|
|
3
3
|
import type { UUID, ListConfdUsersResponse, ListApplicationsResponse } from '../domain/types';
|
|
4
|
+
import type { MeetingCreateArguments, MeetingUpdateArguments } from '../domain/Meeting';
|
|
4
5
|
import Profile from '../domain/Profile';
|
|
5
6
|
import SipLine from '../domain/SipLine';
|
|
6
7
|
import ExternalApp from '../domain/ExternalApp';
|
|
7
8
|
import Meeting from '../domain/Meeting';
|
|
9
|
+
import MeetingAuthorization from '../domain/MeetingAuthorization';
|
|
10
|
+
import { convertKeysFromCamelToUnderscore } from '../utils/object';
|
|
8
11
|
|
|
9
12
|
export default (client: ApiRequester, baseUrl: string) => ({
|
|
10
13
|
listUsers: (): Promise<ListConfdUsersResponse> => client.get(`${baseUrl}/users`, null),
|
|
@@ -72,8 +75,18 @@ export default (client: ApiRequester, baseUrl: string) => ({
|
|
|
72
75
|
getMyMeetings: (): Promise<Meeting> =>
|
|
73
76
|
client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
|
|
74
77
|
|
|
75
|
-
createMyMeeting: (
|
|
76
|
-
client
|
|
78
|
+
createMyMeeting: (args: MeetingCreateArguments): Promise<Meeting> =>
|
|
79
|
+
client
|
|
80
|
+
.post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
|
|
81
|
+
.then(Meeting.parse),
|
|
82
|
+
|
|
83
|
+
updateMyMeeting: (meetingUuid: string, data: MeetingUpdateArguments): Promise<Boolean> =>
|
|
84
|
+
client.put(
|
|
85
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}`,
|
|
86
|
+
convertKeysFromCamelToUnderscore(data),
|
|
87
|
+
null,
|
|
88
|
+
ApiRequester.successResponseParser,
|
|
89
|
+
),
|
|
77
90
|
|
|
78
91
|
deleteMyMeeting: (meetingUuid: string): Promise<Meeting> =>
|
|
79
92
|
client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
|
|
@@ -81,6 +94,34 @@ export default (client: ApiRequester, baseUrl: string) => ({
|
|
|
81
94
|
getMeeting: (meetingUuid: string): Promise<Meeting> =>
|
|
82
95
|
client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
83
96
|
|
|
97
|
+
meetingAuthorizations: (meetingUuid: string): Promise<Array<MeetingAuthorization>> =>
|
|
98
|
+
client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
|
|
99
|
+
|
|
100
|
+
meetingAuthorizationReject: (meetingUuid: string, authorizationUuid: string): Promise<Boolean> =>
|
|
101
|
+
client.put(
|
|
102
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
|
|
103
|
+
{},
|
|
104
|
+
null,
|
|
105
|
+
ApiRequester.successResponseParser,
|
|
106
|
+
),
|
|
107
|
+
|
|
108
|
+
meetingAuthorizationAccept: (meetingUuid: string, authorizationUuid: string): Promise<Boolean> =>
|
|
109
|
+
client.put(
|
|
110
|
+
`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
|
|
111
|
+
{},
|
|
112
|
+
null,
|
|
113
|
+
ApiRequester.successResponseParser,
|
|
114
|
+
),
|
|
115
|
+
|
|
84
116
|
guestGetMeeting: (meetingUuid: string): Promise<Meeting> =>
|
|
85
117
|
client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
|
|
118
|
+
|
|
119
|
+
guestAuthorizationRequest: (userUuid: string, meetingUuid: string, username: string): Promise<> =>
|
|
120
|
+
client
|
|
121
|
+
.post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
|
|
122
|
+
.then(MeetingAuthorization.parse),
|
|
123
|
+
|
|
124
|
+
guestAuthorizationCheck: (userUuid: string, meetingUuid: string, authorizationUuid: string): Promise<> =>
|
|
125
|
+
client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
|
|
126
|
+
|
|
86
127
|
});
|
package/src/domain/Call.js
CHANGED
|
@@ -15,6 +15,7 @@ type CallResponse = {
|
|
|
15
15
|
dialed_extension: string,
|
|
16
16
|
status: string,
|
|
17
17
|
is_caller: boolean,
|
|
18
|
+
is_video?: boolean,
|
|
18
19
|
line_id: ?number,
|
|
19
20
|
creation_time: string,
|
|
20
21
|
on_hold: boolean,
|
|
@@ -27,6 +28,7 @@ type CallArguments = {
|
|
|
27
28
|
id: string,
|
|
28
29
|
sipCallId: string,
|
|
29
30
|
isCaller: boolean,
|
|
31
|
+
isVideo?: boolean,
|
|
30
32
|
callerName: string,
|
|
31
33
|
callerNumber: string,
|
|
32
34
|
calleeName: string,
|
|
@@ -53,6 +55,7 @@ export default class Call {
|
|
|
53
55
|
dialedExtension: string;
|
|
54
56
|
lineId: ?number;
|
|
55
57
|
isCaller: boolean;
|
|
58
|
+
isVideo: boolean;
|
|
56
59
|
onHold: boolean;
|
|
57
60
|
muted: boolean;
|
|
58
61
|
status: string;
|
|
@@ -77,6 +80,7 @@ export default class Call {
|
|
|
77
80
|
calleeNumber: plain.peer_caller_id_number,
|
|
78
81
|
dialedExtension: plain.dialed_extension,
|
|
79
82
|
isCaller: plain.is_caller,
|
|
83
|
+
isVideo: plain.is_video,
|
|
80
84
|
muted: plain.muted,
|
|
81
85
|
onHold: plain.on_hold,
|
|
82
86
|
status: plain.status,
|
|
@@ -100,6 +104,7 @@ export default class Call {
|
|
|
100
104
|
calleeNumber,
|
|
101
105
|
dialedExtension,
|
|
102
106
|
isCaller,
|
|
107
|
+
isVideo,
|
|
103
108
|
lineId,
|
|
104
109
|
muted,
|
|
105
110
|
onHold,
|
|
@@ -123,6 +128,7 @@ export default class Call {
|
|
|
123
128
|
this.startingTime = startingTime;
|
|
124
129
|
this.talkingToIds = talkingToIds || [];
|
|
125
130
|
this.recording = recording;
|
|
131
|
+
this.isVideo = !!isVideo;
|
|
126
132
|
|
|
127
133
|
// Useful to compare instead of instanceof with minified code
|
|
128
134
|
this.type = 'Call';
|
|
@@ -390,7 +390,7 @@ export default class CallSession {
|
|
|
390
390
|
ringing: call.isRinging(),
|
|
391
391
|
answered: call.isUp(),
|
|
392
392
|
answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
|
|
393
|
-
cameraEnabled:
|
|
393
|
+
cameraEnabled: call.isVideo,
|
|
394
394
|
dialedExtension: call.dialedExtension,
|
|
395
395
|
call,
|
|
396
396
|
conference: false, // @FIXME?
|
package/src/domain/Meeting.js
CHANGED
|
@@ -3,6 +3,19 @@ import moment from 'moment';
|
|
|
3
3
|
|
|
4
4
|
import newFrom from '../utils/new-from';
|
|
5
5
|
|
|
6
|
+
import MeetingAuthorization from './MeetingAuthorization';
|
|
7
|
+
|
|
8
|
+
export type MeetingCreateArguments = {
|
|
9
|
+
name: string,
|
|
10
|
+
requireAuthorization: boolean,
|
|
11
|
+
persistent: boolean,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type MeetingUpdateArguments = {
|
|
15
|
+
name?: string,
|
|
16
|
+
requireAuthorization?: boolean,
|
|
17
|
+
}
|
|
18
|
+
|
|
6
19
|
export type MeetingCreationResponse = {
|
|
7
20
|
guest_sip_authorization: string,
|
|
8
21
|
ingress_http_uri: string,
|
|
@@ -13,6 +26,7 @@ export type MeetingCreationResponse = {
|
|
|
13
26
|
exten: string,
|
|
14
27
|
persistent: boolean,
|
|
15
28
|
creation_time: string,
|
|
29
|
+
require_authorization: boolean,
|
|
16
30
|
}
|
|
17
31
|
|
|
18
32
|
export default class Meeting {
|
|
@@ -27,6 +41,8 @@ export default class Meeting {
|
|
|
27
41
|
persistent: boolean;
|
|
28
42
|
ownerUuids: Array<string>;
|
|
29
43
|
creationTime: Date;
|
|
44
|
+
pendingAuthorizations: Array<MeetingAuthorization>
|
|
45
|
+
requireAuthorization: boolean;
|
|
30
46
|
|
|
31
47
|
static parse(plain: MeetingCreationResponse): Meeting {
|
|
32
48
|
return new Meeting({
|
|
@@ -39,6 +55,7 @@ export default class Meeting {
|
|
|
39
55
|
extension: plain.exten,
|
|
40
56
|
persistent: plain.persistent,
|
|
41
57
|
creationTime: moment(plain.creation_time).toDate(),
|
|
58
|
+
requireAuthorization: plain.require_authorization,
|
|
42
59
|
});
|
|
43
60
|
}
|
|
44
61
|
|
|
@@ -63,6 +80,7 @@ export default class Meeting {
|
|
|
63
80
|
extension,
|
|
64
81
|
persistent,
|
|
65
82
|
creationTime,
|
|
83
|
+
requireAuthorization,
|
|
66
84
|
}: Object = {}) {
|
|
67
85
|
this.guestSipAuthorization = guestSipAuthorization;
|
|
68
86
|
this.uri = uri;
|
|
@@ -73,6 +91,7 @@ export default class Meeting {
|
|
|
73
91
|
this.extension = extension;
|
|
74
92
|
this.persistent = persistent;
|
|
75
93
|
this.creationTime = creationTime;
|
|
94
|
+
this.requireAuthorization = requireAuthorization;
|
|
76
95
|
|
|
77
96
|
// Useful to compare instead of instanceof with minified code
|
|
78
97
|
this.type = 'Meeting';
|
|
@@ -83,4 +102,5 @@ export default class Meeting {
|
|
|
83
102
|
const [username, secret] = atob(this.guestSipAuthorization).split(':');
|
|
84
103
|
return { username, secret };
|
|
85
104
|
}
|
|
105
|
+
|
|
86
106
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
export type RawMeetingAuthorization = {
|
|
4
|
+
created_at: string,
|
|
5
|
+
meeting_uuid: string,
|
|
6
|
+
uuid: string,
|
|
7
|
+
guest_uuid: string,
|
|
8
|
+
guest_name: string,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const PENDING = 'pending';
|
|
12
|
+
export const ACCEPTED = 'accepted';
|
|
13
|
+
export const REJECTED = 'rejected';
|
|
14
|
+
export const POST_PROCESSING = 'post_processing';
|
|
15
|
+
export const POST_PROCESSED_SUCCESS = 'post_processed_success';
|
|
16
|
+
export const POST_PROCESSED_ERROR = 'post_processed_error';
|
|
17
|
+
|
|
18
|
+
export default class MeetingAuthorization {
|
|
19
|
+
meetingUuid: string;
|
|
20
|
+
uuid: string;
|
|
21
|
+
userUuid: string;
|
|
22
|
+
userName: string;
|
|
23
|
+
status: string;
|
|
24
|
+
|
|
25
|
+
constructor({
|
|
26
|
+
meetingUuid,
|
|
27
|
+
uuid,
|
|
28
|
+
userUuid,
|
|
29
|
+
userName,
|
|
30
|
+
}: Object = {}) {
|
|
31
|
+
this.meetingUuid = meetingUuid;
|
|
32
|
+
this.uuid = uuid;
|
|
33
|
+
this.userUuid = userUuid;
|
|
34
|
+
this.userName = userName;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setStatus(status: string) {
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getStatus() {
|
|
42
|
+
return this.status;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static parse(plain: RawMeetingAuthorization) {
|
|
46
|
+
const {
|
|
47
|
+
meeting_uuid: meetingUuid,
|
|
48
|
+
uuid,
|
|
49
|
+
guest_uuid: userUuid,
|
|
50
|
+
guest_name: userName,
|
|
51
|
+
} = plain;
|
|
52
|
+
|
|
53
|
+
return new MeetingAuthorization({
|
|
54
|
+
meetingUuid,
|
|
55
|
+
uuid,
|
|
56
|
+
userUuid,
|
|
57
|
+
userName,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static parseMany(items: RawMeetingAuthorization[]): Array<MeetingAuthorization> {
|
|
62
|
+
if (!items) {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
return items.map(MeetingAuthorization.parse);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -668,10 +668,10 @@ export default class WebRTCPhone extends Emitter implements Phone {
|
|
|
668
668
|
this.audioRingVolume = volume;
|
|
669
669
|
}
|
|
670
670
|
|
|
671
|
-
changeAudioInputDevice(id: string) {
|
|
671
|
+
changeAudioInputDevice(id: string, force: ?boolean) {
|
|
672
672
|
logger.info('WebRTC phone - changeAudio input device', { deviceId: id });
|
|
673
673
|
|
|
674
|
-
return this.client.changeAudioInputDevice(id, this.currentSipSession);
|
|
674
|
+
return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
|
|
675
675
|
}
|
|
676
676
|
|
|
677
677
|
changeVideoInputDevice(id: ?string) {
|
|
@@ -1,9 +1,76 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
/* global btoa */
|
|
3
3
|
|
|
4
|
+
import moment from 'moment';
|
|
4
5
|
import Meeting from '../Meeting';
|
|
5
6
|
|
|
7
|
+
const rawCreationTime = '2021-12-21T15:56:42.880Z';
|
|
8
|
+
|
|
6
9
|
describe('Meeting domain', () => {
|
|
10
|
+
it('should retain its values when parsed', () => {
|
|
11
|
+
const args = {
|
|
12
|
+
guest_sip_authorization: 'some-guest-sip-authorization',
|
|
13
|
+
ingress_http_uri: 'some-uri',
|
|
14
|
+
name: 'some-name',
|
|
15
|
+
owner_uuids: ['some-owner-uuid'],
|
|
16
|
+
port: 'some-port',
|
|
17
|
+
uuid: 'some-uuid',
|
|
18
|
+
exten: 'some-exten',
|
|
19
|
+
persistent: true,
|
|
20
|
+
creation_time: rawCreationTime,
|
|
21
|
+
require_authorization: true,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const meeting = Meeting.parse(args);
|
|
25
|
+
const {
|
|
26
|
+
uri,
|
|
27
|
+
uuid,
|
|
28
|
+
name,
|
|
29
|
+
port,
|
|
30
|
+
extension,
|
|
31
|
+
persistent,
|
|
32
|
+
ownerUuids,
|
|
33
|
+
creationTime,
|
|
34
|
+
requireAuthorization,
|
|
35
|
+
} = meeting;
|
|
36
|
+
|
|
37
|
+
expect(uri).toEqual(args.ingress_http_uri);
|
|
38
|
+
expect(uuid).toEqual(args.uuid);
|
|
39
|
+
expect(name).toEqual(args.name);
|
|
40
|
+
expect(port).toEqual(args.port);
|
|
41
|
+
expect(extension).toEqual(args.exten);
|
|
42
|
+
expect(persistent).toEqual(args.persistent);
|
|
43
|
+
expect(ownerUuids).toEqual(args.owner_uuids);
|
|
44
|
+
expect(creationTime).toEqual(moment(rawCreationTime).toDate());
|
|
45
|
+
expect(requireAuthorization).toEqual(args.require_authorization);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should retain its values when instantiated', () => {
|
|
49
|
+
const keys = [
|
|
50
|
+
'uuid',
|
|
51
|
+
'name',
|
|
52
|
+
'guestSipAuthorization',
|
|
53
|
+
'ownerUuids',
|
|
54
|
+
'port',
|
|
55
|
+
'uri',
|
|
56
|
+
'extension',
|
|
57
|
+
'persistent',
|
|
58
|
+
'creationTime',
|
|
59
|
+
'requireAuthorization',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const args = keys.reduce((acc, key) => {
|
|
63
|
+
acc[key] = `some-${key}`;
|
|
64
|
+
return acc;
|
|
65
|
+
}, {});
|
|
66
|
+
|
|
67
|
+
const meeting = new Meeting(args);
|
|
68
|
+
|
|
69
|
+
keys.forEach(key =>
|
|
70
|
+
// $FlowFixMe
|
|
71
|
+
expect(meeting[key]).toEqual(`some-${key}`));
|
|
72
|
+
});
|
|
73
|
+
|
|
7
74
|
it('can return username and secret from an base64 encrypted string', () => {
|
|
8
75
|
const USERNAME = 'username';
|
|
9
76
|
const SECRET = 'secret';
|
|
@@ -18,6 +85,7 @@ describe('Meeting domain', () => {
|
|
|
18
85
|
uuid: '',
|
|
19
86
|
exten: '',
|
|
20
87
|
persistent: false,
|
|
88
|
+
require_authorization: false,
|
|
21
89
|
};
|
|
22
90
|
|
|
23
91
|
const meeting = Meeting.parse(args);
|
|
@@ -30,7 +98,7 @@ describe('Meeting domain', () => {
|
|
|
30
98
|
|
|
31
99
|
it('should return a date from a string', () => {
|
|
32
100
|
const args = {
|
|
33
|
-
creation_time:
|
|
101
|
+
creation_time: rawCreationTime,
|
|
34
102
|
guest_sip_authorization: '',
|
|
35
103
|
ingress_http_uri: '',
|
|
36
104
|
name: '',
|
|
@@ -39,6 +107,7 @@ describe('Meeting domain', () => {
|
|
|
39
107
|
uuid: '',
|
|
40
108
|
exten: '',
|
|
41
109
|
persistent: false,
|
|
110
|
+
require_authorization: false,
|
|
42
111
|
};
|
|
43
112
|
|
|
44
113
|
const { creationTime } = Meeting.parse(args);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import MeetingAuthorization from '../MeetingAuthorization';
|
|
2
|
+
|
|
3
|
+
describe('MeetingAuthorization', () => {
|
|
4
|
+
describe('parse', () => {
|
|
5
|
+
it('should parse a raw input', () => {
|
|
6
|
+
const rawAuthorization = {
|
|
7
|
+
created_at: 'today',
|
|
8
|
+
meeting_uuid: 'meeting_uuid',
|
|
9
|
+
uuid: 'uuid',
|
|
10
|
+
guest_uuid: 'guest_uuid',
|
|
11
|
+
guest_name: 'guest_name',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const authorization = {
|
|
15
|
+
meetingUuid: rawAuthorization.meeting_uuid,
|
|
16
|
+
uuid: rawAuthorization.uuid,
|
|
17
|
+
userUuid: rawAuthorization.guest_uuid,
|
|
18
|
+
userName: rawAuthorization.guest_name,
|
|
19
|
+
status: undefined,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const response = MeetingAuthorization.parse(rawAuthorization);
|
|
23
|
+
expect(response).toEqual(authorization);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('parseMany', () => {
|
|
28
|
+
it('should parse multiple raw inputs', () => {
|
|
29
|
+
const rawAuthorizations = [
|
|
30
|
+
{
|
|
31
|
+
created_at: 'today1',
|
|
32
|
+
meeting_uuid: 'meeting_uuid1',
|
|
33
|
+
uuid: 'uuid1',
|
|
34
|
+
guest_uuid: 'guest_uuid1',
|
|
35
|
+
guest_name: 'guest_name1',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
created_at: 'today2',
|
|
39
|
+
meeting_uuid: 'meeting_uuid2',
|
|
40
|
+
uuid: 'uuid2',
|
|
41
|
+
guest_uuid: 'guest_uuid2',
|
|
42
|
+
guest_name: 'guest_name2',
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const authorizations = rawAuthorizations.map(rawAuthorization => ({
|
|
47
|
+
meetingUuid: rawAuthorization.meeting_uuid,
|
|
48
|
+
uuid: rawAuthorization.uuid,
|
|
49
|
+
userUuid: rawAuthorization.guest_uuid,
|
|
50
|
+
userName: rawAuthorization.guest_name,
|
|
51
|
+
status: undefined,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
const response = MeetingAuthorization.parseMany(rawAuthorizations);
|
|
55
|
+
expect(response).toEqual(authorizations);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -12,7 +12,7 @@ import { SessionDescriptionHandler }
|
|
|
12
12
|
import { SessionDescriptionHandlerOptions }
|
|
13
13
|
from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-options';
|
|
14
14
|
import IssueReporter from '../service/IssueReporter';
|
|
15
|
-
import { fixSdp, parseCandidate } from '../utils/sdp';
|
|
15
|
+
import { addIcesInAllBundles, fixSdp, parseCandidate } from '../utils/sdp';
|
|
16
16
|
|
|
17
17
|
const wazoLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-sdh') : console;
|
|
18
18
|
|
|
@@ -141,7 +141,10 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
|
|
|
141
141
|
|
|
142
142
|
// Check if we got ICEs
|
|
143
143
|
if (sdp.indexOf('a=candidate') !== -1) {
|
|
144
|
-
return
|
|
144
|
+
return {
|
|
145
|
+
type: description.type,
|
|
146
|
+
sdp: addIcesInAllBundles(sdp),
|
|
147
|
+
};
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
|
|
@@ -4,6 +4,7 @@ import IssueReporter from '../../service/IssueReporter';
|
|
|
4
4
|
|
|
5
5
|
import Room, { SIGNAL_TYPE_PARTICIPANT_UPDATE } from './Room';
|
|
6
6
|
import Contact from '../../domain/Contact';
|
|
7
|
+
import getApiClient from '../../service/getApiClient';
|
|
7
8
|
|
|
8
9
|
const logger = IssueReporter.loggerFor('room');
|
|
9
10
|
|
|
@@ -20,6 +21,7 @@ class Participant extends Emitter {
|
|
|
20
21
|
videoMuted: boolean;
|
|
21
22
|
screensharing: boolean;
|
|
22
23
|
isOnHold: boolean;
|
|
24
|
+
banned: boolean;
|
|
23
25
|
extra: Object;
|
|
24
26
|
|
|
25
27
|
ON_UPDATED: string;
|
|
@@ -37,6 +39,7 @@ class Participant extends Emitter {
|
|
|
37
39
|
ON_EXTRA_CHANGE: string;
|
|
38
40
|
ON_HOLD: string;
|
|
39
41
|
ON_RESUME: string;
|
|
42
|
+
ON_BAN: string;
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
45
|
* @param room Room The room where the participant is
|
|
@@ -60,6 +63,7 @@ class Participant extends Emitter {
|
|
|
60
63
|
this.screensharing = false;
|
|
61
64
|
this.isOnHold = false;
|
|
62
65
|
this.extra = extra;
|
|
66
|
+
this.banned = false;
|
|
63
67
|
|
|
64
68
|
this.ON_UPDATED = 'participant/ON_UPDATED';
|
|
65
69
|
this.ON_START_TALKING = 'participant/ON_START_TALKING';
|
|
@@ -76,6 +80,7 @@ class Participant extends Emitter {
|
|
|
76
80
|
this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
|
|
77
81
|
this.ON_HOLD = 'participant/ON_HOLD';
|
|
78
82
|
this.ON_RESUME = 'participant/ON_RESUME';
|
|
83
|
+
this.ON_BAN = 'participant/ON_BAN';
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
triggerEvent(name: string, ...args: any[]) {
|
|
@@ -116,6 +121,10 @@ class Participant extends Emitter {
|
|
|
116
121
|
status.extra = this.extra;
|
|
117
122
|
break;
|
|
118
123
|
}
|
|
124
|
+
case this.ON_BAN: {
|
|
125
|
+
status.banned = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
119
128
|
default:
|
|
120
129
|
break;
|
|
121
130
|
}
|
|
@@ -220,6 +229,11 @@ class Participant extends Emitter {
|
|
|
220
229
|
this.triggerUpdate(this.ON_RESUME, broadcast);
|
|
221
230
|
}
|
|
222
231
|
|
|
232
|
+
onBan(broadcast: boolean = true) {
|
|
233
|
+
this.banned = true;
|
|
234
|
+
this.triggerUpdate(this.ON_BAN, broadcast);
|
|
235
|
+
}
|
|
236
|
+
|
|
223
237
|
getStatus() {
|
|
224
238
|
return {
|
|
225
239
|
callId: this.callId,
|
|
@@ -266,6 +280,10 @@ class Participant extends Emitter {
|
|
|
266
280
|
}
|
|
267
281
|
}
|
|
268
282
|
|
|
283
|
+
if (status.banned) {
|
|
284
|
+
this.onBan(false);
|
|
285
|
+
}
|
|
286
|
+
|
|
269
287
|
// Poor man's object comparison
|
|
270
288
|
if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
|
|
271
289
|
this.extra = { ...this.extra, ...status.extra };
|
|
@@ -293,6 +311,28 @@ class Participant extends Emitter {
|
|
|
293
311
|
this.streams = streams;
|
|
294
312
|
this.videoStreams = streams;
|
|
295
313
|
}
|
|
314
|
+
|
|
315
|
+
async ban(apiRequestDelay: ?number = null) {
|
|
316
|
+
const { meetingUuid } = this.room;
|
|
317
|
+
if (!meetingUuid) {
|
|
318
|
+
throw new Error('Attempting to ban a participant without a `meetingUuid`');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// this notifies all that someone is being banned
|
|
322
|
+
this.onBan(true);
|
|
323
|
+
|
|
324
|
+
// this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
|
|
325
|
+
if (apiRequestDelay) {
|
|
326
|
+
await this.delay(apiRequestDelay);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// proceed with the actual kick
|
|
330
|
+
return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async delay(ms: number) {
|
|
334
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
335
|
+
}
|
|
296
336
|
}
|
|
297
337
|
|
|
298
338
|
export default Participant;
|
package/src/simple/room/Room.js
CHANGED
|
@@ -143,7 +143,7 @@ class Room extends Emitter {
|
|
|
143
143
|
logger.info('connecting to room', { extension, audioOnly, room: !!room });
|
|
144
144
|
|
|
145
145
|
if (!room) {
|
|
146
|
-
await Wazo.Phone.connect();
|
|
146
|
+
await Wazo.Phone.connect({ media: constraints });
|
|
147
147
|
|
|
148
148
|
const withCamera = constraints && !!constraints.video;
|
|
149
149
|
|
|
@@ -590,7 +590,7 @@ class Room extends Emitter {
|
|
|
590
590
|
const participant: ?Participant = this._getParticipantFromCallId(status.callId);
|
|
591
591
|
|
|
592
592
|
if (participant) {
|
|
593
|
-
// we're
|
|
593
|
+
// we're receiving, so no need to broadcast
|
|
594
594
|
participant.updateStatus(status, false);
|
|
595
595
|
}
|
|
596
596
|
break;
|
|
@@ -13,7 +13,7 @@ class SipRoom extends Room {
|
|
|
13
13
|
logger.info('connecting to sip room', { extension, audioOnly, room: !!room });
|
|
14
14
|
|
|
15
15
|
if (!room) {
|
|
16
|
-
await Wazo.Phone.connect();
|
|
16
|
+
await Wazo.Phone.connect({ media: constraints });
|
|
17
17
|
|
|
18
18
|
const withCamera = constraints && !!constraints.video;
|
|
19
19
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Using directly Wazo to avoid issues with require cycle
|
|
2
|
+
import getApiClient from '../../../service/getApiClient';
|
|
3
|
+
import Wazo from '../../index';
|
|
4
|
+
import Room from '../Room';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../../service/getApiClient');
|
|
7
|
+
|
|
8
|
+
describe('Participant', () => {
|
|
9
|
+
describe('ban', () => {
|
|
10
|
+
it('should throw an error when there is no meeting', async () => {
|
|
11
|
+
const room = new Room();
|
|
12
|
+
const participant = new Wazo.RemoteParticipant(room, {
|
|
13
|
+
call_id: 'id',
|
|
14
|
+
caller_id_name: 'Alice',
|
|
15
|
+
caller_id_number: 'number',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
await expect(async () => participant.ban())
|
|
19
|
+
.rejects.toThrow('Attempting to ban a participant without a `meetingUuid`');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should call the api', async () => {
|
|
23
|
+
const number = '1234';
|
|
24
|
+
const meetingUuid = 'some-meeting-uuid';
|
|
25
|
+
const callId = 'some-call-id';
|
|
26
|
+
const room = new Room();
|
|
27
|
+
room.setMeetingUuid(meetingUuid);
|
|
28
|
+
|
|
29
|
+
const banMeetingParticipant = jest.fn();
|
|
30
|
+
|
|
31
|
+
getApiClient.mockImplementation(() => ({
|
|
32
|
+
calld: {
|
|
33
|
+
banMeetingParticipant,
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
const participant = new Wazo.RemoteParticipant(room, {
|
|
38
|
+
call_id: callId,
|
|
39
|
+
caller_id_name: 'Alice',
|
|
40
|
+
caller_id_number: number,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
participant.onBan = jest.fn();
|
|
44
|
+
|
|
45
|
+
await participant.ban();
|
|
46
|
+
expect(banMeetingParticipant).toHaveBeenCalledWith(meetingUuid, callId);
|
|
47
|
+
expect(participant.onBan).toHaveBeenCalledWith(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should call the api with a delay', async () => {
|
|
51
|
+
const number = '1234';
|
|
52
|
+
const meetingUuid = 'some-meeting-uuid';
|
|
53
|
+
const callId = 'some-call-id';
|
|
54
|
+
const someDelay = 2;
|
|
55
|
+
const room = new Room();
|
|
56
|
+
room.setMeetingUuid(meetingUuid);
|
|
57
|
+
|
|
58
|
+
const banMeetingParticipant = jest.fn();
|
|
59
|
+
|
|
60
|
+
getApiClient.mockImplementation(() => ({
|
|
61
|
+
calld: {
|
|
62
|
+
banMeetingParticipant,
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
const participant = new Wazo.RemoteParticipant(room, {
|
|
67
|
+
call_id: callId,
|
|
68
|
+
caller_id_name: 'Alice',
|
|
69
|
+
caller_id_number: number,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
participant.delay = jest.fn();
|
|
73
|
+
participant.onBan = jest.fn();
|
|
74
|
+
|
|
75
|
+
await participant.ban(someDelay);
|
|
76
|
+
expect(banMeetingParticipant).toHaveBeenCalledWith(meetingUuid, callId);
|
|
77
|
+
expect(participant.delay).toHaveBeenCalledWith(someDelay);
|
|
78
|
+
expect(participant.onBan).toHaveBeenCalledWith(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
import type { ChatMessageResponse } from '../domain/ChatMessage';
|
|
9
9
|
import ChatRoom from '../domain/ChatRoom';
|
|
10
10
|
import Meeting from '../domain/Meeting';
|
|
11
|
+
import type MeetingAuthorization from '../domain/MeetingAuthorization';
|
|
11
12
|
|
|
12
13
|
type WebSocketBaseMessage = {
|
|
13
14
|
op: string,
|
|
@@ -189,6 +190,10 @@ type AgentPaused = WebSocketBaseMessage & { data: any, name: 'agent_paused' };
|
|
|
189
190
|
type AgentUnpaused = WebSocketBaseMessage & { data: any, name: 'agent_unpaused' };
|
|
190
191
|
|
|
191
192
|
type MeetingUserProgress = WebSocketBaseMessage & { data: Meeting, name: 'meeting_user_progress' };
|
|
193
|
+
type MeetingAuthorizationPending = WebSocketBaseMessage & {
|
|
194
|
+
data: MeetingAuthorization,
|
|
195
|
+
name: 'meeting_authorization_pending'
|
|
196
|
+
};
|
|
192
197
|
|
|
193
198
|
export type WebSocketMessage =
|
|
194
199
|
| CallCreated
|
|
@@ -223,4 +228,5 @@ export type WebSocketMessage =
|
|
|
223
228
|
| AgentStatusUpdate
|
|
224
229
|
| AgentPaused
|
|
225
230
|
| AgentUnpaused
|
|
226
|
-
| MeetingUserProgress
|
|
231
|
+
| MeetingUserProgress
|
|
232
|
+
| MeetingAuthorizationPending;
|