@webex/plugin-meetings 2.9.0 → 2.11.1

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.
@@ -1 +1 @@
1
- {"version":3,"names":["BEHAVIORAL_METRICS","MEETINGS_REGISTRATION_FAILED","MEETINGS_REGISTRATION_SUCCESS","MERCURY_CONNECTION_FAILURE","MERCURY_CONNECTION_RESTORED","JOIN_SUCCESS","JOIN_FAILURE","ADD_MEDIA_SUCCESS","ADD_MEDIA_FAILURE","CONNECTION_SUCCESS","CONNECTION_FAILURE","MEETING_LEAVE_FAILURE","MEETING_END_ALL_FAILURE","MEETING_END_ALL_INITIATED","GET_USER_MEDIA_FAILURE","GET_DISPLAY_MEDIA_FAILURE","JOIN_WITH_MEDIA_FAILURE","DISCONNECT_DUE_TO_INACTIVITY","MEETING_MEDIA_INACTIVE","MEETING_RECONNECT_FAILURE","MEETING_MAX_REJOIN_FAILURE","MEETING_SHARE_FAILURE","MEETING_START_WHITEBOARD_SHARE_FAILURE","MEETING_STOP_WHITEBOARD_SHARE_FAILURE","MUTE_AUDIO_FAILURE","MUTE_VIDEO_FAILURE","SET_MEETING_QUALITY_FAILURE","STOP_FLOOR_REQUEST_FAILURE","ADD_DIAL_IN_FAILURE","ADD_DIAL_OUT_FAILURE","UPDATE_MEDIA_FAILURE","UNMUTE_AUDIO_FAILURE","UNMUTE_VIDEO_FAILURE","ROAP_ANSWER_FAILURE","ROAP_GLARE_CONDITION","PEERCONNECTION_FAILURE","INVALID_ICE_CANDIDATE","UPLOAD_LOGS_FAILURE","RECEIVE_TRANSCRIPTION_FAILURE","ENABLE_BNR_SUCCESS","ENABLE_BNR_FAILURE","DISABLE_BNR_SUCCESS","DISABLE_BNR_FAILURE"],"sources":["constants.js"],"sourcesContent":["\n// Metrics constants ----------------------------------------------------------\n\nconst BEHAVIORAL_METRICS = {\n MEETINGS_REGISTRATION_FAILED: 'js_sdk_meetings_registration_failed',\n MEETINGS_REGISTRATION_SUCCESS: 'js_sdk_meetings_registration_success',\n MERCURY_CONNECTION_FAILURE: 'js_sdk_mercury_connection_failure',\n MERCURY_CONNECTION_RESTORED: 'js_sdk_mercury_connection_restored',\n JOIN_SUCCESS: 'js_sdk_join_success',\n JOIN_FAILURE: 'js_sdk_join_failures',\n ADD_MEDIA_SUCCESS: 'js_sdk_add_media_success',\n ADD_MEDIA_FAILURE: 'js_sdk_add_media_failures',\n CONNECTION_SUCCESS: 'js_sdk_connection_success',\n CONNECTION_FAILURE: 'js_sdk_connection_failures',\n MEETING_LEAVE_FAILURE: 'js_sdk_meeting_leave_failure',\n MEETING_END_ALL_FAILURE: 'js_sdk_meeting_end_for_all_failure',\n MEETING_END_ALL_INITIATED: 'js_sdk_meeting_end_for_all_initiated',\n GET_USER_MEDIA_FAILURE: 'js_sdk_get_user_media_failures',\n GET_DISPLAY_MEDIA_FAILURE: 'js_sdk_get_display_media_failures',\n JOIN_WITH_MEDIA_FAILURE: 'js_sdk_join_with_media_failures',\n\n DISCONNECT_DUE_TO_INACTIVITY: 'js_sdk_disconnect_due_to_inactivity',\n MEETING_MEDIA_INACTIVE: 'js_sdk_meeting_media_inactive',\n MEETING_RECONNECT_FAILURE: 'js_sdk_meeting_reconnect_failures',\n MEETING_MAX_REJOIN_FAILURE: 'js_sdk_meeting_max_rejoin_failure',\n MEETING_SHARE_FAILURE: 'js_sdk_meeting_share_failures',\n MEETING_START_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_start_whiteboard_share_failures',\n MEETING_STOP_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_stop_whiteboard_share_failures',\n MUTE_AUDIO_FAILURE: 'js_sdk_mute_audio_failures',\n MUTE_VIDEO_FAILURE: 'js_sdk_mute_video_failures',\n SET_MEETING_QUALITY_FAILURE: 'js_sdk_set_meeting_quality_failures',\n STOP_FLOOR_REQUEST_FAILURE: 'js_sdk_stop_floor_request_failures',\n ADD_DIAL_IN_FAILURE: 'js_sdk_add_dial_in_failure',\n ADD_DIAL_OUT_FAILURE: 'js_sdk_add_dial_out_failure',\n UPDATE_MEDIA_FAILURE: 'js_sdk_update_media_failures',\n UNMUTE_AUDIO_FAILURE: 'js_sdk_unmute_audio_failures',\n UNMUTE_VIDEO_FAILURE: 'js_sdk_unmute_video_failures',\n ROAP_ANSWER_FAILURE: 'js_sdk_roap_answer_failures',\n ROAP_GLARE_CONDITION: 'js_sdk_roap_glar_condition',\n PEERCONNECTION_FAILURE: 'js_sdk_peerConnection_failures',\n INVALID_ICE_CANDIDATE: 'js_sdk_invalid_ice_candidate',\n UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',\n RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',\n ENABLE_BNR_SUCCESS: 'js_sdk_enable_bnr_success',\n ENABLE_BNR_FAILURE: 'js_sdk_enable_bnr_failure',\n DISABLE_BNR_SUCCESS: 'js_sdk_disable_bnr_success',\n DISABLE_BNR_FAILURE: 'js_sdk_disable_bnr_failure'\n};\n\n\nexport {BEHAVIORAL_METRICS as default};\n"],"mappings":";;;;;;;;;AACA;AAEA,IAAMA,kBAAkB,GAAG;EACzBC,4BAA4B,EAAE,qCADL;EAEzBC,6BAA6B,EAAE,sCAFN;EAGzBC,0BAA0B,EAAE,mCAHH;EAIzBC,2BAA2B,EAAE,oCAJJ;EAKzBC,YAAY,EAAE,qBALW;EAMzBC,YAAY,EAAE,sBANW;EAOzBC,iBAAiB,EAAE,0BAPM;EAQzBC,iBAAiB,EAAE,2BARM;EASzBC,kBAAkB,EAAE,2BATK;EAUzBC,kBAAkB,EAAE,4BAVK;EAWzBC,qBAAqB,EAAE,8BAXE;EAYzBC,uBAAuB,EAAE,oCAZA;EAazBC,yBAAyB,EAAE,sCAbF;EAczBC,sBAAsB,EAAE,gCAdC;EAezBC,yBAAyB,EAAE,mCAfF;EAgBzBC,uBAAuB,EAAE,iCAhBA;EAkBzBC,4BAA4B,EAAE,qCAlBL;EAmBzBC,sBAAsB,EAAE,+BAnBC;EAoBzBC,yBAAyB,EAAE,mCApBF;EAqBzBC,0BAA0B,EAAE,mCArBH;EAsBzBC,qBAAqB,EAAE,+BAtBE;EAuBzBC,sCAAsC,EAAE,gDAvBf;EAwBzBC,qCAAqC,EAAE,+CAxBd;EAyBzBC,kBAAkB,EAAE,4BAzBK;EA0BzBC,kBAAkB,EAAE,4BA1BK;EA2BzBC,2BAA2B,EAAE,qCA3BJ;EA4BzBC,0BAA0B,EAAE,oCA5BH;EA6BzBC,mBAAmB,EAAE,4BA7BI;EA8BzBC,oBAAoB,EAAE,6BA9BG;EA+BzBC,oBAAoB,EAAE,8BA/BG;EAgCzBC,oBAAoB,EAAE,8BAhCG;EAiCzBC,oBAAoB,EAAE,8BAjCG;EAkCzBC,mBAAmB,EAAE,6BAlCI;EAmCzBC,oBAAoB,EAAE,4BAnCG;EAoCzBC,sBAAsB,EAAE,gCApCC;EAqCzBC,qBAAqB,EAAE,8BArCE;EAsCzBC,mBAAmB,EAAE,4BAtCI;EAuCzBC,6BAA6B,EAAE,sCAvCN;EAwCzBC,kBAAkB,EAAE,2BAxCK;EAyCzBC,kBAAkB,EAAE,2BAzCK;EA0CzBC,mBAAmB,EAAE,4BA1CI;EA2CzBC,mBAAmB,EAAE;AA3CI,CAA3B"}
1
+ {"version":3,"names":["BEHAVIORAL_METRICS","MEETINGS_REGISTRATION_FAILED","MEETINGS_REGISTRATION_SUCCESS","MERCURY_CONNECTION_FAILURE","MERCURY_CONNECTION_RESTORED","JOIN_SUCCESS","JOIN_FAILURE","ADD_MEDIA_SUCCESS","ADD_MEDIA_FAILURE","CONNECTION_SUCCESS","CONNECTION_FAILURE","MEETING_LEAVE_FAILURE","MEETING_END_ALL_FAILURE","MEETING_END_ALL_INITIATED","GET_USER_MEDIA_FAILURE","GET_DISPLAY_MEDIA_FAILURE","JOIN_WITH_MEDIA_FAILURE","DISCONNECT_DUE_TO_INACTIVITY","MEETING_MEDIA_INACTIVE","MEETING_RECONNECT_FAILURE","MEETING_MAX_REJOIN_FAILURE","MEETING_SHARE_FAILURE","MEETING_START_WHITEBOARD_SHARE_FAILURE","MEETING_STOP_WHITEBOARD_SHARE_FAILURE","MUTE_AUDIO_FAILURE","MUTE_VIDEO_FAILURE","SET_MEETING_QUALITY_FAILURE","STOP_FLOOR_REQUEST_FAILURE","ADD_DIAL_IN_FAILURE","ADD_DIAL_OUT_FAILURE","UPDATE_MEDIA_FAILURE","UNMUTE_AUDIO_FAILURE","UNMUTE_VIDEO_FAILURE","ROAP_ANSWER_FAILURE","ROAP_GLARE_CONDITION","PEERCONNECTION_FAILURE","INVALID_ICE_CANDIDATE","UPLOAD_LOGS_FAILURE","RECEIVE_TRANSCRIPTION_FAILURE","ENABLE_BNR_SUCCESS","ENABLE_BNR_FAILURE","DISABLE_BNR_SUCCESS","DISABLE_BNR_FAILURE","FETCH_MEETING_INFO_V1_SUCCESS","FETCH_MEETING_INFO_V1_FAILURE","ADHOC_MEETING_SUCCESS","ADHOC_MEETING_FAILURE","VERIFY_PASSWORD_SUCCESS","VERIFY_PASSWORD_ERROR","VERIFY_CAPTCHA_ERROR"],"sources":["constants.js"],"sourcesContent":["\n// Metrics constants ----------------------------------------------------------\n\nconst BEHAVIORAL_METRICS = {\n MEETINGS_REGISTRATION_FAILED: 'js_sdk_meetings_registration_failed',\n MEETINGS_REGISTRATION_SUCCESS: 'js_sdk_meetings_registration_success',\n MERCURY_CONNECTION_FAILURE: 'js_sdk_mercury_connection_failure',\n MERCURY_CONNECTION_RESTORED: 'js_sdk_mercury_connection_restored',\n JOIN_SUCCESS: 'js_sdk_join_success',\n JOIN_FAILURE: 'js_sdk_join_failures',\n ADD_MEDIA_SUCCESS: 'js_sdk_add_media_success',\n ADD_MEDIA_FAILURE: 'js_sdk_add_media_failures',\n CONNECTION_SUCCESS: 'js_sdk_connection_success',\n CONNECTION_FAILURE: 'js_sdk_connection_failures',\n MEETING_LEAVE_FAILURE: 'js_sdk_meeting_leave_failure',\n MEETING_END_ALL_FAILURE: 'js_sdk_meeting_end_for_all_failure',\n MEETING_END_ALL_INITIATED: 'js_sdk_meeting_end_for_all_initiated',\n GET_USER_MEDIA_FAILURE: 'js_sdk_get_user_media_failures',\n GET_DISPLAY_MEDIA_FAILURE: 'js_sdk_get_display_media_failures',\n JOIN_WITH_MEDIA_FAILURE: 'js_sdk_join_with_media_failures',\n\n DISCONNECT_DUE_TO_INACTIVITY: 'js_sdk_disconnect_due_to_inactivity',\n MEETING_MEDIA_INACTIVE: 'js_sdk_meeting_media_inactive',\n MEETING_RECONNECT_FAILURE: 'js_sdk_meeting_reconnect_failures',\n MEETING_MAX_REJOIN_FAILURE: 'js_sdk_meeting_max_rejoin_failure',\n MEETING_SHARE_FAILURE: 'js_sdk_meeting_share_failures',\n MEETING_START_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_start_whiteboard_share_failures',\n MEETING_STOP_WHITEBOARD_SHARE_FAILURE: 'js_sdk_meeting_stop_whiteboard_share_failures',\n MUTE_AUDIO_FAILURE: 'js_sdk_mute_audio_failures',\n MUTE_VIDEO_FAILURE: 'js_sdk_mute_video_failures',\n SET_MEETING_QUALITY_FAILURE: 'js_sdk_set_meeting_quality_failures',\n STOP_FLOOR_REQUEST_FAILURE: 'js_sdk_stop_floor_request_failures',\n ADD_DIAL_IN_FAILURE: 'js_sdk_add_dial_in_failure',\n ADD_DIAL_OUT_FAILURE: 'js_sdk_add_dial_out_failure',\n UPDATE_MEDIA_FAILURE: 'js_sdk_update_media_failures',\n UNMUTE_AUDIO_FAILURE: 'js_sdk_unmute_audio_failures',\n UNMUTE_VIDEO_FAILURE: 'js_sdk_unmute_video_failures',\n ROAP_ANSWER_FAILURE: 'js_sdk_roap_answer_failures',\n ROAP_GLARE_CONDITION: 'js_sdk_roap_glar_condition',\n PEERCONNECTION_FAILURE: 'js_sdk_peerConnection_failures',\n INVALID_ICE_CANDIDATE: 'js_sdk_invalid_ice_candidate',\n UPLOAD_LOGS_FAILURE: 'js_sdk_upload_logs_failure',\n RECEIVE_TRANSCRIPTION_FAILURE: 'js_sdk_receive_transcription_failure',\n ENABLE_BNR_SUCCESS: 'js_sdk_enable_bnr_success',\n ENABLE_BNR_FAILURE: 'js_sdk_enable_bnr_failure',\n DISABLE_BNR_SUCCESS: 'js_sdk_disable_bnr_success',\n DISABLE_BNR_FAILURE: 'js_sdk_disable_bnr_failure',\n FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',\n FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',\n ADHOC_MEETING_SUCCESS: 'js_sdk_adhoc_meeting_success',\n ADHOC_MEETING_FAILURE: 'js_sdk_adhoc_meeting_failure',\n VERIFY_PASSWORD_SUCCESS: 'js_sdk_verify_password_success',\n VERIFY_PASSWORD_ERROR: 'js_sdk_verify_password_error',\n VERIFY_CAPTCHA_ERROR: 'js_sdk_verify_captcha_error'\n};\n\n\nexport {BEHAVIORAL_METRICS as default};\n"],"mappings":";;;;;;;;;AACA;AAEA,IAAMA,kBAAkB,GAAG;EACzBC,4BAA4B,EAAE,qCADL;EAEzBC,6BAA6B,EAAE,sCAFN;EAGzBC,0BAA0B,EAAE,mCAHH;EAIzBC,2BAA2B,EAAE,oCAJJ;EAKzBC,YAAY,EAAE,qBALW;EAMzBC,YAAY,EAAE,sBANW;EAOzBC,iBAAiB,EAAE,0BAPM;EAQzBC,iBAAiB,EAAE,2BARM;EASzBC,kBAAkB,EAAE,2BATK;EAUzBC,kBAAkB,EAAE,4BAVK;EAWzBC,qBAAqB,EAAE,8BAXE;EAYzBC,uBAAuB,EAAE,oCAZA;EAazBC,yBAAyB,EAAE,sCAbF;EAczBC,sBAAsB,EAAE,gCAdC;EAezBC,yBAAyB,EAAE,mCAfF;EAgBzBC,uBAAuB,EAAE,iCAhBA;EAkBzBC,4BAA4B,EAAE,qCAlBL;EAmBzBC,sBAAsB,EAAE,+BAnBC;EAoBzBC,yBAAyB,EAAE,mCApBF;EAqBzBC,0BAA0B,EAAE,mCArBH;EAsBzBC,qBAAqB,EAAE,+BAtBE;EAuBzBC,sCAAsC,EAAE,gDAvBf;EAwBzBC,qCAAqC,EAAE,+CAxBd;EAyBzBC,kBAAkB,EAAE,4BAzBK;EA0BzBC,kBAAkB,EAAE,4BA1BK;EA2BzBC,2BAA2B,EAAE,qCA3BJ;EA4BzBC,0BAA0B,EAAE,oCA5BH;EA6BzBC,mBAAmB,EAAE,4BA7BI;EA8BzBC,oBAAoB,EAAE,6BA9BG;EA+BzBC,oBAAoB,EAAE,8BA/BG;EAgCzBC,oBAAoB,EAAE,8BAhCG;EAiCzBC,oBAAoB,EAAE,8BAjCG;EAkCzBC,mBAAmB,EAAE,6BAlCI;EAmCzBC,oBAAoB,EAAE,4BAnCG;EAoCzBC,sBAAsB,EAAE,gCApCC;EAqCzBC,qBAAqB,EAAE,8BArCE;EAsCzBC,mBAAmB,EAAE,4BAtCI;EAuCzBC,6BAA6B,EAAE,sCAvCN;EAwCzBC,kBAAkB,EAAE,2BAxCK;EAyCzBC,kBAAkB,EAAE,2BAzCK;EA0CzBC,mBAAmB,EAAE,4BA1CI;EA2CzBC,mBAAmB,EAAE,4BA3CI;EA4CzBC,6BAA6B,EAAE,sCA5CN;EA6CzBC,6BAA6B,EAAE,sCA7CN;EA8CzBC,qBAAqB,EAAE,8BA9CE;EA+CzBC,qBAAqB,EAAE,8BA/CE;EAgDzBC,uBAAuB,EAAE,gCAhDA;EAiDzBC,qBAAqB,EAAE,8BAjDE;EAkDzBC,oBAAoB,EAAE;AAlDG,CAA3B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-meetings",
3
- "version": "2.9.0",
3
+ "version": "2.11.1",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "contributors": [
@@ -24,19 +24,19 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@babel/runtime-corejs2": "^7.14.8",
27
- "@webex/webex-core": "2.9.0",
28
- "@webex/internal-plugin-mercury": "2.9.0",
29
- "@webex/internal-plugin-conversation": "2.9.0",
27
+ "@webex/webex-core": "2.11.1",
28
+ "@webex/internal-plugin-mercury": "2.11.1",
29
+ "@webex/internal-plugin-conversation": "2.11.1",
30
30
  "webrtc-adapter": "^7.7.0",
31
31
  "lodash": "^4.17.21",
32
32
  "uuid": "^3.3.2",
33
33
  "global": "^4.4.0",
34
34
  "ip-anonymize": "^0.1.0",
35
- "@webex/common": "2.9.0",
35
+ "@webex/common": "2.11.1",
36
36
  "bowser": "^2.11.0",
37
37
  "sdp-transform": "^2.12.0",
38
38
  "readable-stream": "^3.6.0",
39
- "@webex/common-timers": "2.9.0",
39
+ "@webex/common-timers": "2.11.1",
40
40
  "btoa": "^1.2.1",
41
41
  "@webex/internal-media-core": "^0.0.4-beta",
42
42
  "javascript-state-machine": "^3.1.0",
@@ -1023,7 +1023,13 @@ export default class Meeting extends StatelessWebexPlugin {
1023
1023
  return this.fetchMeetingInfo({
1024
1024
  password, captchaCode
1025
1025
  })
1026
- .then(() => ({isPasswordValid: true, requiredCaptcha: null, failureReason: MEETING_INFO_FAILURE_REASON.NONE}))
1026
+ .then(() => {
1027
+ Metrics.sendBehavioralMetric(
1028
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS
1029
+ );
1030
+
1031
+ return {isPasswordValid: true, requiredCaptcha: null, failureReason: MEETING_INFO_FAILURE_REASON.NONE};
1032
+ })
1027
1033
  .catch((error) => {
1028
1034
  if (error instanceof PasswordError || error instanceof CaptchaError) {
1029
1035
  return {
@@ -1,5 +1,7 @@
1
1
 
2
2
  import {HTTP_VERBS, _CONVERSATION_URL_} from '../constants';
3
+ import Metrics from '../metrics';
4
+ import BEHAVIORAL_METRICS from '../metrics/constants';
3
5
 
4
6
  import MeetingInfoUtil from './utilv2';
5
7
 
@@ -141,6 +143,10 @@ export default class MeetingInfoV2 {
141
143
  const uri = this.webex.meetings.preferredWebexSite ?
142
144
  `https://${this.webex.meetings.preferredWebexSite}/wbxappapi/v2/meetings/spaceInstant` : '';
143
145
 
146
+ Metrics.sendBehavioralMetric(
147
+ BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS
148
+ );
149
+
144
150
  return this.webex.request({
145
151
  method: HTTP_VERBS.POST,
146
152
  uri,
@@ -149,6 +155,16 @@ export default class MeetingInfoV2 {
149
155
  .catch((err) => {
150
156
  throw new MeetingInfoV2AdhocMeetingError(err.body?.code, err.body?.message);
151
157
  });
158
+ })
159
+ .catch((err) => {
160
+ Metrics.sendBehavioralMetric(
161
+ BEHAVIORAL_METRICS.ADHOC_MEETING_FAILURE,
162
+ {
163
+ reason: err.message,
164
+ stack: err.stack
165
+ }
166
+ );
167
+ throw new MeetingInfoV2AdhocMeetingError(err.body?.code, err.body?.message);
152
168
  });
153
169
  }
154
170
 
@@ -189,11 +205,32 @@ export default class MeetingInfoV2 {
189
205
  if (directURI) options.directURI = directURI;
190
206
 
191
207
  return this.webex.request(options)
208
+ .then(() => {
209
+ Metrics.sendBehavioralMetric(
210
+ BEHAVIORAL_METRICS.FETCH_MEETING_INFO_V1_SUCCESS
211
+ );
212
+ })
192
213
  .catch((err) => {
193
214
  if (err?.statusCode === 403) {
215
+ Metrics.sendBehavioralMetric(
216
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR,
217
+ {
218
+ reason: err.message,
219
+ stack: err.stack
220
+ }
221
+ );
222
+
194
223
  throw new MeetingInfoV2PasswordError(err.body?.code, err.body?.data?.meetingInfo);
195
224
  }
196
225
  if (err?.statusCode === 423) {
226
+ Metrics.sendBehavioralMetric(
227
+ BEHAVIORAL_METRICS.VERIFY_CAPTCHA_ERROR,
228
+ {
229
+ reason: err.message,
230
+ stack: err.stack
231
+ }
232
+ );
233
+
197
234
  throw new MeetingInfoV2CaptchaError(err.body?.code, {
198
235
  captchaId: err.body.captchaID,
199
236
  verificationImageURL: err.body.verificationImageURL,
@@ -201,6 +238,14 @@ export default class MeetingInfoV2 {
201
238
  refreshURL: err.body.refreshURL
202
239
  });
203
240
  }
241
+
242
+ Metrics.sendBehavioralMetric(
243
+ BEHAVIORAL_METRICS.FETCH_MEETING_INFO_V1_FAILURE,
244
+ {
245
+ reason: err.message,
246
+ stack: err.stack
247
+ }
248
+ );
204
249
  throw err;
205
250
  });
206
251
  }
@@ -71,6 +71,13 @@ export default class Member {
71
71
  * @public
72
72
  * @memberof Member
73
73
  */
74
+ this.isHandRaised = null;
75
+ /**
76
+ * @instance
77
+ * @type {Boolean}
78
+ * @public
79
+ * @memberof Member
80
+ */
74
81
  this.isSelf = null;
75
82
  /**
76
83
  * @instance
@@ -206,6 +213,7 @@ export default class Member {
206
213
  this.name = MemberUtil.extractName(participant);
207
214
  this.isAudioMuted = MemberUtil.isAudioMuted(participant);
208
215
  this.isVideoMuted = MemberUtil.isVideoMuted(participant);
216
+ this.isHandRaised = MemberUtil.isHandRaised(participant);
209
217
  this.isGuest = MemberUtil.isGuest(participant);
210
218
  this.isUser = MemberUtil.isUser(participant);
211
219
  this.isDevice = MemberUtil.isDevice(participant);
@@ -107,6 +107,18 @@ MemberUtil.isVideoMuted = (participant) => {
107
107
  return MemberUtil.isMuted(participant.status, VIDEO_STATUS);
108
108
  };
109
109
 
110
+ /**
111
+ * @param {Object} participant the locus participant
112
+ * @returns {Boolean}
113
+ */
114
+ MemberUtil.isHandRaised = (participant) => {
115
+ if (!participant) {
116
+ throw new ParameterError('Raise hand could not be processed, participant is undefined.');
117
+ }
118
+
119
+ return participant.controls?.hand?.raised || false;
120
+ };
121
+
110
122
  /**
111
123
  * utility method for audio/video muted status
112
124
  * @param {String} status
@@ -756,7 +756,7 @@ export default class Members extends StatelessWebexPlugin {
756
756
  }
757
757
  const options = MembersUtil.generateRaiseHandMemberOptions(memberId, raise, this.locusUrl);
758
758
 
759
- return this.membersRequest.raiseLowerHandMember(options);
759
+ return this.membersRequest.raiseOrLowerHandMember(options);
760
760
  }
761
761
 
762
762
  /**
@@ -44,7 +44,14 @@ const BEHAVIORAL_METRICS = {
44
44
  ENABLE_BNR_SUCCESS: 'js_sdk_enable_bnr_success',
45
45
  ENABLE_BNR_FAILURE: 'js_sdk_enable_bnr_failure',
46
46
  DISABLE_BNR_SUCCESS: 'js_sdk_disable_bnr_success',
47
- DISABLE_BNR_FAILURE: 'js_sdk_disable_bnr_failure'
47
+ DISABLE_BNR_FAILURE: 'js_sdk_disable_bnr_failure',
48
+ FETCH_MEETING_INFO_V1_SUCCESS: 'js_sdk_fetch_meeting_info_v1_success',
49
+ FETCH_MEETING_INFO_V1_FAILURE: 'js_sdk_fetch_meeting_info_v1_failure',
50
+ ADHOC_MEETING_SUCCESS: 'js_sdk_adhoc_meeting_success',
51
+ ADHOC_MEETING_FAILURE: 'js_sdk_adhoc_meeting_failure',
52
+ VERIFY_PASSWORD_SUCCESS: 'js_sdk_verify_password_success',
53
+ VERIFY_PASSWORD_ERROR: 'js_sdk_verify_password_error',
54
+ VERIFY_CAPTCHA_ERROR: 'js_sdk_verify_captcha_error'
48
55
  };
49
56
 
50
57
 
@@ -2366,6 +2366,11 @@ describe('plugin-meetings', () => {
2366
2366
  assert.equal(meeting.requiredCaptcha, null);
2367
2367
  assert.calledTwice(TriggerProxy.trigger);
2368
2368
  assert.calledWith(TriggerProxy.trigger, meeting, {file: 'meetings', function: 'fetchMeetingInfo'}, 'meeting:meetingInfoAvailable');
2369
+ assert(Metrics.sendBehavioralMetric.calledOnce);
2370
+ assert.calledWith(
2371
+ Metrics.sendBehavioralMetric,
2372
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_SUCCESS,
2373
+ );
2369
2374
  });
2370
2375
 
2371
2376
  it('calls meetingInfoProvider with all the right parameters and parses the result when random delay is applied', async () => {
@@ -2437,6 +2442,11 @@ describe('plugin-meetings', () => {
2437
2442
 
2438
2443
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, null, null);
2439
2444
 
2445
+ assert(Metrics.sendBehavioralMetric.calledOnce);
2446
+ assert.calledWith(
2447
+ Metrics.sendBehavioralMetric,
2448
+ BEHAVIORAL_METRICS.VERIFY_PASSWORD_ERROR,
2449
+ );
2440
2450
  assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO);
2441
2451
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
2442
2452
  assert.equal(meeting.requiredCaptcha, null);
@@ -2457,6 +2467,11 @@ describe('plugin-meetings', () => {
2457
2467
 
2458
2468
  assert.calledWith(meeting.attrs.meetingInfoProvider.fetchMeetingInfo, FAKE_DESTINATION, FAKE_TYPE, 'aaa', null);
2459
2469
 
2470
+ assert(Metrics.sendBehavioralMetric.calledOnce);
2471
+ assert.calledWith(
2472
+ Metrics.sendBehavioralMetric,
2473
+ BEHAVIORAL_METRICS.VERIFY_CAPTCHA_ERROR,
2474
+ );
2460
2475
  assert.deepEqual(meeting.meetingInfo, {});
2461
2476
  assert.equal(meeting.meetingInfoFailureReason, MEETING_INFO_FAILURE_REASON.WRONG_PASSWORD);
2462
2477
  assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED);
@@ -16,6 +16,8 @@ import {
16
16
  } from '@webex/plugin-meetings/src/constants';
17
17
  import MeetingInfo, {MeetingInfoV2PasswordError, MeetingInfoV2CaptchaError, MeetingInfoV2AdhocMeetingError} from '@webex/plugin-meetings/src/meeting-info/meeting-info-v2';
18
18
  import MeetingInfoUtil from '@webex/plugin-meetings/src/meeting-info/utilv2';
19
+ import Metrics from '@webex/plugin-meetings/src/metrics';
20
+ import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
19
21
 
20
22
  describe('plugin-meetings', () => {
21
23
  const conversation = {
@@ -42,6 +44,13 @@ describe('plugin-meetings', () => {
42
44
  let webex;
43
45
  let meetingInfo = null;
44
46
 
47
+ beforeEach(() => {
48
+ sinon.stub(Metrics, 'sendBehavioralMetric');
49
+ });
50
+ afterEach(() => {
51
+ sinon.restore();
52
+ });
53
+
45
54
  describe('Meeting Info V2', () => {
46
55
  beforeEach(() => {
47
56
  webex = new MockWebex({
@@ -125,6 +134,11 @@ describe('plugin-meetings', () => {
125
134
  captchaVerifyCode: 'aabbcc11'
126
135
  }
127
136
  });
137
+ assert(Metrics.sendBehavioralMetric.calledOnce);
138
+ assert.calledWith(
139
+ Metrics.sendBehavioralMetric,
140
+ BEHAVIORAL_METRICS.FETCH_MEETING_INFO_V1_SUCCESS,
141
+ );
128
142
  });
129
143
 
130
144
  it('create adhoc meeting when conversationUrl passed with enableAdhocMeetings toggle', async () => {
@@ -254,6 +268,11 @@ describe('plugin-meetings', () => {
254
268
  invitees: invitee
255
269
  }
256
270
  });
271
+ assert(Metrics.sendBehavioralMetric.calledOnce);
272
+ assert.calledWith(
273
+ Metrics.sendBehavioralMetric,
274
+ BEHAVIORAL_METRICS.ADHOC_MEETING_SUCCESS,
275
+ );
257
276
  });
258
277
  });
259
278
  });
@@ -0,0 +1,23 @@
1
+ import sinon from 'sinon';
2
+ import {assert} from '@webex/test-helper-chai';
3
+
4
+ import MemberUtil from '@webex/plugin-meetings/src/member/util';
5
+ import Member from '@webex/plugin-meetings/src/member';
6
+
7
+
8
+ describe('member', () => {
9
+ afterEach(() => {
10
+ sinon.restore();
11
+ });
12
+
13
+ it('checks that processParticipant calls isHandRaised', () => {
14
+ const participant = {controls: {}};
15
+
16
+ const member = new Member({});
17
+
18
+ sinon.spy(MemberUtil, 'isHandRaised');
19
+ member.processParticipant(participant);
20
+
21
+ assert.calledOnceWithExactly(MemberUtil.isHandRaised, participant);
22
+ });
23
+ });
@@ -0,0 +1,50 @@
1
+ import {assert} from '@webex/test-helper-chai';
2
+
3
+ import MemberUtil from '@webex/plugin-meetings/src/member/util';
4
+
5
+
6
+ describe('isHandRaised', () => {
7
+ it('throws error when there is no participant', () => {
8
+ assert.throws(() => {
9
+ MemberUtil.isHandRaised();
10
+ }, 'Raise hand could not be processed, participant is undefined.');
11
+ });
12
+
13
+ it('returns false when controls is not there', () => {
14
+ const participant = {};
15
+
16
+ assert.isFalse(MemberUtil.isHandRaised(participant));
17
+ });
18
+
19
+ it('returns false when hand is not there in controls', () => {
20
+ const participant = {
21
+ controls: {}
22
+ };
23
+
24
+ assert.isFalse(MemberUtil.isHandRaised(participant));
25
+ });
26
+
27
+ it('returns true when hand raised is true', () => {
28
+ const participant = {
29
+ controls: {
30
+ hand: {
31
+ raised: true
32
+ },
33
+ }
34
+ };
35
+
36
+ assert.isTrue(MemberUtil.isHandRaised(participant));
37
+ });
38
+
39
+ it('returns false when hand raised is false', () => {
40
+ const participant = {
41
+ controls: {
42
+ hand: {
43
+ raised: false
44
+ },
45
+ }
46
+ };
47
+
48
+ assert.isFalse(MemberUtil.isHandRaised(participant));
49
+ });
50
+ });
@@ -10,8 +10,9 @@ import chaiAsPromised from 'chai-as-promised';
10
10
  import {Credentials} from '@webex/webex-core';
11
11
  import Support from '@webex/internal-plugin-support';
12
12
  import MockWebex from '@webex/test-helper-mock-webex';
13
- import Meetings from '@webex/plugin-meetings';
14
13
 
14
+ import Meetings from '@webex/plugin-meetings';
15
+ import ParameterError from '@webex/plugin-meetings/src/common/errors/parameter';
15
16
  import Members from '@webex/plugin-meetings/src/members';
16
17
  import MembersUtil from '@webex/plugin-meetings/src/members/util';
17
18
 
@@ -191,25 +192,72 @@ describe('plugin-meetings', () => {
191
192
  });
192
193
  });
193
194
 
194
- describe('#raiseHand', () => {
195
- it('should fire spies correctly when raiseOrLowerHand is called with valid params', async () => {
196
- const members = createMembers({url: url1});
195
+ describe('#raiseOrLowerHand', () => {
196
+ const setup = (locusUrl) => {
197
+ const members = createMembers({url: locusUrl});
197
198
 
198
- const {membersRequest} = members;
199
+ const spies = {
200
+ generateRaiseHandMemberOptions: sandbox.spy(MembersUtil, 'generateRaiseHandMemberOptions'),
201
+ raiseOrLowerHandMember: sandbox.spy(members.membersRequest, 'raiseOrLowerHandMember'),
202
+ };
203
+
204
+ return {members, spies};
205
+ };
206
+
207
+ const checkInvalid = async (resultPromise, expectedMessage, spies) => {
208
+ await assert.isRejected(resultPromise, ParameterError, expectedMessage);
209
+ assert.notCalled(spies.generateRaiseHandMemberOptions);
210
+ assert.notCalled(spies.raiseOrLowerHandMember);
211
+ };
199
212
 
200
- const generateOptionsSpy = sandbox.spy(MembersUtil, 'generateRaiseHandMemberOptions');
201
- const raiseOrLowerHandMemberSpy = sandbox.spy(membersRequest, 'raiseOrLowerHandMember');
213
+ const checkValid = async (resultPromise, spies, expectedMemberId, expectedRaise, expectedLocusUrl) => {
214
+ await assert.isFulfilled(resultPromise);
215
+ assert.calledOnceWithExactly(spies.generateRaiseHandMemberOptions, expectedMemberId, expectedRaise, expectedLocusUrl);
216
+ assert.calledOnceWithExactly(spies.raiseOrLowerHandMember, {memberId: expectedMemberId, raised: expectedRaise, locusUrl: expectedLocusUrl});
217
+ assert.strictEqual(resultPromise, spies.raiseOrLowerHandMember.getCall(0).returnValue);
218
+ };
202
219
 
203
- await members.raiseOrLowerHand('test1', true);
220
+ it('should not make a request if there is no member id', async () => {
221
+ const {members, spies} = setup(url1);
204
222
 
205
- assert.calledOnce(generateOptionsSpy);
206
- assert.calledOnce(raiseOrLowerHandMemberSpy);
223
+ const resultPromise = members.raiseOrLowerHand();
224
+
225
+ await checkInvalid(resultPromise, 'The member id must be defined to raise/lower the hand of the member.', spies);
207
226
  });
208
227
 
209
- it('should throw a rejection if there is no locus url', async () => {
210
- const members = createMembers({url: false});
228
+ it('should not make a request if there is no locus url', async () => {
229
+ const {members, spies} = setup();
230
+
231
+ const resultPromise = members.raiseOrLowerHand(uuid.v4());
232
+
233
+ await checkInvalid(resultPromise, 'The associated locus url for this meetings members object must be defined.', spies);
234
+ });
235
+
236
+ it('should make the correct request when called with raise as true', async () => {
237
+ const memberId = uuid.v4();
238
+ const {members, spies} = setup(url1);
239
+
240
+ const resultPromise = members.raiseOrLowerHand(memberId, true);
241
+
242
+ await checkValid(resultPromise, spies, memberId, true, url1);
243
+ });
244
+
245
+ it('should make the correct request when called with raise as false', async () => {
246
+ const memberId = uuid.v4();
247
+ const {members, spies} = setup(url1);
248
+
249
+ const resultPromise = members.raiseOrLowerHand(memberId, false);
250
+
251
+ await checkValid(resultPromise, spies, memberId, false, url1);
252
+ });
253
+
254
+ it('should make the correct request when called with raise as default', async () => {
255
+ const memberId = uuid.v4();
256
+ const {members, spies} = setup(url1);
257
+
258
+ const resultPromise = members.raiseOrLowerHand(memberId);
211
259
 
212
- assert.isRejected(members.raiseOrLowerHand('test1', true));
260
+ await checkValid(resultPromise, spies, memberId, true, url1);
213
261
  });
214
262
  });
215
263
  });