Quellcode durchsuchen

feat(toolbar-buttons) Hide buttons disabled through JWT (#12261)

factor2
Horatiu Muresan vor 2 Jahren
Ursprung
Commit
a2d0492007
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden

+ 26
- 14
react/features/base/jwt/constants.ts Datei anzeigen

@@ -1,17 +1,29 @@
1 1
 /**
2 2
  * The list of supported meeting features to enable/disable through jwt.
3 3
  */
4
-export const MEET_FEATURES = [
5
-    'branding',
6
-    'calendar',
7
-    'callstats',
8
-    'livestreaming',
9
-    'lobby',
10
-    'moderation',
11
-    'outbound-call',
12
-    'recording',
13
-    'room',
14
-    'screen-sharing',
15
-    'sip-outbound-call',
16
-    'transcription'
17
-];
4
+export const MEET_FEATURES = {
5
+    BRANDING: 'branding',
6
+    CALENDAR: 'calendar',
7
+    CALLSTATS: 'callstats',
8
+    FLIP: 'flip',
9
+    INBOUND_CALL: 'inbound-call',
10
+    LIVESTREAMING: 'livestreaming',
11
+    LOBBY: 'lobby',
12
+    MODERATION: 'moderation',
13
+    OUTBOUND_CALL: 'outbound-call',
14
+    RECORDING: 'recording',
15
+    ROOM: 'room',
16
+    SCREEN_SHARING: 'screen-sharing',
17
+    SIP_INBOUND_CALL: 'sip-inbound-call',
18
+    SIP_OUTBOUND_CALL: 'sip-outbound-call',
19
+    TRANSCRIPTION: 'transcription'
20
+};
21
+
22
+/**
23
+ * A mapping between jwt features and toolbar buttons keys.
24
+ */
25
+export const FEATURES_TO_BUTTONS_MAPPING = {
26
+    'livestreaming': 'livestreaming',
27
+    'recording': 'recording',
28
+    'transcription': 'closedcaptions'
29
+};

+ 2
- 1
react/features/base/jwt/functions.ts Datei anzeigen

@@ -147,9 +147,10 @@ export function validateJwt(jwt: string) {
147 147
             errors.push('- `context` object is missing from the payload');
148 148
         } else if (context.features) {
149 149
             const { features } = context;
150
+            const meetFeatures = Object.values(MEET_FEATURES);
150 151
 
151 152
             Object.keys(features).forEach(feature => {
152
-                if (MEET_FEATURES.includes(feature)) {
153
+                if (meetFeatures.includes(feature)) {
153 154
                     const featureValue = features[feature];
154 155
 
155 156
                     // cannot use truthy or falsy because we need the exact value and type check.

+ 0
- 13
react/features/jaas/constants.ts Datei anzeigen

@@ -6,19 +6,6 @@ export const STATUSES = {
6 6
     BLOCKED: 'BLOCKED'
7 7
 };
8 8
 
9
-/**
10
- * Service features for JaaS users.
11
- */
12
-export const FEATURES = {
13
-    INBOUND_CALL: 'inbound-call',
14
-    OUTBOUND_CALL: 'outbound-call',
15
-    RECORDING: 'recording',
16
-    SIP_INBOUND_CALL: 'sip-inbound-call',
17
-    SIP_OUTBOUND_CALL: 'sip-outbound-call',
18
-    STREAMING: 'streaming',
19
-    TRANSCRIPTION: 'transcription'
20
-};
21
-
22 9
 /**
23 10
  * URL for displaying JaaS upgrade options.
24 11
  */

+ 2
- 2
react/features/recording/components/LiveStream/AbstractLiveStreamButton.js Datei anzeigen

@@ -1,13 +1,13 @@
1 1
 // @flow
2 2
 
3 3
 import { IconLiveStreaming } from '../../../base/icons';
4
+import { MEET_FEATURES } from '../../../base/jwt/constants';
4 5
 import { isJwtFeatureEnabled } from '../../../base/jwt/functions';
5 6
 import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
6 7
 import { isLocalParticipantModerator } from '../../../base/participants';
7 8
 import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
8 9
 import { isInBreakoutRoom } from '../../../breakout-rooms/functions';
9 10
 import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
10
-import { FEATURES } from '../../../jaas/constants';
11 11
 import { getActiveSession } from '../../functions';
12 12
 
13 13
 import { getLiveStreaming } from './functions';
@@ -85,7 +85,7 @@ export default class AbstractLiveStreamButton<P: Props> extends AbstractButton<P
85 85
     async _handleClick() {
86 86
         const { dispatch } = this.props;
87 87
 
88
-        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
88
+        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
89 89
 
90 90
         if (!dialogShown) {
91 91
             this._onHandleClick();

+ 2
- 2
react/features/recording/components/Recording/AbstractHighlightButton.js Datei anzeigen

@@ -4,9 +4,9 @@ import { Component } from 'react';
4 4
 
5 5
 import { getActiveSession, isHighlightMeetingMomentDisabled } from '../..';
6 6
 import { openDialog } from '../../../base/dialog';
7
+import { MEET_FEATURES } from '../../../base/jwt/constants';
7 8
 import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
8 9
 import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
9
-import { FEATURES } from '../../../jaas/constants';
10 10
 import {
11 11
     NOTIFICATION_TIMEOUT_TYPE,
12 12
     NOTIFICATION_TYPE,
@@ -79,7 +79,7 @@ export default class AbstractHighlightButton<P: Props> extends Component<P> {
79 79
                 customActionNameKey: [ 'localRecording.start' ],
80 80
                 customActionHandler: [ async () => {
81 81
                     dispatch(hideNotification(PROMPT_RECORDING_NOTIFICATION_ID));
82
-                    const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
82
+                    const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
83 83
 
84 84
                     if (!dialogShown) {
85 85
                         dispatch(openDialog(StartRecordingDialog));

+ 2
- 2
react/features/recording/components/Recording/AbstractRecordButton.js Datei anzeigen

@@ -5,10 +5,10 @@ import {
5 5
     sendAnalytics
6 6
 } from '../../../analytics';
7 7
 import { IconToggleRecording } from '../../../base/icons';
8
+import { MEET_FEATURES } from '../../../base/jwt/constants';
8 9
 import { JitsiRecordingConstants } from '../../../base/lib-jitsi-meet';
9 10
 import { AbstractButton, type AbstractButtonProps } from '../../../base/toolbox/components';
10 11
 import { maybeShowPremiumFeatureDialog } from '../../../jaas/actions';
11
-import { FEATURES } from '../../../jaas/constants';
12 12
 import { getActiveSession, getRecordButtonProps } from '../../functions';
13 13
 
14 14
 import LocalRecordingManager from './LocalRecordingManager';
@@ -91,7 +91,7 @@ export default class AbstractRecordButton<P: Props> extends AbstractButton<P, *>
91 91
                 'is_recording': _isRecordingRunning,
92 92
                 type: JitsiRecordingConstants.mode.FILE
93 93
             }));
94
-        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
94
+        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
95 95
 
96 96
         if (!dialogShown) {
97 97
             this._onHandleClick();

+ 2
- 2
react/features/recording/components/Recording/web/HighlightButton.tsx Datei anzeigen

@@ -9,6 +9,7 @@ import { StartRecordingDialog } from '../..';
9 9
 import { openDialog } from '../../../../base/dialog';
10 10
 import { translate } from '../../../../base/i18n/functions';
11 11
 import { IconHighlight } from '../../../../base/icons/svg';
12
+import { MEET_FEATURES } from '../../../../base/jwt/constants';
12 13
 import Label from '../../../../base/label/components/web/Label';
13 14
 import { connect } from '../../../../base/redux/functions';
14 15
 // @ts-ignore
@@ -16,7 +17,6 @@ import { Tooltip } from '../../../../base/tooltip';
16 17
 import BaseTheme from '../../../../base/ui/components/BaseTheme.web';
17 18
 // @ts-ignore
18 19
 import { maybeShowPremiumFeatureDialog } from '../../../../jaas/actions';
19
-import { FEATURES } from '../../../../jaas/constants';
20 20
 import AbstractHighlightButton, {
21 21
     type Props as AbstractProps,
22 22
     _abstractMapStateToProps
@@ -140,7 +140,7 @@ export class HighlightButton extends AbstractHighlightButton<Props, State> {
140 140
     async _onOpenDialog() {
141 141
         // @ts-ignore
142 142
         const { dispatch } = this.props;
143
-        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
143
+        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
144 144
 
145 145
         if (!dialogShown) {
146 146
             dispatch(openDialog(StartRecordingDialog));

+ 2
- 2
react/features/subtitles/components/AbstractClosedCaptionButton.js Datei anzeigen

@@ -1,10 +1,10 @@
1 1
 // @flow
2 2
 
3 3
 import { createToolbarEvent, sendAnalytics } from '../../analytics';
4
+import { MEET_FEATURES } from '../../base/jwt/constants';
4 5
 import { isLocalParticipantModerator } from '../../base/participants';
5 6
 import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
6 7
 import { maybeShowPremiumFeatureDialog } from '../../jaas/actions';
7
-import { FEATURES } from '../../jaas/constants';
8 8
 
9 9
 export type AbstractProps = AbstractButtonProps & {
10 10
 
@@ -61,7 +61,7 @@ export class AbstractClosedCaptionButton
61 61
                 'requesting_subtitles': Boolean(_requestingSubtitles)
62 62
             }));
63 63
 
64
-        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(FEATURES.RECORDING));
64
+        const dialogShown = await dispatch(maybeShowPremiumFeatureDialog(MEET_FEATURES.RECORDING));
65 65
 
66 66
         if (!dialogShown) {
67 67
             this._handleClickOpenLanguageSelector();

+ 12
- 3
react/features/toolbox/components/web/Toolbox.tsx Datei anzeigen

@@ -115,6 +115,7 @@ import {
115 115
 import { NOTIFY_CLICK_MODE, NOT_APPLICABLE, THRESHOLDS } from '../../constants';
116 116
 // @ts-ignore
117 117
 import { isDesktopShareButtonDisabled, isToolboxVisible } from '../../functions';
118
+import { getJwtDisabledButtons } from '../../functions.any';
118 119
 // @ts-ignore
119 120
 import DownloadButton from '../DownloadButton';
120 121
 // @ts-ignore
@@ -251,6 +252,11 @@ interface Props extends WithTranslation {
251 252
      */
252 253
     _isVpaasMeeting: boolean;
253 254
 
255
+    /**
256
+     * The array of toolbar buttons disabled through jwt features.
257
+     */
258
+    _jwtDisabledButons: string[];
259
+
254 260
     /**
255 261
      * The ID of the local participant.
256 262
      */
@@ -1009,10 +1015,10 @@ class Toolbox extends Component<Props> {
1009 1015
     _getVisibleButtons() {
1010 1016
         const {
1011 1017
             _clientWidth,
1012
-            _toolbarButtons
1018
+            _toolbarButtons,
1019
+            _jwtDisabledButons
1013 1020
         } = this.props;
1014 1021
 
1015
-
1016 1022
         const buttons = this._getAllButtons();
1017 1023
 
1018 1024
         this._setButtonsNotifyClickMode(buttons);
@@ -1027,7 +1033,9 @@ class Toolbox extends Component<Props> {
1027 1033
             ...order.map(key => buttons[key as keyof typeof buttons]),
1028 1034
             ...Object.values(buttons).filter((button, index) => !order.includes(keys[index]))
1029 1035
         ].filter(Boolean).filter(({ key, alias = NOT_APPLICABLE }) =>
1030
-            isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons));
1036
+            !_jwtDisabledButons.includes(key)
1037
+            && (isToolbarButtonEnabled(key, _toolbarButtons) || isToolbarButtonEnabled(alias, _toolbarButtons))
1038
+        );
1031 1039
 
1032 1040
         if (isHangupVisible) {
1033 1041
             sliceIndex -= 1;
@@ -1534,6 +1542,7 @@ function _mapStateToProps(state: IState, ownProps: Partial<Props>) {
1534 1542
         _isIosMobile: isIosMobileBrowser(),
1535 1543
         _isMobile: isMobileBrowser(),
1536 1544
         _isVpaasMeeting: isVpaasMeeting(state),
1545
+        _jwtDisabledButons: getJwtDisabledButtons(state),
1537 1546
         _hasSalesforce: isSalesforceEnabled(state),
1538 1547
         _hangupMenuVisible: hangupMenuVisible,
1539 1548
         _localParticipantID: localParticipant?.id,

+ 18
- 0
react/features/toolbox/functions.any.ts Datei anzeigen

@@ -1,4 +1,6 @@
1 1
 import { IState } from '../app/types';
2
+import { FEATURES_TO_BUTTONS_MAPPING } from '../base/jwt/constants';
3
+import { isJwtFeatureEnabled } from '../base/jwt/functions';
2 4
 
3 5
 /**
4 6
  * Indicates if the audio mute button is disabled or not.
@@ -12,3 +14,19 @@ export function isAudioMuteButtonDisabled(state: IState) {
12 14
 
13 15
     return Boolean(!available || startSilent || (muted && unmuteBlocked));
14 16
 }
17
+
18
+/**
19
+ * Returns the buttons corresponding to features disabled through jwt.
20
+ *
21
+ * @param {IState} state - The state from the Redux store.
22
+ * @returns {string[]} - The disabled by jwt buttons array.
23
+ */
24
+export function getJwtDisabledButtons(state: IState) {
25
+    return Object.keys(FEATURES_TO_BUTTONS_MAPPING).reduce((acc: string[], current: string) => {
26
+        if (!isJwtFeatureEnabled(state, current, true)) {
27
+            acc.push(current);
28
+        }
29
+
30
+        return acc;
31
+    }, []);
32
+}

Laden…
Abbrechen
Speichern