update(chat): add option to disable private chat (#21459)
* update(chat): add option to disable private chat - Adds `public.chat.private` to settings.yml, defaults to true - Adds `privateChat` to disabledFeatures * backend validation for disabledFeatures=privateChat * refactor(settings): remove chat.private from settings.yml Will be kept only in disabledFeatures --------- Co-authored-by: Gustavo Trott <gustavo@trott.com.br>
This commit is contained in:
parent
82774b9a08
commit
e992862e40
@ -20,8 +20,13 @@ trait CreateGroupChatReqMsgHdlr extends SystemConfiguration {
|
||||
liveMeeting: LiveMeeting, bus: MessageBus): MeetingState2x = {
|
||||
log.debug("RECEIVED CREATE CHAT REQ MESSAGE")
|
||||
|
||||
var privateChatDisabled: Boolean = false
|
||||
var chatLocked: Boolean = false
|
||||
|
||||
if (msg.body.access == GroupChatAccess.PRIVATE) {
|
||||
privateChatDisabled = liveMeeting.props.meetingProp.disabledFeatures.contains("privateChat")
|
||||
}
|
||||
|
||||
for {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
} yield {
|
||||
@ -45,7 +50,12 @@ trait CreateGroupChatReqMsgHdlr extends SystemConfiguration {
|
||||
// Check if this message was sent while the lock settings was being changed.
|
||||
val isDelayedMessage = System.currentTimeMillis() - MeetingStatus2x.getPermissionsChangedOn(liveMeeting.status) < 5000
|
||||
|
||||
if (applyPermissionCheck && chatLocked && !isDelayedMessage) {
|
||||
if (privateChatDisabled ||
|
||||
(
|
||||
applyPermissionCheck &&
|
||||
chatLocked &&
|
||||
!isDelayedMessage
|
||||
)) {
|
||||
val meetingId = liveMeeting.props.meetingProp.intId
|
||||
val reason = "No permission to create a new group chat."
|
||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||
|
@ -25,6 +25,7 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
|
||||
val chatDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("chat")
|
||||
var privateChatDisabled: Boolean = false
|
||||
val replyChatMessageDisabled: Boolean = liveMeeting.props.meetingProp.disabledFeatures.contains("replyChatMessage")
|
||||
var chatLocked: Boolean = false
|
||||
var chatLockedForUser: Boolean = false
|
||||
@ -33,6 +34,10 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
|
||||
user <- Users2x.findWithIntId(liveMeeting.users2x, msg.header.userId)
|
||||
groupChat <- state.groupChats.find(msg.body.chatId)
|
||||
} yield {
|
||||
if (groupChat.access == GroupChatAccess.PRIVATE) {
|
||||
privateChatDisabled = liveMeeting.props.meetingProp.disabledFeatures.contains("privateChat")
|
||||
}
|
||||
|
||||
if (groupChat.access == GroupChatAccess.PUBLIC && user.userLockSettings.disablePublicChat && user.role != Roles.MODERATOR_ROLE) {
|
||||
chatLockedForUser = true
|
||||
}
|
||||
@ -54,7 +59,10 @@ trait SendGroupChatMessageMsgHdlr extends HandlerHelpers {
|
||||
}
|
||||
}
|
||||
|
||||
if (!chatDisabled && !(applyPermissionCheck && chatLocked) && !chatLockedForUser) {
|
||||
if (!chatDisabled &&
|
||||
!privateChatDisabled &&
|
||||
!(applyPermissionCheck && chatLocked) &&
|
||||
!chatLockedForUser) {
|
||||
val newState = for {
|
||||
sender <- GroupChatApp.findGroupChatUser(msg.header.userId, liveMeeting.users2x)
|
||||
chat <- state.groupChats.find(msg.body.chatId)
|
||||
|
@ -74,13 +74,13 @@ const intlMessages = defineMessages({
|
||||
description: 'locked element label',
|
||||
},
|
||||
hideCursorsLabel: {
|
||||
id: "app.lock-viewers.hideViewersCursor",
|
||||
id: 'app.lock-viewers.hideViewersCursor',
|
||||
description: 'label for other viewers cursor',
|
||||
},
|
||||
hideAnnotationsLabel: {
|
||||
id: "app.lock-viewers.hideAnnotationsLabel",
|
||||
id: 'app.lock-viewers.hideAnnotationsLabel',
|
||||
description: 'label for other viewers annotation',
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const propTypes = {
|
||||
@ -88,7 +88,7 @@ const propTypes = {
|
||||
intl: PropTypes.shape({
|
||||
formatMessage: PropTypes.func.isRequired,
|
||||
}).isRequired,
|
||||
meeting: PropTypes.object.isRequired,
|
||||
meeting: PropTypes.shape({}).isRequired,
|
||||
showToggleLabel: PropTypes.bool.isRequired,
|
||||
updateLockSettings: PropTypes.func.isRequired,
|
||||
updateWebcamsOnlyForModerator: PropTypes.func.isRequired,
|
||||
@ -106,6 +106,12 @@ class LockViewersComponent extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { closeModal } = this.props;
|
||||
|
||||
closeModal();
|
||||
}
|
||||
|
||||
toggleLockSettings(property) {
|
||||
const { lockSettingsProps } = this.state;
|
||||
|
||||
@ -129,18 +135,14 @@ class LockViewersComponent extends Component {
|
||||
displayLockStatus(status) {
|
||||
const { intl } = this.props;
|
||||
return (
|
||||
status && <Styled.ToggleLabel>
|
||||
status && (
|
||||
<Styled.ToggleLabel>
|
||||
{intl.formatMessage(intlMessages.lockedLabel)}
|
||||
</Styled.ToggleLabel>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { closeModal } = this.props;
|
||||
|
||||
closeModal();
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
closeModal,
|
||||
@ -152,6 +154,7 @@ class LockViewersComponent extends Component {
|
||||
onRequestClose,
|
||||
priority,
|
||||
isChatEnabled,
|
||||
isPrivateChatEnabled,
|
||||
isSharedNotesEnabled,
|
||||
} = this.props;
|
||||
|
||||
@ -257,7 +260,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.Row>
|
||||
|
||||
{isChatEnabled ? (
|
||||
<Fragment>
|
||||
<>
|
||||
<Styled.Row data-test="lockPublicChatItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
@ -283,34 +286,35 @@ class LockViewersComponent extends Component {
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
<Styled.Row data-test="lockPrivateChatItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
{intl.formatMessage(intlMessages.privateChatLable)}
|
||||
</Styled.Label>
|
||||
</Styled.FormElement>
|
||||
</Styled.Col>
|
||||
<Styled.Col>
|
||||
<Styled.FormElementRight>
|
||||
{this.displayLockStatus(lockSettingsProps.disablePrivateChat)}
|
||||
<Toggle
|
||||
icons={false}
|
||||
defaultChecked={lockSettingsProps.disablePrivateChat}
|
||||
onChange={() => {
|
||||
this.toggleLockSettings('disablePrivateChat');
|
||||
}}
|
||||
ariaLabel={intl.formatMessage(intlMessages.privateChatLable)}
|
||||
showToggleLabel={showToggleLabel}
|
||||
invertColors={invertColors}
|
||||
data-test="lockPrivateChat"
|
||||
/>
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
</Fragment>
|
||||
) : null
|
||||
}
|
||||
{isPrivateChatEnabled ? (
|
||||
<Styled.Row data-test="lockPrivateChatItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
<Styled.Label>
|
||||
{intl.formatMessage(intlMessages.privateChatLable)}
|
||||
</Styled.Label>
|
||||
</Styled.FormElement>
|
||||
</Styled.Col>
|
||||
<Styled.Col>
|
||||
<Styled.FormElementRight>
|
||||
{this.displayLockStatus(lockSettingsProps.disablePrivateChat)}
|
||||
<Toggle
|
||||
icons={false}
|
||||
defaultChecked={lockSettingsProps.disablePrivateChat}
|
||||
onChange={() => {
|
||||
this.toggleLockSettings('disablePrivateChat');
|
||||
}}
|
||||
ariaLabel={intl.formatMessage(intlMessages.privateChatLable)}
|
||||
showToggleLabel={showToggleLabel}
|
||||
invertColors={invertColors}
|
||||
data-test="lockPrivateChat"
|
||||
/>
|
||||
</Styled.FormElementRight>
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
{isSharedNotesEnabled
|
||||
? (
|
||||
<Styled.Row data-test="lockEditSharedNotesItem">
|
||||
@ -339,8 +343,7 @@ class LockViewersComponent extends Component {
|
||||
</Styled.Col>
|
||||
</Styled.Row>
|
||||
)
|
||||
: null
|
||||
}
|
||||
: null}
|
||||
<Styled.Row data-test="lockUserListItem">
|
||||
<Styled.Col aria-hidden="true">
|
||||
<Styled.FormElement>
|
||||
|
@ -4,7 +4,7 @@ import LockViewersComponent from './component';
|
||||
import useCurrentUser from '/imports/ui/core/hooks/useCurrentUser';
|
||||
import { SET_LOCK_SETTINGS_PROPS, SET_WEBCAM_ONLY_FOR_MODERATOR } from './mutations';
|
||||
import useMeeting from '../../core/hooks/useMeeting';
|
||||
import { useIsChatEnabled, useIsSharedNotesEnabled } from '../../services/features';
|
||||
import { useIsChatEnabled, useIsPrivateChatEnabled, useIsSharedNotesEnabled } from '../../services/features';
|
||||
|
||||
const LockViewersContainer = (props) => {
|
||||
const { data: currentUserData } = useCurrentUser((user) => ({
|
||||
@ -47,6 +47,7 @@ const LockViewersContainer = (props) => {
|
||||
usersPolicies: m.usersPolicies,
|
||||
}));
|
||||
const isChatEnabled = useIsChatEnabled();
|
||||
const isPrivateChatEnabled = useIsPrivateChatEnabled();
|
||||
const isSharedNotesEnabled = useIsSharedNotesEnabled();
|
||||
|
||||
return amIModerator && meeting && (
|
||||
@ -57,6 +58,7 @@ const LockViewersContainer = (props) => {
|
||||
showToggleLabel={false}
|
||||
meeting={meeting}
|
||||
isChatEnabled={isChatEnabled}
|
||||
isPrivateChatEnabled={isPrivateChatEnabled}
|
||||
isSharedNotesEnabled={isSharedNotesEnabled}
|
||||
{...props}
|
||||
/>
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
import { toggleMuteMicrophone } from '/imports/ui/components/audio/audio-graphql/audio-controls/input-stream-live-selector/service';
|
||||
import { useIsPrivateChatEnabled } from '/imports/ui/services/features';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
|
||||
export const isVoiceOnlyUser = (userId: string) => userId.toString().startsWith('v_');
|
||||
@ -31,7 +32,7 @@ export const generateActionsPermissions = (
|
||||
const parentRoomModerator = getFromUserSettings('bbb_parent_room_moderator', false);
|
||||
const isSubjectUserGuest = subjectUser.guest;
|
||||
const hasAuthority = currentUser.isModerator || amISubjectUser;
|
||||
const allowedToChatPrivately = !amISubjectUser && !isDialInUser;
|
||||
const allowedToChatPrivately = !amISubjectUser && !isDialInUser && useIsPrivateChatEnabled();
|
||||
const allowedToMuteAudio = hasAuthority
|
||||
&& subjectUserVoice?.joined
|
||||
&& !isMuted
|
||||
|
@ -131,3 +131,7 @@ export function useIsChatMessageReactionsEnabled() {
|
||||
&& window.meetingClientSettings.public.chat.toolbar.includes('reactions')
|
||||
);
|
||||
}
|
||||
|
||||
export function useIsPrivateChatEnabled() {
|
||||
return useDisabledFeatures().indexOf('privateChat') === -1;
|
||||
}
|
||||
|
@ -479,7 +479,7 @@ endWhenNoModeratorDelayInMinutes=1
|
||||
# List of features to disable (comma-separated)
|
||||
# https://docs.bigbluebutton.org/3.0/development/api/#create
|
||||
# Available options:
|
||||
# chat, sharedNotes, polls, screenshare, externalVideos, layouts, captions, liveTranscription,
|
||||
# chat, privateChat, sharedNotes, polls, screenshare, externalVideos, layouts, captions, liveTranscription,
|
||||
# breakoutRooms, importSharedNotesFromBreakoutRooms, importPresentationWithAnnotationsFromBreakoutRooms,
|
||||
# presentation, downloadPresentationWithAnnotations, downloadPresentationOriginalFile, downloadPresentationConvertedToPdf,
|
||||
# learningDashboard, learningDashboardDownloadSessionData,
|
||||
|
@ -350,7 +350,7 @@ const createEndpointTableData = [
|
||||
"name": "disabledFeatures",
|
||||
"required": false,
|
||||
"type": "String",
|
||||
"description": (<>List (comma-separated) of features to disable in a particular meeting. (added 2.5)<br /><br />Available options to disable:<br /><ul><li><code className="language-plaintext highlighter-rouge">breakoutRooms</code>- <b>Breakout Rooms</b> </li><li><code className="language-plaintext highlighter-rouge">captions</code>- <b>Closed Caption</b> </li><li><code className="language-plaintext highlighter-rouge">chat</code>- <b>Chat</b></li><li><code className="language-plaintext highlighter-rouge">downloadPresentationWithAnnotations</code>- <b>Annotated presentation download</b></li><li><code className="language-plaintext highlighter-rouge">snapshotOfCurrentSlide</code>- <b>Allow snapshot of the current slide</b></li><li><code className="language-plaintext highlighter-rouge">externalVideos</code>- <b>Share an external video</b> </li><li><code className="language-plaintext highlighter-rouge">importPresentationWithAnnotationsFromBreakoutRooms</code>- <b>Capture breakout presentation</b></li><li><code className="language-plaintext highlighter-rouge">importSharedNotesFromBreakoutRooms</code>- <b>Capture breakout shared notes</b></li><li><code className="language-plaintext highlighter-rouge">layouts</code>- <b>Layouts</b> (allow only default layout)</li><li><code className="language-plaintext highlighter-rouge">learningDashboard</code>- <b>Learning Analytics Dashboard</b></li><li><code className="language-plaintext highlighter-rouge">learningDashboardDownloadSessionData</code>- <b>Learning Analytics Dashboard Download Session Data (prevents the option to download)</b></li><li><code className="language-plaintext highlighter-rouge">polls</code>- <b>Polls</b> </li><li><code className="language-plaintext highlighter-rouge">screenshare</code>- <b>Screen Sharing</b></li><li><code className="language-plaintext highlighter-rouge">sharedNotes</code>- <b>Shared Notes</b></li><li><code className="language-plaintext highlighter-rouge">virtualBackgrounds</code>- <b>Virtual Backgrounds</b></li><li><code className="language-plaintext highlighter-rouge">customVirtualBackgrounds</code>- <b>Virtual Backgrounds Upload</b></li><li><code className="language-plaintext highlighter-rouge">liveTranscription</code>- <b>Live Transcription</b></li><li><code className="language-plaintext highlighter-rouge">presentation</code>- <b>Presentation</b></li><li><code className="language-plaintext highlighter-rouge">cameraAsContent</code>-<b>Enables/Disables camera as a content</b></li><li><code className="language-plaintext highlighter-rouge">timer</code>- <b>disables timer</b></li><li><code className="language-plaintext highlighter-rouge">infiniteWhiteboard</code>- <b>Infinite Whiteboard (added in BigBlueButton 3.0)</b></li></ul></>)
|
||||
"description": (<>List (comma-separated) of features to disable in a particular meeting. (added 2.5)<br /><br />Available options to disable:<br /><ul><li><code className="language-plaintext highlighter-rouge">breakoutRooms</code>- <b>Breakout Rooms</b> </li><li><code className="language-plaintext highlighter-rouge">captions</code>- <b>Closed Caption</b> </li><li><code className="language-plaintext highlighter-rouge">chat</code>- <b>Chat</b></li><li><code className="language-plaintext highlighter-rouge">privateChat</code>- <b>Private Chat</b></li><li><code className="language-plaintext highlighter-rouge">downloadPresentationWithAnnotations</code>- <b>Annotated presentation download</b></li><li><code className="language-plaintext highlighter-rouge">snapshotOfCurrentSlide</code>- <b>Allow snapshot of the current slide</b></li><li><code className="language-plaintext highlighter-rouge">externalVideos</code>- <b>Share an external video</b> </li><li><code className="language-plaintext highlighter-rouge">importPresentationWithAnnotationsFromBreakoutRooms</code>- <b>Capture breakout presentation</b></li><li><code className="language-plaintext highlighter-rouge">importSharedNotesFromBreakoutRooms</code>- <b>Capture breakout shared notes</b></li><li><code className="language-plaintext highlighter-rouge">layouts</code>- <b>Layouts</b> (allow only default layout)</li><li><code className="language-plaintext highlighter-rouge">learningDashboard</code>- <b>Learning Analytics Dashboard</b></li><li><code className="language-plaintext highlighter-rouge">learningDashboardDownloadSessionData</code>- <b>Learning Analytics Dashboard Download Session Data (prevents the option to download)</b></li><li><code className="language-plaintext highlighter-rouge">polls</code>- <b>Polls</b> </li><li><code className="language-plaintext highlighter-rouge">screenshare</code>- <b>Screen Sharing</b></li><li><code className="language-plaintext highlighter-rouge">sharedNotes</code>- <b>Shared Notes</b></li><li><code className="language-plaintext highlighter-rouge">virtualBackgrounds</code>- <b>Virtual Backgrounds</b></li><li><code className="language-plaintext highlighter-rouge">customVirtualBackgrounds</code>- <b>Virtual Backgrounds Upload</b></li><li><code className="language-plaintext highlighter-rouge">liveTranscription</code>- <b>Live Transcription</b></li><li><code className="language-plaintext highlighter-rouge">presentation</code>- <b>Presentation</b></li><li><code className="language-plaintext highlighter-rouge">cameraAsContent</code>-<b>Enables/Disables camera as a content</b></li><li><code className="language-plaintext highlighter-rouge">timer</code>- <b>disables timer</b></li><li><code className="language-plaintext highlighter-rouge">infiniteWhiteboard</code>- <b>Infinite Whiteboard (added in BigBlueButton 3.0)</b></li></ul></>)
|
||||
},
|
||||
{
|
||||
"name": "disabledFeaturesExclude",
|
||||
|
Loading…
Reference in New Issue
Block a user