@webex/plugin-meetings 3.7.0-next.4 → 3.7.0-next.6

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 (42) hide show
  1. package/dist/breakouts/breakout.js +1 -1
  2. package/dist/breakouts/index.js +1 -1
  3. package/dist/constants.js +10 -1
  4. package/dist/constants.js.map +1 -1
  5. package/dist/interpretation/index.js +1 -1
  6. package/dist/interpretation/siLanguage.js +1 -1
  7. package/dist/meeting/in-meeting-actions.js +11 -1
  8. package/dist/meeting/in-meeting-actions.js.map +1 -1
  9. package/dist/meeting/index.js +18 -0
  10. package/dist/meeting/index.js.map +1 -1
  11. package/dist/members/util.js +4 -2
  12. package/dist/members/util.js.map +1 -1
  13. package/dist/recording-controller/enums.js +8 -4
  14. package/dist/recording-controller/enums.js.map +1 -1
  15. package/dist/recording-controller/index.js +18 -9
  16. package/dist/recording-controller/index.js.map +1 -1
  17. package/dist/recording-controller/util.js +13 -9
  18. package/dist/recording-controller/util.js.map +1 -1
  19. package/dist/types/constants.d.ts +8 -0
  20. package/dist/types/meeting/in-meeting-actions.d.ts +10 -0
  21. package/dist/types/meeting/index.d.ts +1 -0
  22. package/dist/types/members/util.d.ts +2 -0
  23. package/dist/types/recording-controller/enums.d.ts +5 -2
  24. package/dist/types/recording-controller/index.d.ts +1 -0
  25. package/dist/types/recording-controller/util.d.ts +2 -1
  26. package/dist/webinar/index.js +39 -7
  27. package/dist/webinar/index.js.map +1 -1
  28. package/package.json +21 -21
  29. package/src/constants.ts +10 -0
  30. package/src/meeting/in-meeting-actions.ts +21 -0
  31. package/src/meeting/index.ts +22 -0
  32. package/src/members/util.ts +1 -0
  33. package/src/recording-controller/enums.ts +5 -2
  34. package/src/recording-controller/index.ts +17 -4
  35. package/src/recording-controller/util.ts +20 -5
  36. package/src/webinar/index.ts +40 -8
  37. package/test/unit/spec/meeting/in-meeting-actions.ts +13 -1
  38. package/test/unit/spec/meeting/index.js +3 -0
  39. package/test/unit/spec/members/utils.js +95 -0
  40. package/test/unit/spec/recording-controller/index.js +61 -5
  41. package/test/unit/spec/recording-controller/util.js +39 -3
  42. package/test/unit/spec/webinar/index.ts +47 -0
@@ -1 +1 @@
1
- {"version":3,"names":["_webexCore","require","_lodash","_constants","_collection","_interopRequireDefault","Webinar","WebexPlugin","extend","namespace","MEETINGS","collections","webinar","WebinarCollection","props","locusUrl","webcastInstanceUrl","canManageWebcast","selfIsPanelist","selfIsAttendee","locusUrlUpdate","set","updateWebcastUrl","payload","get","updateCanManageWebcast","updateRoleChanged","isPromoted","includes","SELF_ROLES","ATTENDEE","PANELIST","isDemoted","MODERATOR","version","_default","exports","default"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2023 Cisco Systems, Inc. See LICENSE file.\n */\nimport {WebexPlugin} from '@webex/webex-core';\nimport {get} from 'lodash';\nimport {MEETINGS, SELF_ROLES} from '../constants';\n\nimport WebinarCollection from './collection';\n\n/**\n * @class Webinar\n */\nconst Webinar = WebexPlugin.extend({\n namespace: MEETINGS,\n collections: {\n webinar: WebinarCollection,\n },\n\n props: {\n locusUrl: 'string', // appears current webinar's locus url\n webcastInstanceUrl: 'string', // current webinar's webcast instance url\n canManageWebcast: 'boolean', // appears the ability to manage webcast\n selfIsPanelist: 'boolean', // self is panelist\n selfIsAttendee: 'boolean', // self is attendee\n },\n\n /**\n * Update the current locus url of the webinar\n * @param {string} locusUrl\n * @returns {void}\n */\n locusUrlUpdate(locusUrl) {\n this.set('locusUrl', locusUrl);\n },\n\n /**\n * Update the current webcast instance url of the meeting\n * @param {object} payload\n * @returns {void}\n */\n updateWebcastUrl(payload) {\n this.set('webcastInstanceUrl', get(payload, 'resources.webcastInstance.url'));\n },\n\n /**\n * Update whether self has capability to manage start/stop webcast (only host can manage it)\n * @param {boolean} canManageWebcast\n * @returns {void}\n */\n updateCanManageWebcast(canManageWebcast) {\n this.set('canManageWebcast', canManageWebcast);\n },\n\n /**\n * Updates user roles and manages associated state transitions\n * @param {object} payload\n * @param {string[]} payload.oldRoles - Previous roles of the user\n * @param {string[]} payload.newRoles - New roles of the user\n * @returns {{isPromoted: boolean, isDemoted: boolean}} Role transition states\n */\n updateRoleChanged(payload) {\n const isPromoted =\n get(payload, 'oldRoles', []).includes(SELF_ROLES.ATTENDEE) &&\n get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST);\n const isDemoted =\n get(payload, 'oldRoles', []).includes(SELF_ROLES.PANELIST) &&\n get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE);\n this.set('selfIsPanelist', get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST));\n this.set('selfIsAttendee', get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE));\n this.updateCanManageWebcast(get(payload, 'newRoles', []).includes(SELF_ROLES.MODERATOR));\n\n return {isPromoted, isDemoted};\n },\n});\n\nexport default Webinar;\n"],"mappings":";;;;;;;;AAGA,IAAAA,UAAA,GAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,UAAA,GAAAF,OAAA;AAEA,IAAAG,WAAA,GAAAC,sBAAA,CAAAJ,OAAA;AAPA;AACA;AACA;;AAOA;AACA;AACA;AACA,IAAMK,OAAO,GAAGC,sBAAW,CAACC,MAAM,CAAC;EACjCC,SAAS,EAAEC,mBAAQ;EACnBC,WAAW,EAAE;IACXC,OAAO,EAAEC;EACX,CAAC;EAEDC,KAAK,EAAE;IACLC,QAAQ,EAAE,QAAQ;IAAE;IACpBC,kBAAkB,EAAE,QAAQ;IAAE;IAC9BC,gBAAgB,EAAE,SAAS;IAAE;IAC7BC,cAAc,EAAE,SAAS;IAAE;IAC3BC,cAAc,EAAE,SAAS,CAAE;EAC7B,CAAC;EAED;AACF;AACA;AACA;AACA;EACEC,cAAc,WAAAA,eAACL,QAAQ,EAAE;IACvB,IAAI,CAACM,GAAG,CAAC,UAAU,EAAEN,QAAQ,CAAC;EAChC,CAAC;EAED;AACF;AACA;AACA;AACA;EACEO,gBAAgB,WAAAA,iBAACC,OAAO,EAAE;IACxB,IAAI,CAACF,GAAG,CAAC,oBAAoB,EAAE,IAAAG,WAAG,EAACD,OAAO,EAAE,+BAA+B,CAAC,CAAC;EAC/E,CAAC;EAED;AACF;AACA;AACA;AACA;EACEE,sBAAsB,WAAAA,uBAACR,gBAAgB,EAAE;IACvC,IAAI,CAACI,GAAG,CAAC,kBAAkB,EAAEJ,gBAAgB,CAAC;EAChD,CAAC;EAED;AACF;AACA;AACA;AACA;AACA;AACA;EACES,iBAAiB,WAAAA,kBAACH,OAAO,EAAE;IACzB,IAAMI,UAAU,GACd,IAAAH,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACC,QAAQ,CAAC,IAC1D,IAAAN,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACE,QAAQ,CAAC;IAC5D,IAAMC,SAAS,GACb,IAAAR,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACE,QAAQ,CAAC,IAC1D,IAAAP,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACC,QAAQ,CAAC;IAC5D,IAAI,CAACT,GAAG,CAAC,gBAAgB,EAAE,IAAAG,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACE,QAAQ,CAAC,CAAC;IACtF,IAAI,CAACV,GAAG,CAAC,gBAAgB,EAAE,IAAAG,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACC,QAAQ,CAAC,CAAC;IACtF,IAAI,CAACL,sBAAsB,CAAC,IAAAD,WAAG,EAACD,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAACK,QAAQ,CAACC,qBAAU,CAACI,SAAS,CAAC,CAAC;IAExF,OAAO;MAACN,UAAU,EAAVA,UAAU;MAAEK,SAAS,EAATA;IAAS,CAAC;EAChC,CAAC;EAAAE,OAAA;AACH,CAAC,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAEY/B,OAAO"}
1
+ {"version":3,"names":["_webexCore","require","_lodash","_constants","_collection","_interopRequireDefault","_loggerProxy","Webinar","WebexPlugin","extend","namespace","MEETINGS","collections","webinar","WebinarCollection","props","locusUrl","webcastInstanceUrl","canManageWebcast","selfIsPanelist","selfIsAttendee","practiceSessionEnabled","locusUrlUpdate","set","updateWebcastUrl","payload","get","updateCanManageWebcast","updateRoleChanged","oldRoles","newRoles","isPromoted","includes","SELF_ROLES","ATTENDEE","PANELIST","isDemoted","MODERATOR","setPracticeSessionState","enabled","request","method","HTTP_VERBS","PATCH","uri","concat","body","practiceSession","catch","error","LoggerProxy","logger","updatePracticeSessionStatus","version","_default","exports","default"],"sources":["index.ts"],"sourcesContent":["/*!\n * Copyright (c) 2015-2023 Cisco Systems, Inc. See LICENSE file.\n */\nimport {WebexPlugin} from '@webex/webex-core';\nimport {get} from 'lodash';\nimport {HTTP_VERBS, MEETINGS, SELF_ROLES} from '../constants';\n\nimport WebinarCollection from './collection';\nimport LoggerProxy from '../common/logs/logger-proxy';\n\n/**\n * @class Webinar\n */\nconst Webinar = WebexPlugin.extend({\n namespace: MEETINGS,\n collections: {\n webinar: WebinarCollection,\n },\n\n props: {\n locusUrl: 'string', // appears current webinar's locus url\n webcastInstanceUrl: 'string', // current webinar's webcast instance url\n canManageWebcast: 'boolean', // appears the ability to manage webcast\n selfIsPanelist: 'boolean', // self is panelist\n selfIsAttendee: 'boolean', // self is attendee\n practiceSessionEnabled: 'boolean', // practice session enabled\n },\n\n /**\n * Update the current locus url of the webinar\n * @param {string} locusUrl\n * @returns {void}\n */\n locusUrlUpdate(locusUrl) {\n this.set('locusUrl', locusUrl);\n },\n\n /**\n * Update the current webcast instance url of the meeting\n * @param {object} payload\n * @returns {void}\n */\n updateWebcastUrl(payload) {\n this.set('webcastInstanceUrl', get(payload, 'resources.webcastInstance.url'));\n },\n\n /**\n * Update whether self has capability to manage start/stop webcast (only host can manage it)\n * @param {boolean} canManageWebcast\n * @returns {void}\n */\n updateCanManageWebcast(canManageWebcast) {\n this.set('canManageWebcast', canManageWebcast);\n },\n\n /**\n * Updates user roles and manages associated state transitions\n * @param {object} payload\n * @param {string[]} payload.oldRoles - Previous roles of the user\n * @param {string[]} payload.newRoles - New roles of the user\n * @returns {{isPromoted: boolean, isDemoted: boolean}} Role transition states\n */\n updateRoleChanged(payload) {\n const oldRoles = get(payload, 'oldRoles', []);\n const newRoles = get(payload, 'newRoles', []);\n\n const isPromoted =\n oldRoles.includes(SELF_ROLES.ATTENDEE) && newRoles.includes(SELF_ROLES.PANELIST);\n const isDemoted =\n oldRoles.includes(SELF_ROLES.PANELIST) && newRoles.includes(SELF_ROLES.ATTENDEE);\n this.set('selfIsPanelist', newRoles.includes(SELF_ROLES.PANELIST));\n this.set('selfIsAttendee', newRoles.includes(SELF_ROLES.ATTENDEE));\n this.updateCanManageWebcast(newRoles.includes(SELF_ROLES.MODERATOR));\n\n return {isPromoted, isDemoted};\n },\n\n /**\n * start or stop practice session for webinar\n * @param {boolean} enabled\n * @returns {Promise}\n */\n setPracticeSessionState(enabled) {\n return this.request({\n method: HTTP_VERBS.PATCH,\n uri: `${this.locusUrl}/controls`,\n body: {\n practiceSession: {\n enabled,\n },\n },\n }).catch((error) => {\n LoggerProxy.logger.error('Meeting:webinar#setPracticeSessionState failed', error);\n throw error;\n });\n },\n\n /**\n * update practice session status\n * @param {object} payload\n * @returns {void}\n */\n updatePracticeSessionStatus(payload) {\n this.set('practiceSessionEnabled', payload.enabled);\n },\n});\n\nexport default Webinar;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -43,13 +43,13 @@
43
43
  "@webex/eslint-config-legacy": "0.0.0",
44
44
  "@webex/jest-config-legacy": "0.0.0",
45
45
  "@webex/legacy-tools": "0.0.0",
46
- "@webex/plugin-meetings": "3.7.0-next.4",
47
- "@webex/plugin-rooms": "3.7.0-next.1",
48
- "@webex/test-helper-chai": "3.7.0-next.1",
49
- "@webex/test-helper-mocha": "3.7.0-next.1",
50
- "@webex/test-helper-mock-webex": "3.7.0-next.1",
51
- "@webex/test-helper-retry": "3.7.0-next.1",
52
- "@webex/test-helper-test-users": "3.7.0-next.1",
46
+ "@webex/plugin-meetings": "3.7.0-next.6",
47
+ "@webex/plugin-rooms": "3.7.0-next.2",
48
+ "@webex/test-helper-chai": "3.7.0-next.2",
49
+ "@webex/test-helper-mocha": "3.7.0-next.2",
50
+ "@webex/test-helper-mock-webex": "3.7.0-next.2",
51
+ "@webex/test-helper-retry": "3.7.0-next.2",
52
+ "@webex/test-helper-test-users": "3.7.0-next.2",
53
53
  "chai": "^4.3.4",
54
54
  "chai-as-promised": "^7.1.1",
55
55
  "eslint": "^8.24.0",
@@ -61,21 +61,21 @@
61
61
  "typescript": "^4.7.4"
62
62
  },
63
63
  "dependencies": {
64
- "@webex/common": "3.7.0-next.1",
64
+ "@webex/common": "3.7.0-next.2",
65
65
  "@webex/internal-media-core": "2.12.2",
66
- "@webex/internal-plugin-conversation": "3.7.0-next.1",
67
- "@webex/internal-plugin-device": "3.7.0-next.1",
68
- "@webex/internal-plugin-llm": "3.7.0-next.1",
69
- "@webex/internal-plugin-mercury": "3.7.0-next.1",
70
- "@webex/internal-plugin-metrics": "3.7.0-next.1",
71
- "@webex/internal-plugin-support": "3.7.0-next.1",
72
- "@webex/internal-plugin-user": "3.7.0-next.1",
73
- "@webex/internal-plugin-voicea": "3.7.0-next.4",
74
- "@webex/media-helpers": "3.7.0-next.1",
75
- "@webex/plugin-people": "3.7.0-next.1",
76
- "@webex/plugin-rooms": "3.7.0-next.1",
66
+ "@webex/internal-plugin-conversation": "3.7.0-next.2",
67
+ "@webex/internal-plugin-device": "3.7.0-next.2",
68
+ "@webex/internal-plugin-llm": "3.7.0-next.2",
69
+ "@webex/internal-plugin-mercury": "3.7.0-next.2",
70
+ "@webex/internal-plugin-metrics": "3.7.0-next.2",
71
+ "@webex/internal-plugin-support": "3.7.0-next.2",
72
+ "@webex/internal-plugin-user": "3.7.0-next.2",
73
+ "@webex/internal-plugin-voicea": "3.7.0-next.6",
74
+ "@webex/media-helpers": "3.7.0-next.2",
75
+ "@webex/plugin-people": "3.7.0-next.2",
76
+ "@webex/plugin-rooms": "3.7.0-next.2",
77
77
  "@webex/web-capabilities": "^1.4.0",
78
- "@webex/webex-core": "3.7.0-next.1",
78
+ "@webex/webex-core": "3.7.0-next.2",
79
79
  "ampersand-collection": "^2.0.2",
80
80
  "bowser": "^2.11.0",
81
81
  "btoa": "^1.2.1",
@@ -91,5 +91,5 @@
91
91
  "//": [
92
92
  "TODO: upgrade jwt-decode when moving to node 18"
93
93
  ],
94
- "version": "3.7.0-next.4"
94
+ "version": "3.7.0-next.6"
95
95
  }
package/src/constants.ts CHANGED
@@ -904,6 +904,10 @@ export const DISPLAY_HINTS = {
904
904
  RECORDING_CONTROL_PAUSE: 'RECORDING_CONTROL_PAUSE',
905
905
  RECORDING_CONTROL_STOP: 'RECORDING_CONTROL_STOP',
906
906
  RECORDING_CONTROL_RESUME: 'RECORDING_CONTROL_RESUME',
907
+ PREMISE_RECORDING_CONTROL_START: 'PREMISE_RECORDING_CONTROL_START',
908
+ PREMISE_RECORDING_CONTROL_PAUSE: 'PREMISE_RECORDING_CONTROL_PAUSE',
909
+ PREMISE_RECORDING_CONTROL_STOP: 'PREMISE_RECORDING_CONTROL_STOP',
910
+ PREMISE_RECORDING_CONTROL_RESUME: 'PREMISE_RECORDING_CONTROL_RESUME',
907
911
  LOCK_CONTROL_UNLOCK: 'LOCK_CONTROL_UNLOCK',
908
912
  LOCK_CONTROL_LOCK: 'LOCK_CONTROL_LOCK',
909
913
  LOCK_STATUS_LOCKED: 'LOCK_STATUS_LOCKED',
@@ -988,6 +992,12 @@ export const DISPLAY_HINTS = {
988
992
  STAGE_VIEW_INACTIVE: 'STAGE_VIEW_INACTIVE',
989
993
  ENABLE_STAGE_VIEW: 'ENABLE_STAGE_VIEW',
990
994
  DISABLE_STAGE_VIEW: 'DISABLE_STAGE_VIEW',
995
+
996
+ // Practice Session
997
+ PRACTICE_SESSION_ON: 'PRACTICE_SESSION_ON',
998
+ PRACTICE_SESSION_OFF: 'PRACTICE_SESSION_OFF',
999
+ SHOW_PRACTICE_SESSION_START: 'SHOW_PRACTICE_SESSION_START',
1000
+ SHOW_PRACTICE_SESSION_STOP: 'SHOW_PRACTICE_SESSION_STOP',
991
1001
  };
992
1002
 
993
1003
  export const INTERSTITIAL_DISPLAY_HINTS = [DISPLAY_HINTS.VOIP_IS_ENABLED];
@@ -26,6 +26,7 @@ interface IInMeetingActions {
26
26
  canStartRecording?: boolean;
27
27
  canPauseRecording?: boolean;
28
28
  canResumeRecording?: boolean;
29
+ isPremiseRecordingEnabled?: boolean;
29
30
  canStopRecording?: boolean;
30
31
  canRaiseHand?: boolean;
31
32
  canLowerAllHands?: boolean;
@@ -93,6 +94,10 @@ interface IInMeetingActions {
93
94
  canShowStageView?: boolean;
94
95
  canEnableStageView?: boolean;
95
96
  canDisableStageView?: boolean;
97
+ isPracticeSessionOn?: boolean;
98
+ isPracticeSessionOff?: boolean;
99
+ canStartPracticeSession?: boolean;
100
+ canStopPracticeSession?: boolean;
96
101
  }
97
102
 
98
103
  /**
@@ -117,6 +122,8 @@ export default class InMeetingActions implements IInMeetingActions {
117
122
 
118
123
  canResumeRecording = null;
119
124
 
125
+ isPremiseRecordingEnabled = null;
126
+
120
127
  canStopRecording = null;
121
128
 
122
129
  canSetMuteOnEntry = null;
@@ -266,6 +273,15 @@ export default class InMeetingActions implements IInMeetingActions {
266
273
  canEnableStageView = null;
267
274
 
268
275
  canDisableStageView = null;
276
+
277
+ isPracticeSessionOn = null;
278
+
279
+ isPracticeSessionOff = null;
280
+
281
+ canStartPracticeSession = null;
282
+
283
+ canStopPracticeSession = null;
284
+
269
285
  /**
270
286
  * Returns all meeting action options
271
287
  * @returns {Object}
@@ -288,6 +304,7 @@ export default class InMeetingActions implements IInMeetingActions {
288
304
  canPauseRecording: this.canPauseRecording,
289
305
  canResumeRecording: this.canResumeRecording,
290
306
  canStopRecording: this.canStopRecording,
307
+ isPremiseRecordingEnabled: this.isPremiseRecordingEnabled,
291
308
  canRaiseHand: this.canRaiseHand,
292
309
  canLowerAllHands: this.canLowerAllHands,
293
310
  canLowerSomeoneElsesHand: this.canLowerSomeoneElsesHand,
@@ -354,6 +371,10 @@ export default class InMeetingActions implements IInMeetingActions {
354
371
  canShowStageView: this.canShowStageView,
355
372
  canEnableStageView: this.canEnableStageView,
356
373
  canDisableStageView: this.canDisableStageView,
374
+ isPracticeSessionOn: this.isPracticeSessionOn,
375
+ isPracticeSessionOff: this.isPracticeSessionOff,
376
+ canStartPracticeSession: this.canStartPracticeSession,
377
+ canStopPracticeSession: this.canStopPracticeSession,
357
378
  });
358
379
 
359
380
  /**
@@ -2660,6 +2660,7 @@ export default class Meeting extends StatelessWebexPlugin {
2660
2660
  });
2661
2661
 
2662
2662
  this.locusInfo.on(LOCUSINFO.EVENTS.CONTROLS_PRACTICE_SESSION_STATUS_UPDATED, ({state}) => {
2663
+ this.webinar.updatePracticeSessionStatus(state);
2663
2664
  Trigger.trigger(
2664
2665
  this,
2665
2666
  {file: 'meeting/index', function: 'setupLocusControlsListener'},
@@ -3516,6 +3517,7 @@ export default class Meeting extends StatelessWebexPlugin {
3516
3517
  emailAddress: string;
3517
3518
  email: string;
3518
3519
  phoneNumber: string;
3520
+ roles: Array<string>;
3519
3521
  },
3520
3522
  alertIfActive = true
3521
3523
  ) {
@@ -3772,6 +3774,10 @@ export default class Meeting extends StatelessWebexPlugin {
3772
3774
  this.userDisplayHints,
3773
3775
  this.selfUserPolicies
3774
3776
  ),
3777
+ isPremiseRecordingEnabled: RecordingUtil.isPremiseRecordingEnabled(
3778
+ this.userDisplayHints,
3779
+ this.selfUserPolicies
3780
+ ),
3775
3781
  canRaiseHand: MeetingUtil.canUserRaiseHand(this.userDisplayHints),
3776
3782
  canLowerAllHands: MeetingUtil.canUserLowerAllHands(this.userDisplayHints),
3777
3783
  canLowerSomeoneElsesHand: MeetingUtil.canUserLowerSomeoneElsesHand(this.userDisplayHints),
@@ -3915,6 +3921,22 @@ export default class Meeting extends StatelessWebexPlugin {
3915
3921
  requiredHints: [DISPLAY_HINTS.DISABLE_STAGE_VIEW],
3916
3922
  displayHints: this.userDisplayHints,
3917
3923
  }),
3924
+ isPracticeSessionOn: ControlsOptionsUtil.hasHints({
3925
+ requiredHints: [DISPLAY_HINTS.PRACTICE_SESSION_ON],
3926
+ displayHints: this.userDisplayHints,
3927
+ }),
3928
+ isPracticeSessionOff: ControlsOptionsUtil.hasHints({
3929
+ requiredHints: [DISPLAY_HINTS.PRACTICE_SESSION_OFF],
3930
+ displayHints: this.userDisplayHints,
3931
+ }),
3932
+ canStartPracticeSession: ControlsOptionsUtil.hasHints({
3933
+ requiredHints: [DISPLAY_HINTS.SHOW_PRACTICE_SESSION_START],
3934
+ displayHints: this.userDisplayHints,
3935
+ }),
3936
+ canStopPracticeSession: ControlsOptionsUtil.hasHints({
3937
+ requiredHints: [DISPLAY_HINTS.SHOW_PRACTICE_SESSION_STOP],
3938
+ displayHints: this.userDisplayHints,
3939
+ }),
3918
3940
  canShareFile:
3919
3941
  (ControlsOptionsUtil.hasHints({
3920
3942
  requiredHints: [DISPLAY_HINTS.SHARE_FILE],
@@ -46,6 +46,7 @@ const MembersUtil = {
46
46
  {
47
47
  address:
48
48
  options.invitee.emailAddress || options.invitee.email || options.invitee.phoneNumber,
49
+ ...(options.invitee.roles ? {roles: options.invitee.roles} : {}),
49
50
  },
50
51
  ],
51
52
  alertIfActive: options.alertIfActive,
@@ -1,8 +1,11 @@
1
- enum RecordingAction {
1
+ export enum RecordingAction {
2
2
  Start = 'Start',
3
3
  Stop = 'Stop',
4
4
  Pause = 'Pause',
5
5
  Resume = 'Resume',
6
6
  }
7
7
 
8
- export default RecordingAction;
8
+ export enum RecordingType {
9
+ Premise = 'premise',
10
+ Cloud = 'cloud',
11
+ }
@@ -1,9 +1,9 @@
1
1
  import PermissionError from '../common/errors/permission';
2
+ import LoggerProxy from '../common/logs/logger-proxy';
2
3
  import {CONTROLS, HTTP_VERBS, SELF_POLICY} from '../constants';
3
4
  import MeetingRequest from '../meeting/request';
4
- import RecordingAction from './enums';
5
+ import {RecordingAction, RecordingType} from './enums';
5
6
  import Util from './util';
6
- import LoggerProxy from '../common/logs/logger-proxy';
7
7
 
8
8
  /**
9
9
  * @description Recording manages the recording functionality of the meeting object, there should only be one instantation of recording per meeting
@@ -228,11 +228,12 @@ export default class RecordingController {
228
228
 
229
229
  /**
230
230
  * @param {RecordingAction} action
231
+ * @param {RecordingType} recordingType
231
232
  * @private
232
233
  * @memberof RecordingController
233
234
  * @returns {Promise}
234
235
  */
235
- private recordingService(action: RecordingAction): Promise<any> {
236
+ private recordingService(action: RecordingAction, recordingType: RecordingType): Promise<any> {
236
237
  // @ts-ignore
237
238
  return this.request.request({
238
239
  body: {
@@ -242,6 +243,7 @@ export default class RecordingController {
242
243
  recording: {
243
244
  action: action.toLowerCase(),
244
245
  },
246
+ recordingType,
245
247
  },
246
248
  uri: `${this.serviceUrl}/loci/${this.locusId}/recording`,
247
249
  method: HTTP_VERBS.PUT,
@@ -276,14 +278,25 @@ export default class RecordingController {
276
278
  * @returns {Promise}
277
279
  */
278
280
  private recordingFacade(action: RecordingAction): Promise<any> {
281
+ const isPremiseRecordingEnabled = Util.isPremiseRecordingEnabled(
282
+ this.displayHints,
283
+ this.selfUserPolicies
284
+ );
279
285
  LoggerProxy.logger.log(
280
286
  `RecordingController:index#recordingFacade --> recording action [${action}]`
281
287
  );
282
288
 
289
+ let recordingType: RecordingType;
290
+ if (isPremiseRecordingEnabled) {
291
+ recordingType = RecordingType.Premise;
292
+ } else {
293
+ recordingType = RecordingType.Cloud;
294
+ }
295
+
283
296
  // assumes action is proper cased (i.e., Example)
284
297
  if (Util?.[`canUser${action}`](this.displayHints, this.selfUserPolicies)) {
285
298
  if (this.serviceUrl) {
286
- return this.recordingService(action);
299
+ return this.recordingService(action, recordingType);
287
300
  }
288
301
 
289
302
  return this.recordingControls(action);
@@ -1,33 +1,47 @@
1
1
  import {DISPLAY_HINTS, SELF_POLICY} from '../constants';
2
- import RecordingAction from './enums';
2
+ import {RecordingAction} from './enums';
3
3
  import MeetingUtil from '../meeting/util';
4
4
 
5
5
  const canUserStart = (
6
6
  displayHints: Array<string>,
7
7
  userPolicies: Record<SELF_POLICY, boolean>
8
8
  ): boolean =>
9
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START) &&
9
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_START) ||
10
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_START)) &&
10
11
  MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
11
12
 
12
13
  const canUserPause = (
13
14
  displayHints: Array<string>,
14
15
  userPolicies: Record<SELF_POLICY, boolean>
15
16
  ): boolean =>
16
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE) &&
17
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_PAUSE) ||
18
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_PAUSE)) &&
17
19
  MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
18
20
 
19
21
  const canUserResume = (
20
22
  displayHints: Array<string>,
21
23
  userPolicies: Record<SELF_POLICY, boolean>
22
24
  ): boolean =>
23
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME) &&
25
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_RESUME) ||
26
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_RESUME)) &&
24
27
  MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
25
28
 
26
29
  const canUserStop = (
27
30
  displayHints: Array<string>,
28
31
  userPolicies: Record<SELF_POLICY, boolean>
29
32
  ): boolean =>
30
- displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP) &&
33
+ (displayHints.includes(DISPLAY_HINTS.RECORDING_CONTROL_STOP) ||
34
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_STOP)) &&
35
+ MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
36
+
37
+ const isPremiseRecordingEnabled = (
38
+ displayHints: Array<string>,
39
+ userPolicies: Record<SELF_POLICY, boolean>
40
+ ): boolean =>
41
+ (displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_START) ||
42
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_PAUSE) ||
43
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_STOP) ||
44
+ displayHints.includes(DISPLAY_HINTS.PREMISE_RECORDING_CONTROL_RESUME)) &&
31
45
  MeetingUtil.selfSupportsFeature(SELF_POLICY.SUPPORT_NETWORK_BASED_RECORD, userPolicies);
32
46
 
33
47
  const extractLocusId = (url: string) => {
@@ -70,6 +84,7 @@ export default {
70
84
  canUserPause,
71
85
  canUserResume,
72
86
  canUserStop,
87
+ isPremiseRecordingEnabled,
73
88
  deriveRecordingStates,
74
89
  extractLocusId,
75
90
  };
@@ -3,9 +3,10 @@
3
3
  */
4
4
  import {WebexPlugin} from '@webex/webex-core';
5
5
  import {get} from 'lodash';
6
- import {MEETINGS, SELF_ROLES} from '../constants';
6
+ import {HTTP_VERBS, MEETINGS, SELF_ROLES} from '../constants';
7
7
 
8
8
  import WebinarCollection from './collection';
9
+ import LoggerProxy from '../common/logs/logger-proxy';
9
10
 
10
11
  /**
11
12
  * @class Webinar
@@ -22,6 +23,7 @@ const Webinar = WebexPlugin.extend({
22
23
  canManageWebcast: 'boolean', // appears the ability to manage webcast
23
24
  selfIsPanelist: 'boolean', // self is panelist
24
25
  selfIsAttendee: 'boolean', // self is attendee
26
+ practiceSessionEnabled: 'boolean', // practice session enabled
25
27
  },
26
28
 
27
29
  /**
@@ -59,18 +61,48 @@ const Webinar = WebexPlugin.extend({
59
61
  * @returns {{isPromoted: boolean, isDemoted: boolean}} Role transition states
60
62
  */
61
63
  updateRoleChanged(payload) {
64
+ const oldRoles = get(payload, 'oldRoles', []);
65
+ const newRoles = get(payload, 'newRoles', []);
66
+
62
67
  const isPromoted =
63
- get(payload, 'oldRoles', []).includes(SELF_ROLES.ATTENDEE) &&
64
- get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST);
68
+ oldRoles.includes(SELF_ROLES.ATTENDEE) && newRoles.includes(SELF_ROLES.PANELIST);
65
69
  const isDemoted =
66
- get(payload, 'oldRoles', []).includes(SELF_ROLES.PANELIST) &&
67
- get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE);
68
- this.set('selfIsPanelist', get(payload, 'newRoles', []).includes(SELF_ROLES.PANELIST));
69
- this.set('selfIsAttendee', get(payload, 'newRoles', []).includes(SELF_ROLES.ATTENDEE));
70
- this.updateCanManageWebcast(get(payload, 'newRoles', []).includes(SELF_ROLES.MODERATOR));
70
+ oldRoles.includes(SELF_ROLES.PANELIST) && newRoles.includes(SELF_ROLES.ATTENDEE);
71
+ this.set('selfIsPanelist', newRoles.includes(SELF_ROLES.PANELIST));
72
+ this.set('selfIsAttendee', newRoles.includes(SELF_ROLES.ATTENDEE));
73
+ this.updateCanManageWebcast(newRoles.includes(SELF_ROLES.MODERATOR));
71
74
 
72
75
  return {isPromoted, isDemoted};
73
76
  },
77
+
78
+ /**
79
+ * start or stop practice session for webinar
80
+ * @param {boolean} enabled
81
+ * @returns {Promise}
82
+ */
83
+ setPracticeSessionState(enabled) {
84
+ return this.request({
85
+ method: HTTP_VERBS.PATCH,
86
+ uri: `${this.locusUrl}/controls`,
87
+ body: {
88
+ practiceSession: {
89
+ enabled,
90
+ },
91
+ },
92
+ }).catch((error) => {
93
+ LoggerProxy.logger.error('Meeting:webinar#setPracticeSessionState failed', error);
94
+ throw error;
95
+ });
96
+ },
97
+
98
+ /**
99
+ * update practice session status
100
+ * @param {object} payload
101
+ * @returns {void}
102
+ */
103
+ updatePracticeSessionStatus(payload) {
104
+ this.set('practiceSessionEnabled', payload.enabled);
105
+ },
74
106
  });
75
107
 
76
108
  export default Webinar;
@@ -33,6 +33,7 @@ describe('plugin-meetings', () => {
33
33
  canStartManualCaption: null,
34
34
  canStopManualCaption: null,
35
35
  isManualCaptionActive: null,
36
+ isPremiseRecordingEnabled: null,
36
37
  isSaveTranscriptsEnabled: null,
37
38
  isWebexAssistantActive: null,
38
39
  canViewCaptionPanel: null,
@@ -88,6 +89,11 @@ describe('plugin-meetings', () => {
88
89
  canShowStageView: null,
89
90
  canEnableStageView: null,
90
91
  canDisableStageView: null,
92
+ isPracticeSessionOn : null,
93
+ isPracticeSessionOff : null,
94
+ canStartPracticeSession: null,
95
+ canStopPracticeSession: null,
96
+
91
97
  ...expected,
92
98
  };
93
99
 
@@ -126,6 +132,7 @@ describe('plugin-meetings', () => {
126
132
  'canStartManualCaption',
127
133
  'canStopManualCaption',
128
134
  'isManualCaptionActive',
135
+ 'isPremiseRecordingEnabled',
129
136
  'isSaveTranscriptsEnabled',
130
137
  'isWebexAssistantActive',
131
138
  'canViewCaptionPanel',
@@ -181,7 +188,12 @@ describe('plugin-meetings', () => {
181
188
  'canShowStageView',
182
189
  'canEnableStageView',
183
190
  'canDisableStageView',
184
- ].forEach((key) => {
191
+ 'isPracticeSessionOn',
192
+ 'isPracticeSessionOff',
193
+ 'canStartPracticeSession',
194
+ 'canStopPracticeSession',
195
+
196
+ ].forEach((key) => {
185
197
  it(`get and set for ${key} work as expected`, () => {
186
198
  const inMeetingActions = new InMeetingActions();
187
199
 
@@ -9044,6 +9044,8 @@ describe('plugin-meetings', () => {
9044
9044
  });
9045
9045
 
9046
9046
  it('listens to MEETING_CONTROLS_PRACTICE_SESSION_STATUS_UPDATED', async () => {
9047
+ meeting.webinar.updatePracticeSessionStatus = sinon.stub();
9048
+
9047
9049
  const state = {example: 'value'};
9048
9050
 
9049
9051
  await meeting.locusInfo.emitScoped(
@@ -9052,6 +9054,7 @@ describe('plugin-meetings', () => {
9052
9054
  {state}
9053
9055
  );
9054
9056
 
9057
+ assert.calledOnceWithExactly( meeting.webinar.updatePracticeSessionStatus, state);
9055
9058
  assert.calledWith(
9056
9059
  TriggerProxy.trigger,
9057
9060
  meeting,
@@ -262,5 +262,100 @@ describe('plugin-meetings', () => {
262
262
  testParams(false);
263
263
  });
264
264
  });
265
+
266
+ describe('#getAddMemberBody', () => {
267
+ it('returns the correct body with email address and roles', () => {
268
+ const options = {
269
+ invitee: {
270
+ emailAddress: 'test@example.com',
271
+ roles: ['role1', 'role2'],
272
+ },
273
+ alertIfActive: true,
274
+ };
275
+
276
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
277
+ invitees: [
278
+ {
279
+ address: 'test@example.com',
280
+ roles: ['role1', 'role2'],
281
+ },
282
+ ],
283
+ alertIfActive: true,
284
+ });
285
+ });
286
+
287
+ it('returns the correct body with phone number and no roles', () => {
288
+ const options = {
289
+ invitee: {
290
+ phoneNumber: '1234567890',
291
+ },
292
+ alertIfActive: false,
293
+ };
294
+
295
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
296
+ invitees: [
297
+ {
298
+ address: '1234567890',
299
+ },
300
+ ],
301
+ alertIfActive: false,
302
+ });
303
+ });
304
+
305
+ it('returns the correct body with fallback to email', () => {
306
+ const options = {
307
+ invitee: {
308
+ email: 'fallback@example.com',
309
+ },
310
+ alertIfActive: true,
311
+ };
312
+
313
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
314
+ invitees: [
315
+ {
316
+ address: 'fallback@example.com',
317
+ },
318
+ ],
319
+ alertIfActive: true,
320
+ });
321
+ });
322
+
323
+ it('handles missing `alertIfActive` gracefully', () => {
324
+ const options = {
325
+ invitee: {
326
+ emailAddress: 'test@example.com',
327
+ roles: ['role1'],
328
+ },
329
+ };
330
+
331
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
332
+ invitees: [
333
+ {
334
+ address: 'test@example.com',
335
+ roles: ['role1'],
336
+ },
337
+ ],
338
+ alertIfActive: undefined,
339
+ });
340
+ });
341
+
342
+ it('ignores roles if not provided', () => {
343
+ const options = {
344
+ invitee: {
345
+ emailAddress: 'test@example.com',
346
+ },
347
+ alertIfActive: false,
348
+ };
349
+
350
+ assert.deepEqual(MembersUtil.getAddMemberBody(options), {
351
+ invitees: [
352
+ {
353
+ address: 'test@example.com',
354
+ },
355
+ ],
356
+ alertIfActive: false,
357
+ });
358
+ });
359
+ });
265
360
  });
266
361
  });