@wazo/sdk 0.38.7 → 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.
Files changed (106) 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 +227 -27
  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 +183 -24
  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 +183 -24
  11. package/esm/checker/checks/wazo-websocket.js +2 -0
  12. package/esm/checker/checks/webrtc-transport.js +181 -24
  13. package/esm/checker/checks/webrtc.js +181 -24
  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/__tests__/Meeting.test.js +87 -1
  20. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  21. package/esm/index.js +226 -27
  22. package/esm/service/CallApi.js +142 -2
  23. package/esm/service/getApiClient.js +142 -2
  24. package/esm/simple/Auth.js +226 -27
  25. package/esm/simple/Configuration.js +226 -27
  26. package/esm/simple/Directory.js +142 -2
  27. package/esm/simple/Phone.js +226 -27
  28. package/esm/simple/Websocket.js +3 -0
  29. package/esm/simple/index.js +226 -27
  30. package/esm/simple/room/LocalParticipant.js +226 -27
  31. package/esm/simple/room/Participant.js +226 -27
  32. package/esm/simple/room/RemoteParticipant.js +226 -27
  33. package/esm/simple/room/Room.js +226 -27
  34. package/esm/simple/room/SipRoom.js +226 -27
  35. package/esm/simple/room/Stream.js +226 -27
  36. package/esm/simple/room/__tests__/Participant.test.js +14747 -0
  37. package/esm/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  38. package/esm/simple/utils.js +226 -27
  39. package/esm/utils/__tests__/object.test.js +57 -0
  40. package/esm/utils/__tests__/string.test.js +30 -0
  41. package/esm/utils/object.js +24 -0
  42. package/esm/utils/string.js +10 -0
  43. package/esm/web-rtc-client.js +181 -24
  44. package/esm/websocket-client.js +3 -1
  45. package/lib/__tests__/api-client.test.js +142 -2
  46. package/lib/__tests__/web-rtc-client.test.js +227 -27
  47. package/lib/api/calld.js +8 -0
  48. package/lib/api/confd.js +134 -2
  49. package/lib/api-client.js +142 -2
  50. package/lib/checker/Checker.js +183 -24
  51. package/lib/checker/checks/aor.js +142 -2
  52. package/lib/checker/checks/api.js +142 -2
  53. package/lib/checker/checks/index.js +183 -24
  54. package/lib/checker/checks/wazo-websocket.js +2 -0
  55. package/lib/checker/checks/webrtc-transport.js +181 -24
  56. package/lib/checker/checks/webrtc.js +181 -24
  57. package/lib/domain/AdHocAPIConference.js +142 -2
  58. package/lib/domain/Features.js +142 -2
  59. package/lib/domain/Meeting.js +18 -0
  60. package/lib/domain/MeetingAuthorization.js +79 -0
  61. package/lib/domain/Phone/CTIPhone.js +142 -2
  62. package/lib/domain/__tests__/Meeting.test.js +87 -1
  63. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  64. package/lib/index.js +226 -27
  65. package/lib/service/CallApi.js +142 -2
  66. package/lib/service/getApiClient.js +142 -2
  67. package/lib/simple/Auth.js +226 -27
  68. package/lib/simple/Configuration.js +226 -27
  69. package/lib/simple/Directory.js +142 -2
  70. package/lib/simple/Phone.js +226 -27
  71. package/lib/simple/Websocket.js +3 -0
  72. package/lib/simple/index.js +226 -27
  73. package/lib/simple/room/LocalParticipant.js +226 -27
  74. package/lib/simple/room/Participant.js +226 -27
  75. package/lib/simple/room/RemoteParticipant.js +226 -27
  76. package/lib/simple/room/Room.js +226 -27
  77. package/lib/simple/room/SipRoom.js +226 -27
  78. package/lib/simple/room/Stream.js +226 -27
  79. package/lib/simple/room/__tests__/Participant.test.js +14757 -0
  80. package/lib/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  81. package/lib/simple/utils.js +226 -27
  82. package/lib/utils/__tests__/object.test.js +59 -0
  83. package/lib/utils/__tests__/string.test.js +32 -0
  84. package/lib/utils/object.js +28 -0
  85. package/lib/utils/string.js +14 -0
  86. package/lib/web-rtc-client.js +181 -24
  87. package/lib/websocket-client.js +3 -0
  88. package/package.json +2 -2
  89. package/src/__tests__/web-rtc-client.test.js +46 -3
  90. package/src/api/calld.js +8 -0
  91. package/src/api/confd.js +43 -2
  92. package/src/domain/Meeting.js +20 -0
  93. package/src/domain/MeetingAuthorization.js +67 -0
  94. package/src/domain/__tests__/Meeting.test.js +70 -1
  95. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  96. package/src/simple/room/Participant.js +40 -0
  97. package/src/simple/room/Room.js +2 -2
  98. package/src/simple/room/SipRoom.js +1 -1
  99. package/src/simple/room/__tests__/Participant.test.js +81 -0
  100. package/src/types/WebSocketMessage.js +7 -1
  101. package/src/utils/__tests__/object.test.js +35 -0
  102. package/src/utils/__tests__/string.test.js +23 -0
  103. package/src/utils/object.js +15 -0
  104. package/src/utils/string.js +8 -0
  105. package/src/web-rtc-client.js +39 -22
  106. package/src/websocket-client.js +2 -0
@@ -3213,6 +3213,70 @@ class ExternalApp {
3213
3213
 
3214
3214
  //
3215
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
+
3216
3280
 
3217
3281
 
3218
3282
 
@@ -3223,6 +3287,7 @@ class ExternalApp {
3223
3287
 
3224
3288
 
3225
3289
 
3290
+
3226
3291
 
3227
3292
 
3228
3293
  class Meeting {
@@ -3237,6 +3302,8 @@ class Meeting {
3237
3302
 
3238
3303
 
3239
3304
 
3305
+
3306
+
3240
3307
 
3241
3308
  static parse(plain ) {
3242
3309
  return new Meeting({
@@ -3249,6 +3316,7 @@ class Meeting {
3249
3316
  extension: plain.exten,
3250
3317
  persistent: plain.persistent,
3251
3318
  creationTime: moment__default['default'](plain.creation_time).toDate(),
3319
+ requireAuthorization: plain.require_authorization,
3252
3320
  });
3253
3321
  }
3254
3322
 
@@ -3273,6 +3341,7 @@ class Meeting {
3273
3341
  extension,
3274
3342
  persistent,
3275
3343
  creationTime,
3344
+ requireAuthorization,
3276
3345
  } = {}) {
3277
3346
  this.guestSipAuthorization = guestSipAuthorization;
3278
3347
  this.uri = uri;
@@ -3283,6 +3352,7 @@ class Meeting {
3283
3352
  this.extension = extension;
3284
3353
  this.persistent = persistent;
3285
3354
  this.creationTime = creationTime;
3355
+ this.requireAuthorization = requireAuthorization;
3286
3356
 
3287
3357
  // Useful to compare instead of instanceof with minified code
3288
3358
  this.type = 'Meeting';
@@ -3293,8 +3363,32 @@ class Meeting {
3293
3363
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
3294
3364
  return { username, secret };
3295
3365
  }
3366
+
3296
3367
  }
3297
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
+
3298
3392
  /* */
3299
3393
 
3300
3394
  var confdMethods = (client , baseUrl ) => ({
@@ -3363,8 +3457,18 @@ var confdMethods = (client , baseUrl ) => ({
3363
3457
  getMyMeetings: () =>
3364
3458
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
3365
3459
 
3366
- createMyMeeting: (name , persistent ) =>
3367
- 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
+ ),
3368
3472
 
3369
3473
  deleteMyMeeting: (meetingUuid ) =>
3370
3474
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -3372,8 +3476,36 @@ var confdMethods = (client , baseUrl ) => ({
3372
3476
  getMeeting: (meetingUuid ) =>
3373
3477
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
3374
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
+
3375
3498
  guestGetMeeting: (meetingUuid ) =>
3376
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
+
3377
3509
  });
3378
3510
 
3379
3511
  //
@@ -4812,6 +4944,14 @@ var calldMethods = (client , baseUrl ) => ({
4812
4944
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
4813
4945
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
4814
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
+
4815
4955
  listTrunks: () => client.get(`${baseUrl}/trunks`),
4816
4956
 
4817
4957
  mute: (callId ) =>
@@ -6455,7 +6595,7 @@ class WebRTCClient extends Emitter {
6455
6595
  });
6456
6596
  }
6457
6597
 
6458
- changeAudioInputDevice(id , session , force ) {
6598
+ async changeAudioInputDevice(id , session , force ) {
6459
6599
  const currentId = this.getAudioDeviceId();
6460
6600
  logger.info('setting audio input device', { id, currentId, session: !!session });
6461
6601
 
@@ -6463,33 +6603,50 @@ class WebRTCClient extends Emitter {
6463
6603
  return null;
6464
6604
  }
6465
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
+
6466
6624
  // let's update the local audio value
6467
6625
  if (this.audio) {
6468
6626
  this.audio = {
6469
6627
  deviceId: {
6470
- exact: id,
6628
+ exact: deviceId,
6471
6629
  },
6472
6630
  };
6473
6631
  }
6474
6632
 
6475
- if (session) {
6633
+ if (session && navigator.mediaDevices) {
6476
6634
  const sdh = session.sessionDescriptionHandler;
6477
6635
  const pc = sdh.peerConnection;
6478
6636
 
6479
- // $FlowFixMe
6480
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
6481
- const audioTrack = stream.getAudioTracks()[0];
6482
- 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);
6483
6641
 
6484
- if (sender) {
6485
- if (sender.track) {
6486
- audioTrack.enabled = sender.track.enabled;
6487
- }
6488
- sender.replaceTrack(audioTrack);
6642
+ if (sender) {
6643
+ if (sender.track) {
6644
+ audioTrack.enabled = sender.track.enabled;
6489
6645
  }
6646
+ sender.replaceTrack(audioTrack);
6647
+ }
6490
6648
 
6491
- return stream;
6492
- });
6649
+ return stream;
6493
6650
  }
6494
6651
  }
6495
6652
 
@@ -6509,14 +6666,14 @@ class WebRTCClient extends Emitter {
6509
6666
  return null;
6510
6667
  }
6511
6668
 
6512
- // let's update the local video value
6513
- if (this.video) {
6514
- this.video = {
6515
- deviceId: {
6516
- exact: id,
6517
- },
6518
- };
6519
- }
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
+ };
6520
6677
  }
6521
6678
 
6522
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.7",
3
+ "version": "0.38.8",
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
  }
@@ -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
+ }