@wazo/sdk 0.38.6 → 0.38.9

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.
Files changed (118) hide show
  1. package/dist/wazo-sdk.js +2 -2
  2. package/esm/__tests__/api-client.test.js +142 -2
  3. package/esm/__tests__/web-rtc-client.test.js +249 -28
  4. package/esm/api/calld.js +8 -0
  5. package/esm/api/confd.js +134 -2
  6. package/esm/api-client.js +142 -2
  7. package/esm/checker/Checker.js +205 -25
  8. package/esm/checker/checks/aor.js +142 -2
  9. package/esm/checker/checks/api.js +142 -2
  10. package/esm/checker/checks/index.js +205 -25
  11. package/esm/checker/checks/wazo-websocket.js +2 -0
  12. package/esm/checker/checks/webrtc-transport.js +203 -25
  13. package/esm/checker/checks/webrtc.js +203 -25
  14. package/esm/domain/AdHocAPIConference.js +142 -2
  15. package/esm/domain/Features.js +142 -2
  16. package/esm/domain/Meeting.js +18 -0
  17. package/esm/domain/MeetingAuthorization.js +70 -0
  18. package/esm/domain/Phone/CTIPhone.js +142 -2
  19. package/esm/domain/Phone/WebRTCPhone.js +1 -3
  20. package/esm/domain/__tests__/Meeting.test.js +87 -1
  21. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  22. package/esm/index.js +249 -31
  23. package/esm/lib/WazoSessionDescriptionHandler.js +22 -1
  24. package/esm/service/CallApi.js +142 -2
  25. package/esm/service/getApiClient.js +142 -2
  26. package/esm/simple/Auth.js +249 -31
  27. package/esm/simple/Configuration.js +249 -31
  28. package/esm/simple/Directory.js +142 -2
  29. package/esm/simple/Phone.js +249 -31
  30. package/esm/simple/Websocket.js +3 -0
  31. package/esm/simple/index.js +249 -31
  32. package/esm/simple/room/LocalParticipant.js +249 -31
  33. package/esm/simple/room/Participant.js +249 -31
  34. package/esm/simple/room/RemoteParticipant.js +249 -31
  35. package/esm/simple/room/Room.js +249 -31
  36. package/esm/simple/room/SipRoom.js +249 -31
  37. package/esm/simple/room/Stream.js +249 -31
  38. package/esm/simple/room/__tests__/Participant.test.js +14745 -0
  39. package/esm/simple/room/__tests__/RemoteParticipant.test.js +249 -31
  40. package/esm/simple/utils.js +249 -31
  41. package/esm/utils/__tests__/object.test.js +57 -0
  42. package/esm/utils/__tests__/sdp.test.js +50 -0
  43. package/esm/utils/__tests__/string.test.js +30 -0
  44. package/esm/utils/object.js +24 -0
  45. package/esm/utils/sdp.js +19 -1
  46. package/esm/utils/string.js +10 -0
  47. package/esm/web-rtc-client.js +203 -25
  48. package/esm/websocket-client.js +3 -1
  49. package/lib/__tests__/api-client.test.js +142 -2
  50. package/lib/__tests__/web-rtc-client.test.js +249 -28
  51. package/lib/api/calld.js +8 -0
  52. package/lib/api/confd.js +134 -2
  53. package/lib/api-client.js +142 -2
  54. package/lib/checker/Checker.js +205 -25
  55. package/lib/checker/checks/aor.js +142 -2
  56. package/lib/checker/checks/api.js +142 -2
  57. package/lib/checker/checks/index.js +205 -25
  58. package/lib/checker/checks/wazo-websocket.js +2 -0
  59. package/lib/checker/checks/webrtc-transport.js +203 -25
  60. package/lib/checker/checks/webrtc.js +203 -25
  61. package/lib/domain/AdHocAPIConference.js +142 -2
  62. package/lib/domain/Features.js +142 -2
  63. package/lib/domain/Meeting.js +18 -0
  64. package/lib/domain/MeetingAuthorization.js +79 -0
  65. package/lib/domain/Phone/CTIPhone.js +142 -2
  66. package/lib/domain/Phone/WebRTCPhone.js +1 -3
  67. package/lib/domain/__tests__/Meeting.test.js +87 -1
  68. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  69. package/lib/index.js +249 -31
  70. package/lib/lib/WazoSessionDescriptionHandler.js +22 -1
  71. package/lib/service/CallApi.js +142 -2
  72. package/lib/service/getApiClient.js +142 -2
  73. package/lib/simple/Auth.js +249 -31
  74. package/lib/simple/Configuration.js +249 -31
  75. package/lib/simple/Directory.js +142 -2
  76. package/lib/simple/Phone.js +249 -31
  77. package/lib/simple/Websocket.js +3 -0
  78. package/lib/simple/index.js +249 -31
  79. package/lib/simple/room/LocalParticipant.js +249 -31
  80. package/lib/simple/room/Participant.js +249 -31
  81. package/lib/simple/room/RemoteParticipant.js +249 -31
  82. package/lib/simple/room/Room.js +249 -31
  83. package/lib/simple/room/SipRoom.js +249 -31
  84. package/lib/simple/room/Stream.js +249 -31
  85. package/lib/simple/room/__tests__/Participant.test.js +14755 -0
  86. package/lib/simple/room/__tests__/RemoteParticipant.test.js +249 -31
  87. package/lib/simple/utils.js +249 -31
  88. package/lib/utils/__tests__/object.test.js +59 -0
  89. package/lib/utils/__tests__/sdp.test.js +50 -0
  90. package/lib/utils/__tests__/string.test.js +32 -0
  91. package/lib/utils/object.js +28 -0
  92. package/lib/utils/sdp.js +19 -0
  93. package/lib/utils/string.js +14 -0
  94. package/lib/web-rtc-client.js +203 -25
  95. package/lib/websocket-client.js +3 -0
  96. package/package.json +2 -2
  97. package/src/__tests__/web-rtc-client.test.js +46 -3
  98. package/src/api/calld.js +8 -0
  99. package/src/api/confd.js +43 -2
  100. package/src/domain/Meeting.js +20 -0
  101. package/src/domain/MeetingAuthorization.js +67 -0
  102. package/src/domain/Phone/WebRTCPhone.js +1 -3
  103. package/src/domain/__tests__/Meeting.test.js +70 -1
  104. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  105. package/src/lib/WazoSessionDescriptionHandler.js +5 -2
  106. package/src/simple/room/Participant.js +40 -0
  107. package/src/simple/room/Room.js +2 -2
  108. package/src/simple/room/SipRoom.js +1 -1
  109. package/src/simple/room/__tests__/Participant.test.js +81 -0
  110. package/src/types/WebSocketMessage.js +7 -1
  111. package/src/utils/__tests__/object.test.js +35 -0
  112. package/src/utils/__tests__/sdp.test.js +33 -1
  113. package/src/utils/__tests__/string.test.js +23 -0
  114. package/src/utils/object.js +15 -0
  115. package/src/utils/sdp.js +18 -0
  116. package/src/utils/string.js +8 -0
  117. package/src/web-rtc-client.js +39 -22
  118. package/src/websocket-client.js +2 -0
package/lib/utils/sdp.js CHANGED
@@ -130,7 +130,26 @@ const fixSdp = (sdp , candidates , forcePort = true)
130
130
  return fixed;
131
131
  };
132
132
 
133
+ const addIcesInAllBundles = (sdp ) => {
134
+ const parsedSdp = sdpParser__default['default'].parse(sdp);
135
+
136
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
137
+ if (!mediaWithCandidate) {
138
+ return sdp;
139
+ }
140
+
141
+ const { candidates } = mediaWithCandidate;
142
+
143
+ parsedSdp.media = parsedSdp.media.map(media => ({
144
+ ...media,
145
+ candidates: media.candidates || candidates,
146
+ }));
147
+
148
+ return sdpParser__default['default'].write(parsedSdp);
149
+ };
150
+
133
151
  exports.activateVideoModifier = activateVideoModifier;
152
+ exports.addIcesInAllBundles = addIcesInAllBundles;
134
153
  exports.areCandidateValid = areCandidateValid;
135
154
  exports.deactivateVideoModifier = deactivateVideoModifier;
136
155
  exports.fixBundle = fixBundle;
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ //
6
+
7
+ const camelToUnderscore = (key ) => {
8
+ if (typeof key !== 'string') {
9
+ throw new Error('Input is not a string');
10
+ }
11
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
12
+ };
13
+
14
+ exports.camelToUnderscore = camelToUnderscore;
@@ -789,6 +789,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
789
789
  return fixed;
790
790
  };
791
791
 
792
+ const addIcesInAllBundles = (sdp ) => {
793
+ const parsedSdp = sdpParser__default['default'].parse(sdp);
794
+
795
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
796
+ if (!mediaWithCandidate) {
797
+ return sdp;
798
+ }
799
+
800
+ const { candidates } = mediaWithCandidate;
801
+
802
+ parsedSdp.media = parsedSdp.media.map(media => ({
803
+ ...media,
804
+ candidates: media.candidates || candidates,
805
+ }));
806
+
807
+ return sdpParser__default['default'].write(parsedSdp);
808
+ };
809
+
792
810
  /* global RTCSessionDescriptionInit, navigator */
793
811
 
794
812
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -918,7 +936,10 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
918
936
 
919
937
  // Check if we got ICEs
920
938
  if (sdp.indexOf('a=candidate') !== -1) {
921
- return description;
939
+ return {
940
+ type: description.type,
941
+ sdp: addIcesInAllBundles(sdp),
942
+ };
922
943
  }
923
944
 
924
945
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -3192,6 +3213,70 @@ class ExternalApp {
3192
3213
 
3193
3214
  //
3194
3215
 
3216
+ class MeetingAuthorization {
3217
+
3218
+
3219
+
3220
+
3221
+
3222
+
3223
+ constructor({
3224
+ meetingUuid,
3225
+ uuid,
3226
+ userUuid,
3227
+ userName,
3228
+ } = {}) {
3229
+ this.meetingUuid = meetingUuid;
3230
+ this.uuid = uuid;
3231
+ this.userUuid = userUuid;
3232
+ this.userName = userName;
3233
+ }
3234
+
3235
+ setStatus(status ) {
3236
+ this.status = status;
3237
+ }
3238
+
3239
+ getStatus() {
3240
+ return this.status;
3241
+ }
3242
+
3243
+ static parse(plain ) {
3244
+ const {
3245
+ meeting_uuid: meetingUuid,
3246
+ uuid,
3247
+ guest_uuid: userUuid,
3248
+ guest_name: userName,
3249
+ } = plain;
3250
+
3251
+ return new MeetingAuthorization({
3252
+ meetingUuid,
3253
+ uuid,
3254
+ userUuid,
3255
+ userName,
3256
+ });
3257
+ }
3258
+
3259
+ static parseMany(items ) {
3260
+ if (!items) {
3261
+ return [];
3262
+ }
3263
+ return items.map(MeetingAuthorization.parse);
3264
+ }
3265
+ }
3266
+
3267
+ //
3268
+
3269
+
3270
+
3271
+
3272
+
3273
+
3274
+
3275
+
3276
+
3277
+
3278
+
3279
+
3195
3280
 
3196
3281
 
3197
3282
 
@@ -3202,6 +3287,7 @@ class ExternalApp {
3202
3287
 
3203
3288
 
3204
3289
 
3290
+
3205
3291
 
3206
3292
 
3207
3293
  class Meeting {
@@ -3216,6 +3302,8 @@ class Meeting {
3216
3302
 
3217
3303
 
3218
3304
 
3305
+
3306
+
3219
3307
 
3220
3308
  static parse(plain ) {
3221
3309
  return new Meeting({
@@ -3228,6 +3316,7 @@ class Meeting {
3228
3316
  extension: plain.exten,
3229
3317
  persistent: plain.persistent,
3230
3318
  creationTime: moment__default['default'](plain.creation_time).toDate(),
3319
+ requireAuthorization: plain.require_authorization,
3231
3320
  });
3232
3321
  }
3233
3322
 
@@ -3252,6 +3341,7 @@ class Meeting {
3252
3341
  extension,
3253
3342
  persistent,
3254
3343
  creationTime,
3344
+ requireAuthorization,
3255
3345
  } = {}) {
3256
3346
  this.guestSipAuthorization = guestSipAuthorization;
3257
3347
  this.uri = uri;
@@ -3262,6 +3352,7 @@ class Meeting {
3262
3352
  this.extension = extension;
3263
3353
  this.persistent = persistent;
3264
3354
  this.creationTime = creationTime;
3355
+ this.requireAuthorization = requireAuthorization;
3265
3356
 
3266
3357
  // Useful to compare instead of instanceof with minified code
3267
3358
  this.type = 'Meeting';
@@ -3272,8 +3363,32 @@ class Meeting {
3272
3363
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
3273
3364
  return { username, secret };
3274
3365
  }
3366
+
3275
3367
  }
3276
3368
 
3369
+ //
3370
+
3371
+ const camelToUnderscore = (key ) => {
3372
+ if (typeof key !== 'string') {
3373
+ throw new Error('Input is not a string');
3374
+ }
3375
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
3376
+ };
3377
+
3378
+ //
3379
+
3380
+ const convertKeysFromCamelToUnderscore = (args ) => {
3381
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
3382
+ throw new Error('Input is not an object');
3383
+ }
3384
+
3385
+ return Object.keys(args).reduce((acc, key) => {
3386
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
3387
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
3388
+ return acc;
3389
+ }, {});
3390
+ };
3391
+
3277
3392
  /* */
3278
3393
 
3279
3394
  var confdMethods = (client , baseUrl ) => ({
@@ -3342,8 +3457,18 @@ var confdMethods = (client , baseUrl ) => ({
3342
3457
  getMyMeetings: () =>
3343
3458
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
3344
3459
 
3345
- createMyMeeting: (name , persistent ) =>
3346
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
3460
+ createMyMeeting: (args ) =>
3461
+ client
3462
+ .post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
3463
+ .then(Meeting.parse),
3464
+
3465
+ updateMyMeeting: (meetingUuid , data ) =>
3466
+ client.put(
3467
+ `${baseUrl}/users/me/meetings/${meetingUuid}`,
3468
+ convertKeysFromCamelToUnderscore(data),
3469
+ null,
3470
+ ApiRequester.successResponseParser,
3471
+ ),
3347
3472
 
3348
3473
  deleteMyMeeting: (meetingUuid ) =>
3349
3474
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -3351,8 +3476,36 @@ var confdMethods = (client , baseUrl ) => ({
3351
3476
  getMeeting: (meetingUuid ) =>
3352
3477
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
3353
3478
 
3479
+ meetingAuthorizations: (meetingUuid ) =>
3480
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
3481
+
3482
+ meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
3483
+ client.put(
3484
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
3485
+ {},
3486
+ null,
3487
+ ApiRequester.successResponseParser,
3488
+ ),
3489
+
3490
+ meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
3491
+ client.put(
3492
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
3493
+ {},
3494
+ null,
3495
+ ApiRequester.successResponseParser,
3496
+ ),
3497
+
3354
3498
  guestGetMeeting: (meetingUuid ) =>
3355
3499
  client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
3500
+
3501
+ guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
3502
+ client
3503
+ .post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
3504
+ .then(MeetingAuthorization.parse),
3505
+
3506
+ guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
3507
+ client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
3508
+
3356
3509
  });
3357
3510
 
3358
3511
  //
@@ -4791,6 +4944,14 @@ var calldMethods = (client , baseUrl ) => ({
4791
4944
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
4792
4945
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
4793
4946
 
4947
+ banMeetingParticipant: (meetingUuid , participantUuid ) =>
4948
+ client.delete(
4949
+ `${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
4950
+ null,
4951
+ null,
4952
+ ApiRequester.successResponseParser,
4953
+ ),
4954
+
4794
4955
  listTrunks: () => client.get(`${baseUrl}/trunks`),
4795
4956
 
4796
4957
  mute: (callId ) =>
@@ -6434,7 +6595,7 @@ class WebRTCClient extends Emitter {
6434
6595
  });
6435
6596
  }
6436
6597
 
6437
- changeAudioInputDevice(id , session , force ) {
6598
+ async changeAudioInputDevice(id , session , force ) {
6438
6599
  const currentId = this.getAudioDeviceId();
6439
6600
  logger.info('setting audio input device', { id, currentId, session: !!session });
6440
6601
 
@@ -6442,33 +6603,50 @@ class WebRTCClient extends Emitter {
6442
6603
  return null;
6443
6604
  }
6444
6605
 
6606
+ // in order to handle an audio track change for default devices
6607
+ // we need the actual id of the device (not 'default')
6608
+ let deviceId = id;
6609
+ if (id === 'default' && navigator.mediaDevices) {
6610
+ const devices = await navigator.mediaDevices.enumerateDevices();
6611
+ const defaultDevice = devices.find(device => device.deviceId === 'default');
6612
+ if (defaultDevice) {
6613
+ const deviceLabel = defaultDevice.label.replace('Default - ', '');
6614
+ const targetDevice = devices.find(device => device.label === deviceLabel);
6615
+ if (targetDevice) {
6616
+ deviceId = targetDevice.deviceId;
6617
+ if (!force && deviceId === currentId) {
6618
+ return null;
6619
+ }
6620
+ }
6621
+ }
6622
+ }
6623
+
6445
6624
  // let's update the local audio value
6446
6625
  if (this.audio) {
6447
6626
  this.audio = {
6448
6627
  deviceId: {
6449
- exact: id,
6628
+ exact: deviceId,
6450
6629
  },
6451
6630
  };
6452
6631
  }
6453
6632
 
6454
- if (session) {
6633
+ if (session && navigator.mediaDevices) {
6455
6634
  const sdh = session.sessionDescriptionHandler;
6456
6635
  const pc = sdh.peerConnection;
6457
6636
 
6458
- // $FlowFixMe
6459
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
6460
- const audioTrack = stream.getAudioTracks()[0];
6461
- const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6637
+ const constraints = { audio: { deviceId: { exact: deviceId } } };
6638
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
6639
+ const audioTrack = stream.getAudioTracks()[0];
6640
+ const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
6462
6641
 
6463
- if (sender) {
6464
- if (sender.track) {
6465
- audioTrack.enabled = sender.track.enabled;
6466
- }
6467
- sender.replaceTrack(audioTrack);
6642
+ if (sender) {
6643
+ if (sender.track) {
6644
+ audioTrack.enabled = sender.track.enabled;
6468
6645
  }
6646
+ sender.replaceTrack(audioTrack);
6647
+ }
6469
6648
 
6470
- return stream;
6471
- });
6649
+ return stream;
6472
6650
  }
6473
6651
  }
6474
6652
 
@@ -6488,14 +6666,14 @@ class WebRTCClient extends Emitter {
6488
6666
  return null;
6489
6667
  }
6490
6668
 
6491
- // let's update the local video value
6492
- if (this.video) {
6493
- this.video = {
6494
- deviceId: {
6495
- exact: id,
6496
- },
6497
- };
6498
- }
6669
+ // let's make sure we don't lose other video constraints settings -- width, height, frameRate...
6670
+ const videoObject = typeof this.video === 'object' ? this.video : {};
6671
+ this.video = {
6672
+ ...videoObject,
6673
+ deviceId: {
6674
+ exact: id,
6675
+ },
6676
+ };
6499
6677
  }
6500
6678
 
6501
6679
  changeSessionVideoInputDevice(id , session ) {
@@ -617,6 +617,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
617
617
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
618
618
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
619
619
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
620
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
620
621
 
621
622
  const BLACKLIST_EVENTS = [
622
623
  CHAT_MESSAGE_SENT,
@@ -968,6 +969,7 @@ WebSocketClient.eventLists = [
968
969
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
969
970
  CONFERENCE_ADHOC_DELETED,
970
971
  MEETING_USER_PROGRESS,
972
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
971
973
  ];
972
974
 
973
975
  exports.AGENT_PAUSED = AGENT_PAUSED;
@@ -1021,6 +1023,7 @@ exports.FAX_OUTBOUND_USER_FAILED = FAX_OUTBOUND_USER_FAILED;
1021
1023
  exports.FAX_OUTBOUND_USER_SUCCEEDED = FAX_OUTBOUND_USER_SUCCEEDED;
1022
1024
  exports.HEARTBEAT_ENGINE_VERSION = HEARTBEAT_ENGINE_VERSION;
1023
1025
  exports.LINE_STATUS_UPDATED = LINE_STATUS_UPDATED;
1026
+ exports.MEETING_USER_GUEST_AUTHORIZATION_CREATED = MEETING_USER_GUEST_AUTHORIZATION_CREATED;
1024
1027
  exports.MEETING_USER_PARTICIPANT_JOINED = MEETING_USER_PARTICIPANT_JOINED;
1025
1028
  exports.MEETING_USER_PARTICIPANT_LEFT = MEETING_USER_PARTICIPANT_LEFT;
1026
1029
  exports.MEETING_USER_PROGRESS = MEETING_USER_PROGRESS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wazo/sdk",
3
- "version": "0.38.6",
3
+ "version": "0.38.9",
4
4
  "description": "Wazo's JavaScript Software Development Kit.",
5
5
  "main": "dist/wazo-sdk.js",
6
6
  "author": "Wazo (http://wazo.io)",
@@ -100,4 +100,4 @@
100
100
  "react-native": {
101
101
  "node-fetch/lib/index": false
102
102
  }
103
- }
103
+ }
@@ -69,27 +69,70 @@ describe('changeAudioInputDevice', () => {
69
69
  });
70
70
  });
71
71
 
72
+ const devices = [
73
+ { deviceId: 'default', kind: 'audioinput', label: 'Default - Fake Microphone', groupId: 'fak3Gr0up3' },
74
+ { deviceId: 'fak3d3v1c3', kind: 'audioinput', label: 'Fake Microphone', groupId: 'fak3Gr0up3' },
75
+ ];
76
+ const enumerateDevicesMock = jest.fn(async () => {
77
+ return new Promise(resolve => {
78
+ resolve(devices);
79
+ });
80
+ });
81
+
72
82
  Object.defineProperty(global.navigator, 'mediaDevices', {
73
83
  value: {
74
84
  getUserMedia: getUserMediaMock,
85
+ enumerateDevices: enumerateDevicesMock,
75
86
  },
76
87
  });
77
88
 
78
89
  it('should change the audio input track if the provided id is different', async () => {
79
90
  client.setMediaConstraints(constraints);
80
91
  expect(client.getAudioDeviceId()).toBe(defaultId);
81
- expect(client.changeAudioInputDevice(deviceId, session)).toBeTruthy();
92
+ const result = await client.changeAudioInputDevice(deviceId, session);
93
+ expect(result).toBeTruthy();
82
94
  });
83
95
 
84
96
  it('should NOT change the audio input track if the provided id is the same', async () => {
85
97
  client.setMediaConstraints(constraints);
86
98
  expect(client.getAudioDeviceId()).toBe(defaultId);
87
- expect(client.changeAudioInputDevice(defaultId, session)).toBeFalsy();
99
+ const result = await client.changeAudioInputDevice(defaultId, session);
100
+ expect(result).toBeFalsy();
88
101
  });
89
102
 
90
103
  it('should change the audio input track if the provided id is the same and force param is TRUE', async () => {
91
104
  client.setMediaConstraints(constraints);
92
105
  expect(client.getAudioDeviceId()).toBe(defaultId);
93
- expect(client.changeAudioInputDevice(defaultId, session, true)).toBeTruthy();
106
+ const result = await client.changeAudioInputDevice(defaultId, session, true);
107
+ expect(result).toBeTruthy();
108
+ });
109
+
110
+ describe('setVideoInputDevice', () => {
111
+ it('should retain its original video values', () => {
112
+ const video = { height: { min: 480, max: 720 }, width: { min: 640, max: 1280 } };
113
+
114
+ client.video = video;
115
+ client.setVideoInputDevice(deviceId);
116
+ expect(client.video).toEqual({ ...video, deviceId: { exact: deviceId } });
117
+ });
118
+
119
+ it('should set deviceId when video\'s original value is true', () => {
120
+ client.video = true;
121
+ client.setVideoInputDevice(deviceId);
122
+ expect(client.video).toEqual({ deviceId: { exact: deviceId } });
123
+ });
124
+
125
+ it('should set deviceId when video\'s original value is not set', () => {
126
+ client.video = undefined;
127
+ client.setVideoInputDevice(deviceId);
128
+ expect(client.video).toEqual({ deviceId: { exact: deviceId } });
129
+ });
130
+
131
+ it('should NOT set deviceId when its value does not change', () => {
132
+ client.video = { deviceId: { exact: deviceId } };
133
+ const result = client.setVideoInputDevice(deviceId);
134
+ expect(result).toEqual(null);
135
+ expect(client.video).toEqual({ deviceId: { exact: deviceId } });
136
+ });
94
137
  });
95
138
  });
package/src/api/calld.js CHANGED
@@ -137,6 +137,14 @@ export default (client: ApiRequester, baseUrl: string) => ({
137
137
  getMeetingParticipantsAsUser: async (meetingUuid: string): Promise<Object> =>
138
138
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
139
139
 
140
+ banMeetingParticipant: (meetingUuid: string, participantUuid: string) =>
141
+ client.delete(
142
+ `${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
143
+ null,
144
+ null,
145
+ ApiRequester.successResponseParser,
146
+ ),
147
+
140
148
  listTrunks: () => client.get(`${baseUrl}/trunks`),
141
149
 
142
150
  mute: (callId: string) =>
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: (name: string, persistent: boolean): Promise<Meeting> =>
76
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
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
  });
@@ -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
  }