Skip to content

Commit ae25857

Browse files
feat(meetings): add site preferences API (#4955)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 844d001 commit ae25857

9 files changed

Lines changed: 367 additions & 0 deletions

File tree

packages/@webex/plugin-meetings/src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export default {
8282
enableExtmap: false,
8383
enableAutomaticLLM: false,
8484
installedOrgID: undefined,
85+
multipartSitePrefixList: ['.my.', '.mydmz.', '.mybts.', '.mydev.', '.myats2.', '.myats.'],
8586
experimental: {
8687
enableMediaNegotiatedEvent: false,
8788
enableUnifiedMeetings: true,

packages/@webex/plugin-meetings/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ export * as REACTIONS from './reactions/reactions';
6565
export * as sdkAnnotationTypes from './annotation/annotation.types';
6666
export * as MeetingInfoV2 from './meeting-info/meeting-info-v2';
6767
export {type Reaction} from './reactions/reactions.type';
68+
export {SitePreferenceSelectOption} from './meetings/meetings.types';
69+
export type {
70+
FetchSitePreferencesMeViaSiteOptions,
71+
SitePreferencesResponse,
72+
} from './meetings/meetings.types';
6873

6974
export {
7075
CaptchaError,

packages/@webex/plugin-meetings/src/meetings/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ import PasswordError from '../common/errors/password-error';
5555
import CaptchaError from '../common/errors/captcha-error';
5656
import MeetingCollection from './collection';
5757
import {
58+
FetchSitePreferencesMeViaSiteOptions,
5859
MEETING_KEY,
5960
INoiseReductionEffect,
6061
IVirtualBackgroundEffect,
6162
MeetingRegistrationStatus,
63+
SitePreferencesResponse,
6264
} from './meetings.types';
6365
import MeetingsUtil from './util';
6466
import PermissionError from '../common/errors/permission';
@@ -1405,6 +1407,31 @@ export default class Meetings extends WebexPlugin {
14051407
return this.personalMeetingRoom;
14061408
}
14071409

1410+
/**
1411+
* Fetches site preferences for the provided Webex site, or the preferred Webex site.
1412+
* This is used to determine capabilities of the site, such as whether scheduling a webinar is supported.
1413+
*
1414+
* @param {object} [options]
1415+
* @param {string} [options.siteUrl] - Webex site URL. Defaults to preferredWebexSite, for example "cisco.webex.com".
1416+
* @param {string} [options.siteName] - Site name query override. Defaults to the site name derived from siteUrl, for example "cisco" for "cisco.webex.com".
1417+
* @param {SitePreferenceSelectOption[]} [options.selectOptions] - Preference sections to fetch. Defaults to 'scheduling'.
1418+
* @returns {Promise<SitePreferencesResponse>} site preferences response body
1419+
* @throws {ParameterError}
1420+
* @public
1421+
* @memberof Meetings
1422+
* @example
1423+
* const preferences = await webex.meetings.fetchSitePreferencesMeViaSite();
1424+
* const supportScheduleWebinar = preferences?.scheduling?.supportScheduleWebinar;
1425+
*/
1426+
public fetchSitePreferencesMeViaSite(
1427+
options: FetchSitePreferencesMeViaSiteOptions = {}
1428+
): Promise<SitePreferencesResponse> {
1429+
return this.request.fetchSitePreferencesMeViaSite({
1430+
...options,
1431+
siteUrl: options.siteUrl || this.preferredWebexSite,
1432+
});
1433+
}
1434+
14081435
/**
14091436
* Returns basic information about a meeting that exists or
14101437
* used to exist in the MeetingCollection

packages/@webex/plugin-meetings/src/meetings/meetings.types.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,22 @@ export type MeetingRegistrationStatus = {
3131
mercuryConnect: boolean;
3232
checkH264Support: boolean;
3333
};
34+
35+
export enum SitePreferenceSelectOption {
36+
SCHEDULING = 'scheduling',
37+
}
38+
39+
export type FetchSitePreferencesMeViaSiteOptions = {
40+
siteUrl?: string;
41+
siteName?: string;
42+
selectOptions?: SitePreferenceSelectOption[];
43+
};
44+
45+
export const DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS = [SitePreferenceSelectOption.SCHEDULING];
46+
47+
export type SitePreferencesResponse = {
48+
scheduling?: {
49+
supportScheduleWebinar?: boolean;
50+
webinarWebLink?: string;
51+
};
52+
};

packages/@webex/plugin-meetings/src/meetings/request.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22
import {StatelessWebexPlugin} from '@webex/webex-core';
33

44
import LoggerProxy from '../common/logs/logger-proxy';
5+
import ParameterError from '../common/errors/parameter';
56
import {HTTP_VERBS, API, RESOURCE} from '../constants';
7+
import {
8+
DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS,
9+
type FetchSitePreferencesMeViaSiteOptions,
10+
type SitePreferencesResponse,
11+
} from './meetings.types';
12+
import MeetingsUtil from './util';
613

714
/**
815
* @class MeetingRequest
@@ -45,6 +52,42 @@ export default class MeetingRequest extends StatelessWebexPlugin {
4552
return this.webex.internal.services.getMeetingPreferences();
4653
}
4754

55+
/**
56+
* Fetches site preferences from a given site given a select option and a siteUrl with an optional siteName. If siteName is not provided, it will be derived from the siteUrl. If siteUrl is not provided, it will throw an error. If selectOptions is not provided, it will default to scheduling.
57+
*
58+
* @param {object} [options]
59+
* @param {string} [options.siteUrl] - Webex site URL, for example "cisco.webex.com".
60+
* @param {string} [options.siteName] - Site name query override. Defaults to the site name derived from options.siteUrl, e.g., "cisco".
61+
* @param {SitePreferenceSelectOption[]} [options.selectOptions] - Preference sections to fetch. Defaults to 'scheduling'.
62+
* @returns {Promise<SitePreferencesResponse>} site preferences response body
63+
* @throws {ParameterError}
64+
* @public
65+
* @memberof MeetingRequest
66+
*/
67+
fetchSitePreferencesMeViaSite(
68+
options: FetchSitePreferencesMeViaSiteOptions = {}
69+
): Promise<SitePreferencesResponse> {
70+
const {siteUrl, selectOptions = DEFAULT_SITE_PREFERENCE_SELECT_OPTIONS} = options;
71+
72+
if (!siteUrl) {
73+
throw new ParameterError(
74+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
75+
);
76+
}
77+
78+
// @ts-ignore - config comes from registerPlugin
79+
const multipartSitePrefixList = this.config.meetings.multipartSitePrefixList || [];
80+
const siteName = options.siteName || MeetingsUtil.getSiteName(siteUrl, multipartSitePrefixList);
81+
82+
// @ts-ignore
83+
return this.request({
84+
method: HTTP_VERBS.GET,
85+
uri: `https://${siteUrl}/wbxappapi/v1/users/me/preference?select=${encodeURIComponent(
86+
selectOptions.join(',')
87+
)}&siteurl=${encodeURIComponent(siteName)}`,
88+
}).then((res: any) => res.body);
89+
}
90+
4891
// locus federation, determines and populate locus if the responseBody has remote URLs to fetch locus details
4992

5093
/**

packages/@webex/plugin-meetings/src/meetings/util.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,30 @@ MeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {
153153
return result;
154154
};
155155

156+
MeetingsUtil.getSiteName = (site: string, multipartSitePrefixList: string[] = []) => {
157+
if (!site) {
158+
return null;
159+
}
160+
161+
let siteName: string | undefined;
162+
163+
multipartSitePrefixList.forEach((multipartSitePrefix) => {
164+
if (!siteName && site.includes(multipartSitePrefix)) {
165+
const secondDot = site.indexOf('.', site.indexOf('.') + 1);
166+
167+
siteName = site.substring(0, secondDot);
168+
}
169+
});
170+
171+
if (siteName) {
172+
return siteName;
173+
}
174+
175+
siteName = site.substring(0, site.indexOf('.'));
176+
177+
return siteName;
178+
};
179+
156180
/**
157181
* Will check to see if the H.264 media codec is supported.
158182
* @async

packages/@webex/plugin-meetings/test/unit/spec/meetings/index.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import StaticConfig from '@webex/plugin-meetings/src/common/config';
1414
import TriggerProxy from '@webex/plugin-meetings/src/common/events/trigger-proxy';
1515
import LoggerProxy from '@webex/plugin-meetings/src/common/logs/logger-proxy';
1616
import LoggerConfig from '@webex/plugin-meetings/src/common/logs/logger-config';
17+
import ParameterError from '@webex/plugin-meetings/src/common/errors/parameter';
1718
import Meeting, {CallStateForMetrics} from '@webex/plugin-meetings/src/meeting';
1819
import {Services} from '@webex/webex-core';
1920
import MeetingUtil from '@webex/plugin-meetings/src/meeting/util';
2021
import Meetings from '@webex/plugin-meetings/src/meetings';
2122
import MeetingCollection from '@webex/plugin-meetings/src/meetings/collection';
2223
import MeetingsUtil from '@webex/plugin-meetings/src/meetings/util';
24+
import {SitePreferenceSelectOption} from '@webex/plugin-meetings/src/meetings/meetings.types';
2325
import PersonalMeetingRoom from '@webex/plugin-meetings/src/personal-meeting-room';
2426
import Reachability from '@webex/plugin-meetings/src/reachability';
2527
import Metrics from '@webex/plugin-meetings/src/metrics';
@@ -1356,6 +1358,87 @@ describe('plugin-meetings', () => {
13561358
);
13571359
});
13581360
});
1361+
describe('#fetchSitePreferencesMeViaSite', () => {
1362+
const sitePreferencesResponse = {
1363+
scheduling: {
1364+
supportScheduleWebinar: true,
1365+
webinarWebLink: 'https://go.webex.com/webappng/sites/go/webinar/scheduler',
1366+
},
1367+
};
1368+
1369+
beforeEach(() => {
1370+
webex.meetings.request.fetchSitePreferencesMeViaSite = sinon
1371+
.stub()
1372+
.resolves(sitePreferencesResponse);
1373+
});
1374+
1375+
it('should have #fetchSitePreferencesMeViaSite', () => {
1376+
assert.exists(webex.meetings.fetchSitePreferencesMeViaSite);
1377+
});
1378+
1379+
it('fetches scheduling preferences for the preferred Webex site by default', async () => {
1380+
webex.meetings.preferredWebexSite = 'go.webex.com';
1381+
1382+
const result = await webex.meetings.fetchSitePreferencesMeViaSite();
1383+
1384+
assert.deepEqual(result, sitePreferencesResponse);
1385+
assert.calledOnceWithExactly(
1386+
webex.meetings.request.fetchSitePreferencesMeViaSite,
1387+
{
1388+
siteUrl: 'go.webex.com',
1389+
}
1390+
);
1391+
});
1392+
1393+
it('uses the provided Webex site instead of the preferred Webex site', async () => {
1394+
webex.meetings.preferredWebexSite = 'preferred.webex.com';
1395+
1396+
await webex.meetings.fetchSitePreferencesMeViaSite({siteUrl: 'go.webex.com'});
1397+
1398+
assert.calledOnceWithExactly(
1399+
webex.meetings.request.fetchSitePreferencesMeViaSite,
1400+
{
1401+
siteUrl: 'go.webex.com',
1402+
}
1403+
);
1404+
});
1405+
1406+
it('forwards custom site name and preference sections to the request helper', async () => {
1407+
webex.meetings.preferredWebexSite = 'go.webex.com';
1408+
1409+
await webex.meetings.fetchSitePreferencesMeViaSite({
1410+
siteName: 'custom-site',
1411+
selectOptions: [SitePreferenceSelectOption.SCHEDULING],
1412+
});
1413+
1414+
assert.calledOnceWithExactly(
1415+
webex.meetings.request.fetchSitePreferencesMeViaSite,
1416+
{
1417+
siteUrl: 'go.webex.com',
1418+
siteName: 'custom-site',
1419+
selectOptions: [SitePreferenceSelectOption.SCHEDULING],
1420+
}
1421+
);
1422+
});
1423+
1424+
it('throws when no Webex site is available', () => {
1425+
webex.meetings.preferredWebexSite = '';
1426+
webex.meetings.request.fetchSitePreferencesMeViaSite.throws(
1427+
new ParameterError(
1428+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
1429+
)
1430+
);
1431+
1432+
assert.throws(
1433+
() => webex.meetings.fetchSitePreferencesMeViaSite(),
1434+
ParameterError,
1435+
'No siteUrl available. Call register() before fetching site preferences or provide options.siteUrl.'
1436+
);
1437+
assert.calledOnceWithExactly(webex.meetings.request.fetchSitePreferencesMeViaSite, {
1438+
siteUrl: '',
1439+
});
1440+
});
1441+
});
13591442
describe('Static shortcut proxy methods', () => {
13601443
describe('MeetingCollection getByKey proxies', () => {
13611444
beforeEach(() => {

0 commit comments

Comments
 (0)