From d9f0e1433f831e3a94636d76474b0b9c14d674cd Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Mon, 3 Mar 2025 10:35:18 +0800 Subject: [PATCH 1/7] feat(webinar): spark-623318 return correct info when can't join meeting since not reach JBH --- .../@webex/plugin-meetings/src/constants.ts | 2 ++ .../plugin-meetings/src/meeting/index.ts | 13 ++++++++ .../test/unit/spec/meeting/index.js | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/packages/@webex/plugin-meetings/src/constants.ts b/packages/@webex/plugin-meetings/src/constants.ts index d3223f8a56a..1f048830f9c 100644 --- a/packages/@webex/plugin-meetings/src/constants.ts +++ b/packages/@webex/plugin-meetings/src/constants.ts @@ -203,6 +203,7 @@ export const ICE_AND_DTLS_CONNECTION_TIMEOUT = 20000; export const ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT = 35000; export const WEBINAR_ERROR_WEBCAST = [403026]; export const WEBINAR_ERROR_REGISTRATIONID = [403037, 403137]; +export const JOIN_ERROR_REASN_FOR_END_USER = [403003]; // ******************** REGEX ********************** // Please alphabetize @@ -1333,6 +1334,7 @@ export const MEETING_INFO_FAILURE_REASON = { WEBINAR_REGISTRATION: 'WEBINAR_REGISTRATION', // webinar need registration NEED_JOIN_WITH_WEBCAST: 'NEED_JOIN_WITH_WEBCAST', // webinar need using webcast join WEBINAR_NEED_REGISTRATIONID: 'WEBINAR_NEED_REGISTRATIONID', // webinar need registrationID + NOT_REACH_JBH: 'NOT_REACH_JBH', // Meeting is not allow to access since not reach JBH time OTHER: 'OTHER', // any other error (network, etc) }; diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index ec04739d2b1..5f487d9996d 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -123,6 +123,7 @@ import { NAMED_MEDIA_GROUP_TYPE_AUDIO, WEBINAR_ERROR_WEBCAST, WEBINAR_ERROR_REGISTRATIONID, + JOIN_ERROR_REASN_FOR_END_USER, } from '../constants'; import BEHAVIORAL_METRICS from '../metrics/constants'; import ParameterError from '../common/errors/parameter'; @@ -162,6 +163,7 @@ import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHan import JoinWebinarError from '../common/errors/join-webinar-error'; import Member from '../member'; import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error'; +import JoinMeetingError from '../common/errors/join-meeting'; // default callback so we don't call an undefined function, but in practice it should never be used const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL'; @@ -1790,6 +1792,17 @@ export default class Meeting extends StatelessWebexPlugin { `Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - password required (code=${err?.body?.code}).` ); + if (JOIN_ERROR_REASN_FOR_END_USER.includes(err.wbxAppApiCode)) { + this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.JOIN_ERROR_REASN_FOR_END_USER; + this.meetingInfoFailureCode = err.wbxAppApiCode; + + if (err.meetingInfo) { + this.meetingInfo = err.meetingInfo; + } + + throw new JoinMeetingError(); + } + // when wbxappapi requires password it still populates partial meeting info in the response if (err.meetingInfo) { this.meetingInfo = err.meetingInfo; diff --git a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js index e02e8c6e979..1779c1f01f1 100644 --- a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js +++ b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js @@ -114,6 +114,7 @@ import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagno import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection'; import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea'; +import JoinMeetingError from '../../../../src/common/errors/join-meeting'; describe('plugin-meetings', () => { const logger = { @@ -6339,6 +6340,38 @@ describe('plugin-meetings', () => { assert.equal(meeting.passwordStatus, PASSWORD_STATUS.REQUIRED); }); + it('handles meetingInfoProvider not reach JBH', async () => { + meeting.destination = FAKE_DESTINATION; + meeting.destinationType = FAKE_TYPE; + meeting.attrs.meetingInfoProvider = { + fetchMeetingInfo: sinon + .stub() + .throws(new MeetingInfoV2PasswordError(403003, FAKE_MEETING_INFO)), + }; + + await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinMeetingError); + + assert.calledWith( + meeting.attrs.meetingInfoProvider.fetchMeetingInfo, + FAKE_DESTINATION, + FAKE_TYPE, + null, + null, + undefined, + 'locus-id', + {}, + {meetingId: meeting.id, sendCAevents: true} + ); + + assert.deepEqual(meeting.meetingInfo, FAKE_MEETING_INFO); + assert.equal(meeting.meetingInfoFailureCode, 403003); + assert.equal( + meeting.meetingInfoFailureReason, + MEETING_INFO_FAILURE_REASON.JOIN_ERROR_REASN_FOR_END_USER + ); + assert.equal(meeting.requiredCaptcha, null); + }); + it('handles meetingInfoProvider policy error', async () => { meeting.destination = FAKE_DESTINATION; meeting.destinationType = FAKE_TYPE; From fcbe4ae84dfca9b98f566341b8b7781507d1eabe Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Mon, 3 Mar 2025 11:08:36 +0800 Subject: [PATCH 2/7] feat(webinar): spark-623318 return correct info when can't join meeting since not reach JBH --- packages/@webex/plugin-meetings/src/meeting/index.ts | 2 +- .../@webex/plugin-meetings/test/unit/spec/meeting/index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index 5f487d9996d..45cdbc55dc0 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -1793,7 +1793,7 @@ export default class Meeting extends StatelessWebexPlugin { ); if (JOIN_ERROR_REASN_FOR_END_USER.includes(err.wbxAppApiCode)) { - this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.JOIN_ERROR_REASN_FOR_END_USER; + this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH; this.meetingInfoFailureCode = err.wbxAppApiCode; if (err.meetingInfo) { diff --git a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js index 1779c1f01f1..681b022c86d 100644 --- a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js +++ b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js @@ -116,7 +116,7 @@ import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection'; import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea'; import JoinMeetingError from '../../../../src/common/errors/join-meeting'; -describe('plugin-meetings', () => { +describe.only('plugin-meetings', () => { const logger = { info: () => {}, log: () => {}, @@ -6367,7 +6367,7 @@ describe('plugin-meetings', () => { assert.equal(meeting.meetingInfoFailureCode, 403003); assert.equal( meeting.meetingInfoFailureReason, - MEETING_INFO_FAILURE_REASON.JOIN_ERROR_REASN_FOR_END_USER + MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH ); assert.equal(meeting.requiredCaptcha, null); }); From ef0fad1deb8e97d1c29f0b4cb3ac45313570baca Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Mon, 3 Mar 2025 14:04:31 +0800 Subject: [PATCH 3/7] feat(webinar): spark-623318 return correct info when can't join meeting since not reach JBH --- packages/@webex/plugin-meetings/src/meeting/index.ts | 1 + packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index 45cdbc55dc0..2ac23811fe9 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -1792,6 +1792,7 @@ export default class Meeting extends StatelessWebexPlugin { `Meeting:index#fetchMeetingInfo --> Info Unable to fetch meeting info for ${this.destination} - password required (code=${err?.body?.code}).` ); + // Handle the case where user hasn't reached Join Before Host (JBH) time (error code 403003) if (JOIN_ERROR_REASN_FOR_END_USER.includes(err.wbxAppApiCode)) { this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH; this.meetingInfoFailureCode = err.wbxAppApiCode; diff --git a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js index 681b022c86d..5a56d007fba 100644 --- a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js +++ b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js @@ -116,7 +116,7 @@ import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection'; import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea'; import JoinMeetingError from '../../../../src/common/errors/join-meeting'; -describe.only('plugin-meetings', () => { +describe('plugin-meetings', () => { const logger = { info: () => {}, log: () => {}, From 5cb037a9026b8896208896690f30b92175d7d2d2 Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Tue, 4 Mar 2025 09:16:52 +0800 Subject: [PATCH 4/7] feat(webinar): correct spelling errors --- packages/@webex/plugin-meetings/src/constants.ts | 9 ++++++++- packages/@webex/plugin-meetings/src/meeting/index.ts | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/@webex/plugin-meetings/src/constants.ts b/packages/@webex/plugin-meetings/src/constants.ts index 1f048830f9c..f6482ad557e 100644 --- a/packages/@webex/plugin-meetings/src/constants.ts +++ b/packages/@webex/plugin-meetings/src/constants.ts @@ -203,7 +203,7 @@ export const ICE_AND_DTLS_CONNECTION_TIMEOUT = 20000; export const ROAP_OFFER_ANSWER_EXCHANGE_TIMEOUT = 35000; export const WEBINAR_ERROR_WEBCAST = [403026]; export const WEBINAR_ERROR_REGISTRATIONID = [403037, 403137]; -export const JOIN_ERROR_REASN_FOR_END_USER = [403003]; +export const JOIN_ERROR_REASON_FOR_END_USER = [403003]; // ******************** REGEX ********************** // Please alphabetize @@ -1326,6 +1326,13 @@ export const PASSWORD_STATUS = { VERIFIED: 'VERIFIED', // client has already provided the password and it has been verified, client can proceed to call join() }; +export const REGISTRATIONID_STATUS = { + NOT_REQUIRED: 'NOT_REQUIRED', // password is not required to join the meeting + REQUIRED: 'REQUIRED', // client needs to provide the password by calling verifyPassword() before calling join() + UNKNOWN: 'UNKNOWN', // we are waiting for information from the backend if password is required or not + VERIFIED: 'VERIFIED', // client has already provided the password and it has been verified, client can proceed to call join() +}; + export const MEETING_INFO_FAILURE_REASON = { NONE: 'NONE', // meeting info was retrieved succesfully WRONG_PASSWORD: 'WRONG_PASSWORD', // meeting requires password and no password or wrong one was provided diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index 2ac23811fe9..2e1f8082afe 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -123,7 +123,7 @@ import { NAMED_MEDIA_GROUP_TYPE_AUDIO, WEBINAR_ERROR_WEBCAST, WEBINAR_ERROR_REGISTRATIONID, - JOIN_ERROR_REASN_FOR_END_USER, + JOIN_ERROR_REASON_FOR_END_USER, } from '../constants'; import BEHAVIORAL_METRICS from '../metrics/constants'; import ParameterError from '../common/errors/parameter'; @@ -1793,7 +1793,7 @@ export default class Meeting extends StatelessWebexPlugin { ); // Handle the case where user hasn't reached Join Before Host (JBH) time (error code 403003) - if (JOIN_ERROR_REASN_FOR_END_USER.includes(err.wbxAppApiCode)) { + if (JOIN_ERROR_REASON_FOR_END_USER.includes(err.wbxAppApiCode)) { this.meetingInfoFailureReason = MEETING_INFO_FAILURE_REASON.NOT_REACH_JBH; this.meetingInfoFailureCode = err.wbxAppApiCode; From 84f19f44b6117ff36051c1e9fca91cbb48289f5c Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Tue, 4 Mar 2025 09:24:11 +0800 Subject: [PATCH 5/7] feat(webinar): remove unless code --- packages/@webex/plugin-meetings/src/constants.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/@webex/plugin-meetings/src/constants.ts b/packages/@webex/plugin-meetings/src/constants.ts index f6482ad557e..4ca1117ec3c 100644 --- a/packages/@webex/plugin-meetings/src/constants.ts +++ b/packages/@webex/plugin-meetings/src/constants.ts @@ -1326,13 +1326,6 @@ export const PASSWORD_STATUS = { VERIFIED: 'VERIFIED', // client has already provided the password and it has been verified, client can proceed to call join() }; -export const REGISTRATIONID_STATUS = { - NOT_REQUIRED: 'NOT_REQUIRED', // password is not required to join the meeting - REQUIRED: 'REQUIRED', // client needs to provide the password by calling verifyPassword() before calling join() - UNKNOWN: 'UNKNOWN', // we are waiting for information from the backend if password is required or not - VERIFIED: 'VERIFIED', // client has already provided the password and it has been verified, client can proceed to call join() -}; - export const MEETING_INFO_FAILURE_REASON = { NONE: 'NONE', // meeting info was retrieved succesfully WRONG_PASSWORD: 'WRONG_PASSWORD', // meeting requires password and no password or wrong one was provided From 1d50b0e80fd641368f77e362a421e7b937d4c5ee Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Tue, 4 Mar 2025 13:51:25 +0800 Subject: [PATCH 6/7] feat(webinar): spark-623318 return correct info when can't join meeting since not reach JBH --- packages/@webex/plugin-meetings/src/meeting/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index 0ae5044d941..94e4c835fd8 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -1801,7 +1801,7 @@ export default class Meeting extends StatelessWebexPlugin { this.meetingInfo = err.meetingInfo; } - throw new JoinMeetingError(); + throw new JoinWebinarError(); } // when wbxappapi requires password it still populates partial meeting info in the response From 4a3a015240eb9f4094bc2ae7c590369877a6ae37 Mon Sep 17 00:00:00 2001 From: "Judy Zhu (judyz)" Date: Tue, 4 Mar 2025 13:55:46 +0800 Subject: [PATCH 7/7] feat(webinar): spark-623318 return correct info when can't join meeting since not reach JBH --- packages/@webex/plugin-meetings/src/meeting/index.ts | 1 - .../@webex/plugin-meetings/test/unit/spec/meeting/index.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/@webex/plugin-meetings/src/meeting/index.ts b/packages/@webex/plugin-meetings/src/meeting/index.ts index 94e4c835fd8..610a295cd61 100644 --- a/packages/@webex/plugin-meetings/src/meeting/index.ts +++ b/packages/@webex/plugin-meetings/src/meeting/index.ts @@ -163,7 +163,6 @@ import {ConnectionStateHandler, ConnectionStateEvent} from './connectionStateHan import JoinWebinarError from '../common/errors/join-webinar-error'; import Member from '../member'; import MultistreamNotSupportedError from '../common/errors/multistream-not-supported-error'; -import JoinMeetingError from '../common/errors/join-meeting'; // default callback so we don't call an undefined function, but in practice it should never be used const DEFAULT_ICE_PHASE_CALLBACK = () => 'JOIN_MEETING_FINAL'; diff --git a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js index 045bb656e00..3a8d4cbaca2 100644 --- a/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js +++ b/packages/@webex/plugin-meetings/test/unit/spec/meeting/index.js @@ -114,7 +114,6 @@ import {ERROR_DESCRIPTIONS} from '@webex/internal-plugin-metrics/src/call-diagno import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection'; import {EVENT_TRIGGERS as VOICEAEVENTS} from '@webex/internal-plugin-voicea'; -import JoinMeetingError from '../../../../src/common/errors/join-meeting'; describe('plugin-meetings', () => { const logger = { @@ -6349,7 +6348,7 @@ describe('plugin-meetings', () => { .throws(new MeetingInfoV2PasswordError(403003, FAKE_MEETING_INFO)), }; - await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinMeetingError); + await assert.isRejected(meeting.fetchMeetingInfo({sendCAevents: true}), JoinWebinarError); assert.calledWith( meeting.attrs.meetingInfoProvider.fetchMeetingInfo,