diff --git a/bbb-api-demo/src/main/webapp/demo_iframe.jsp b/bbb-api-demo/src/main/webapp/demo_iframe.jsp index 3cd02f6fda..e8aafb61d2 100644 --- a/bbb-api-demo/src/main/webapp/demo_iframe.jsp +++ b/bbb-api-demo/src/main/webapp/demo_iframe.jsp @@ -133,10 +133,11 @@ muteButton.id = 'muteButton'; function getInitialState() { document.getElementById('client-content').contentWindow.postMessage('c_recording_status', '*'); - document.getElementById('client-content').contentWindow.postMessage('c_mute_status', '*'); + document.getElementById('client-content').contentWindow.postMessage('get_audio_joined_status', '*'); } function handleMessage(e) { + let neverJoinedAudio = true; switch (e) { case 'readyToConnect': { // get initial state @@ -160,11 +161,18 @@ function handleMessage(e) { case 'notInAudio': { muteButton.innerHTML = 'Not in audio'; document.getElementById('muteButton').disabled = true; + if (neverJoinedAudio) { + // poll every 1 sec to check if we joined audio + setTimeout(function(){ + document.getElementById('client-content').contentWindow.postMessage('get_audio_joined_status', '*'); + }, 1000);} break; } case 'joinedAudio': { + neverJoinedAudio = false; muteButton.innerHTML = ''; - document.getElementById('muteButton').disabled = false; getInitialState(); + document.getElementById('muteButton').disabled = false; + document.getElementById('client-content').contentWindow.postMessage('c_mute_status', '*'); break; } default: console.log('neither', { e }); diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods.js b/bigbluebutton-html5/imports/api/meetings/server/methods.js old mode 100644 new mode 100755 index 74401c1b15..960ef8082e --- a/bigbluebutton-html5/imports/api/meetings/server/methods.js +++ b/bigbluebutton-html5/imports/api/meetings/server/methods.js @@ -2,9 +2,13 @@ import { Meteor } from 'meteor/meteor'; import endMeeting from './methods/endMeeting'; import toggleRecording from './methods/toggleRecording'; import transferUser from './methods/transferUser'; +import toggleLockSettings from './methods/toggleLockSettings'; +import toggleWebcamsOnlyForModerator from './methods/toggleWebcamsOnlyForModerator'; Meteor.methods({ endMeeting, toggleRecording, + toggleLockSettings, transferUser, + toggleWebcamsOnlyForModerator, }); diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js new file mode 100755 index 0000000000..ee59cf102e --- /dev/null +++ b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleLockSettings.js @@ -0,0 +1,37 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import RedisPubSub from '/imports/startup/server/redis'; + +export default function toggleLockSettings(credentials, meeting) { + const REDIS_CONFIG = Meteor.settings.private.redis; + const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; + const EVENT_NAME = 'ChangeLockSettingsInMeetingCmdMsg'; + + const { meetingId, requesterUserId } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(meeting.lockSettingsProp, { + disableCam: Boolean, + disableMic: Boolean, + disablePrivChat: Boolean, + disablePubChat: Boolean, + lockedLayout: Boolean, + lockOnJoin: Boolean, + lockOnJoinConfigurable: Boolean, + setBy: String, + }); + + const payload = { + disableCam: meeting.lockSettingsProp.disableCam, + disableMic: meeting.lockSettingsProp.disableMic, + disablePrivChat: meeting.lockSettingsProp.disablePrivChat, + disablePubChat: meeting.lockSettingsProp.disablePubChat, + lockedLayout: meeting.lockSettingsProp.lockedLayout, + lockOnJoin: meeting.lockSettingsProp.lockOnJoin, + lockOnJoinConfigurable: meeting.lockSettingsProp.lockOnJoinConfigurable, + setBy: requesterUserId, + }; + + RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js new file mode 100755 index 0000000000..75f052de76 --- /dev/null +++ b/bigbluebutton-html5/imports/api/meetings/server/methods/toggleWebcamsOnlyForModerator.js @@ -0,0 +1,22 @@ +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import RedisPubSub from '/imports/startup/server/redis'; + +export default function toggleWebcamsOnlyForModerator(credentials, meeting) { + const REDIS_CONFIG = Meteor.settings.private.redis; + const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; + const EVENT_NAME = 'UpdateWebcamsOnlyForModeratorCmdMsg'; + + const { meetingId, requesterUserId } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(meeting.usersProp.webcamsOnlyForModerator, Boolean); + + const payload = { + webcamsOnlyForModerator: meeting.usersProp.webcamsOnlyForModerator, + setBy: requesterUserId, + }; + + RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload); +} diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js index a8023da362..f8011fd0d3 100644 --- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js +++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/addMeeting.js @@ -69,10 +69,22 @@ export default function addMeeting(meeting) { meetingId, }; + const lockSettingsProp = { + disableCam: false, + disableMic: false, + disablePrivChat: false, + disablePubChat: false, + lockOnJoin: true, + lockOnJoinConfigurable: false, + lockedLayout: false, + setBy: 'temp', + }; + const modifier = { $set: Object.assign( { meetingId }, flat(meeting, { safe: true }), + { lockSettingsProp }, ), }; diff --git a/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js b/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js index a5377f1773..be28a30199 100644 --- a/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js +++ b/bigbluebutton-html5/imports/api/voice-users/server/methods/muteToggle.js @@ -8,10 +8,6 @@ export default function muteToggle(credentials, userId) { const REDIS_CONFIG = Meteor.settings.private.redis; const CHANNEL = REDIS_CONFIG.channels.toAkkaApps; const EVENT_NAME = 'MuteUserCmdMsg'; - const APP_CONFIG = Meteor.settings.public.app; - const ALLOW_MODERATOR_TO_UNMUTE_AUDIO = APP_CONFIG.allowModeratorToUnmuteAudio; - const USER_CONFIG = Meteor.settings.public.user; - const ROLE_MODERATOR = USER_CONFIG.role_moderator; const { meetingId, requesterUserId } = credentials; @@ -32,15 +28,6 @@ export default function muteToggle(credentials, userId) { const { listenOnly, muted } = voiceUser; if (listenOnly) return; - const isModerator = requester.roles.includes(ROLE_MODERATOR.toLowerCase()); - const isNotHimself = requesterUserId !== userId; - - // the ability for a moderator to unmute other users is configurable (on/off) - if (!ALLOW_MODERATOR_TO_UNMUTE_AUDIO && - isModerator && - muted && - isNotHimself) return; - const payload = { userId, mutedBy: requesterUserId, diff --git a/bigbluebutton-html5/imports/startup/server/logger.js b/bigbluebutton-html5/imports/startup/server/logger.js old mode 100755 new mode 100644 diff --git a/bigbluebutton-html5/imports/ui/components/app/component.jsx b/bigbluebutton-html5/imports/ui/components/app/component.jsx index 81ac621100..526ec18f65 100755 --- a/bigbluebutton-html5/imports/ui/components/app/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/component.jsx @@ -2,8 +2,10 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { throttle } from 'lodash'; import { defineMessages, injectIntl, intlShape } from 'react-intl'; +import { Session } from 'meteor/session'; import Modal from 'react-modal'; import browser from 'browser-detect'; +import PanelManager from '/imports/ui/components/panel-manager/component'; import PollingContainer from '/imports/ui/components/polling/container'; import ToastContainer from '../toast/container'; import ModalContainer from '../modal/container'; @@ -11,8 +13,6 @@ import NotificationsBarContainer from '../notifications-bar/container'; import AudioContainer from '../audio/container'; import ChatAlertContainer from '../chat/alert/container'; import { styles } from './styles'; -import PanelManager from '/imports/ui/components/panel-manager/component'; -import { Session } from 'meteor/session'; const MOBILE_MEDIA = 'only screen and (max-width: 40em)'; @@ -188,7 +188,7 @@ class App extends Component { render() { const { - customStyle, customStyleUrl, + customStyle, customStyleUrl, micsLocked, } = this.props; return ( @@ -205,11 +205,11 @@ class App extends Component { - + {micsLocked ? null : } - { customStyleUrl ? : null } - { customStyle ? : null } + {customStyleUrl ? : null} + {customStyle ? : null} ); } diff --git a/bigbluebutton-html5/imports/ui/components/app/container.jsx b/bigbluebutton-html5/imports/ui/components/app/container.jsx index 964df9be3d..ef095ec724 100755 --- a/bigbluebutton-html5/imports/ui/components/app/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/app/container.jsx @@ -69,6 +69,7 @@ const AppContainer = (props) => { export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) => { const currentUser = Users.findOne({ userId: Auth.userID }); + const meeting = Meetings.findOne({ meetingId: Auth.meetingID }); const isMeetingBreakout = meetingIsBreakout(); if (!currentUser.approved) { @@ -116,6 +117,7 @@ export default injectIntl(withModalMounter(withTracker(({ intl, baseControls }) chatIsOpen: Session.equals('openPanel', 'chat'), openPanel: Session.get('openPanel'), userListIsOpen: !Session.equals('openPanel', ''), + micsLocked: (currentUser.locked && meeting.lockSettingsProp.disableMic), }; })(AppContainer))); diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx index b2334ede83..6211484d91 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/container.jsx @@ -3,6 +3,9 @@ import { withTracker } from 'meteor/react-meteor-data'; import { withModalMounter } from '/imports/ui/components/modal/service'; import AudioManager from '/imports/ui/services/audio-manager'; import { makeCall } from '/imports/ui/services/api'; +import Users from '/imports/api/users/'; +import Meetings from '/imports/api/meetings'; +import Auth from '/imports/ui/services/auth'; import AudioControls from './component'; import AudioModalContainer from '../audio-modal/container'; import Service from '../service'; @@ -15,11 +18,12 @@ const processToggleMuteFromOutside = (e) => { makeCall('toggleSelfVoice'); break; } + case 'get_audio_joined_status': { + const audioJoinedState = AudioManager.isConnected ? 'joinedAudio' : 'notInAudio'; + this.window.parent.postMessage({ response: audioJoinedState }, '*'); + break; + } case 'c_mute_status': { - if (!AudioManager.isUsingAudio()) { - this.window.parent.postMessage({ response: 'notInAudio' }, '*'); - return; - } const muteState = AudioManager.isMuted ? 'selfMuted' : 'selfUnmuted'; this.window.parent.postMessage({ response: muteState }, '*'); break; @@ -39,6 +43,12 @@ export default withModalMounter(withTracker(({ mountModal }) => disable: Service.isConnecting() || Service.isHangingUp(), glow: Service.isTalking() && !Service.isMuted(), handleToggleMuteMicrophone: () => Service.toggleMuteMicrophone(), - handleJoinAudio: () => mountModal(), + handleJoinAudio: () => { + const meeting = Meetings.findOne({ meetingId: Auth.meetingID }); + const currentUser = Users.findOne({ userId: Auth.userID }); + const micsLocked = (currentUser.locked && meeting.lockSettingsProp.disableMic); + + return micsLocked ? Service.joinListenOnly() : mountModal(); + }, handleLeaveAudio: () => Service.exitAudio(), }))(AudioControlsContainer)); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx b/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx new file mode 100755 index 0000000000..7c89ec1f1b --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/component.jsx @@ -0,0 +1,251 @@ +import React, { Component } from 'react'; +import { defineMessages, injectIntl } from 'react-intl'; +import Button from '/imports/ui/components/button/component'; +import Toggle from '/imports/ui/components/switch/component'; +import cx from 'classnames'; +import ModalBase from '/imports/ui/components/modal/base/component'; +import { styles } from './styles'; + +const intlMessages = defineMessages({ + lockViewersTitle: { + id: 'app.lock-viewers.title', + description: 'lock-viewers title', + }, + closeLabel: { + id: 'app.shortcut-help.closeLabel', + description: 'label for close button', + }, + closeDesc: { + id: 'app.shortcut-help.closeDesc', + description: 'description for close button', + }, + lockViewersDescription: { + id: 'app.lock-viewers.description', + description: 'description for lock viewers feature', + }, + featuresLable: { + id: 'app.lock-viewers.featuresLable', + description: 'features label', + }, + lockStatusLabel: { + id: 'app.lock-viewers.lockStatusLabel', + description: 'description for close button', + }, + webcamLabel: { + id: 'app.lock-viewers.webcamLabel', + description: 'description for close button', + }, + otherViewersWebcamLabel: { + id: 'app.lock-viewers.otherViewersWebcamLabel', + description: 'description for close button', + }, + microphoneLable: { + id: 'app.lock-viewers.microphoneLable', + description: 'description for close button', + }, + publicChatLabel: { + id: 'app.lock-viewers.PublicChatLabel', + description: 'description for close button', + }, + privateChatLable: { + id: 'app.lock-viewers.PrivateChatLable', + description: 'description for close button', + }, + layoutLable: { + id: 'app.lock-viewers.Layout', + description: 'description for close button', + }, +}); + +class LockViewersComponent extends Component { + constructor(props) { + super(props); + const { + closeModal, + toggleLockSettings, + toggleWebcamsOnlyForModerator, + } = props; + + this.closeModal = closeModal; + this.toggleLockSettings = toggleLockSettings; + this.toggleWebcamsOnlyForModerator = toggleWebcamsOnlyForModerator; + } + + render() { + const { intl, meeting } = this.props; + + return ( + + +
+
+
{intl.formatMessage(intlMessages.lockViewersTitle)}
+
+
+ {`${intl.formatMessage(intlMessages.lockViewersDescription)}`} +
+ +
+
+
{intl.formatMessage(intlMessages.featuresLable)}
+
{intl.formatMessage(intlMessages.lockStatusLabel)}
+
+
+ +
+
+ { + meeting.lockSettingsProp.disableCam = + !meeting.lockSettingsProp.disableCam; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.webcamLabel)} + /> +
+
+
+
+ +
+
+ { + meeting.usersProp.webcamsOnlyForModerator = + !meeting.usersProp.webcamsOnlyForModerator; + this.toggleWebcamsOnlyForModerator(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.otherViewersWebcamLabel)} + /> +
+
+
+
+ +
+
+ { + meeting.lockSettingsProp.disableMic = + !meeting.lockSettingsProp.disableMic; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.microphoneLable)} + /> +
+
+
+
+ +
+
+ { + meeting.lockSettingsProp.disablePubChat = + !meeting.lockSettingsProp.disablePubChat; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.publicChatLabel)} + /> +
+
+
+
+ +
+
+ { + meeting.lockSettingsProp.disablePrivChat = + !meeting.lockSettingsProp.disablePrivChat; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.privateChatLable)} + /> +
+
+
+
+ +
+
+ { + meeting.lockSettingsProp.lockedLayout = + !meeting.lockSettingsProp.lockedLayout; + this.toggleLockSettings(meeting); + }} + ariaLabel={intl.formatMessage(intlMessages.layoutLable)} + /> +
+
+
+
+
+
+ ); + } +} + +export default injectIntl(LockViewersComponent); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx b/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx new file mode 100755 index 0000000000..2ce4edcc89 --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/container.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { withTracker } from 'meteor/react-meteor-data'; +import { withModalMounter } from '/imports/ui/components/modal/service'; +import { makeCall } from '/imports/ui/services/api'; +import Meetings from '/imports/api/meetings'; +import Auth from '/imports/ui/services/auth'; +import LockViewersComponent from './component'; + +const LockViewersContainer = props => ; + +export default withModalMounter(withTracker(({ mountModal }) => ({ + closeModal() { + mountModal(null); + }, + + toggleLockSettings(meeting) { + makeCall('toggleLockSettings', meeting); + }, + + toggleWebcamsOnlyForModerator(meeting) { + makeCall('toggleWebcamsOnlyForModerator', meeting); + }, + meeting: (Meetings.findOne({ meetingId: Auth.meetingID })), +}))(LockViewersContainer)); diff --git a/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss b/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss new file mode 100755 index 0000000000..078b36e6da --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/lock-viewers/styles.scss @@ -0,0 +1,118 @@ +@import '/imports/ui/stylesheets/mixins/focus'; +@import '/imports/ui/stylesheets/variables/_all'; +@import "/imports/ui/components/modal/simple/styles"; + +:root { + --modal-margin: 3rem; + --title-position-left: 2.2rem; + --closeBtn-position-left: 2.5rem; +} + +.title { + position: relative; + left: var(--title-position-left); + color: var(--color-gray-dark); + font-weight: bold; + font-size: var(--font-size-large); + text-align: center; +} + +.form { + display: flex; + flex-flow: column; +} + +.container { + margin: var(--modal-margin); + margin-bottom: var(--lg-padding-x); +} + +.subHeader { + display: flex; + flex-flow: row; + flex-grow: 1; + justify-content: space-between; + color: var(--color-gray-label); + font-size: var(--font-size-base); + margin-bottom: var(--title-position-left); +} + +.modal { + @extend .modal; + padding: var(--jumbo-padding-y); +} + +.overlay { + @extend .overlay; +} + +.description { + text-align: center; + color: var(--color-gray); + margin-bottom: var(--jumbo-padding-y) +} + +.row { + display: flex; + flex-flow: row; + flex-grow: 1; + justify-content: space-between; + margin-bottom: var(--md-padding-x); +} + +.col { + display: flex; + flex-grow: 1; + flex-basis: 0; + margin-right: var(--md-padding-x); +} + +.label { + color: var(--color-gray-label); + font-size: var(--font-size-small); + margin-bottom: var(--lg-padding-y); +} + +.formElement { + position: relative; + display: flex; + flex-flow: column; + flex-grow: 1; +} + +.pullContentRight { + display: flex; + justify-content: flex-end; + flex-flow: row; +} + +.bold { + font-weight: bold; +} + +.closeBtn { + position: relative; + background-color: var(--color-white); + left: var(--closeBtn-position-left); + bottom: var(--closeBtn-position-left); + + i { + color: var(--color-gray-light); + } + + &:focus, + &:hover { + background-color: var(--color-gray-lighter); + i { + color: var(--color-gray); + } + } +} + +.header { + margin: 0; + padding: 0; + border: none; + line-height: var(--title-position-left); + margin-bottom: var(--lg-padding-y); +} diff --git a/bigbluebutton-html5/imports/ui/components/user-list/service.js b/bigbluebutton-html5/imports/ui/components/user-list/service.js index 5ee0883dcf..3678f7d61d 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/service.js +++ b/bigbluebutton-html5/imports/ui/components/user-list/service.js @@ -12,9 +12,6 @@ import { makeCall } from '/imports/ui/services/api'; import _ from 'lodash'; import KEY_CODES from '/imports/utils/keyCodes'; -const APP_CONFIG = Meteor.settings.public.app; -const ALLOW_MODERATOR_TO_UNMUTE_AUDIO = APP_CONFIG.allowModeratorToUnmuteAudio; - const CHAT_CONFIG = Meteor.settings.public.chat; const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id; @@ -277,7 +274,7 @@ const getAvailableActions = (currentUser, user, isBreakoutRoom) => { && user.isVoiceUser && !user.isListenOnly && user.isMuted - && (ALLOW_MODERATOR_TO_UNMUTE_AUDIO || user.isCurrent); + && user.isCurrent; const allowedToResetStatus = hasAuthority && user.emoji.status !== EMOJI_STATUSES.none diff --git a/bigbluebutton-html5/imports/ui/components/user-list/styles.scss b/bigbluebutton-html5/imports/ui/components/user-list/styles.scss index d8de801266..50e54ffaf1 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/user-list/styles.scss @@ -121,6 +121,11 @@ color: var(--color-gray-light); } +.userListColumn { + @extend %flex-column; + min-height: 0; +} + .enter, .appear { opacity: 0.01; diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/styles.scss b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/styles.scss index 6ab7b7e20f..6c671c9f3a 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/styles.scss +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/styles.scss @@ -12,7 +12,8 @@ .container{ display: flex; align-items: center; - margin-bottom: .3rem; + margin-bottom: var(--lg-padding-y); + margin-top: var(--sm-padding-x); } .scrollableList { diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx index b3907e9329..2009826c84 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/component.jsx @@ -175,7 +175,7 @@ class UserParticipants extends Component { } = this.props; return ( -
+
{ !compact ?
diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx index 3e689940ef..69c2551259 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/component.jsx @@ -9,6 +9,7 @@ import DropdownTrigger from '/imports/ui/components/dropdown/trigger/component'; import DropdownContent from '/imports/ui/components/dropdown/content/component'; import DropdownList from '/imports/ui/components/dropdown/list/component'; import DropdownListItem from '/imports/ui/components/dropdown/list/item/component'; +import LockViewersContainer from '/imports/ui/components/lock-viewers/container'; import { styles } from './styles'; const propTypes = { @@ -19,7 +20,6 @@ const propTypes = { toggleMuteAllUsers: PropTypes.func.isRequired, toggleMuteAllUsersExceptPresenter: PropTypes.func.isRequired, toggleStatus: PropTypes.func.isRequired, - toggleLockView: PropTypes.func.isRequired, }; const intlMessages = defineMessages({ @@ -83,7 +83,8 @@ class UserOptions extends Component { } componentWillMount() { - const { intl, isMeetingMuted } = this.props; + const { intl, isMeetingMuted, mountModal } = this.props; + this.menuItems = _.compact([ ( mountModal()} />), ]); diff --git a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx index 59561dab0d..cf5af07ef7 100755 --- a/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/user-list/user-list-content/user-participants/user-options/container.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import logger from '/imports/startup/client/logger'; import Auth from '/imports/ui/services/auth'; import mapUser from '/imports/ui/services/user/mapUser'; import Users from '/imports/api/users/'; @@ -26,7 +25,6 @@ export default class UserOptionsContainer extends Component { this.muteMeeting = this.muteMeeting.bind(this); this.muteAllUsersExceptPresenter = this.muteAllUsersExceptPresenter.bind(this); - this.handleLockView = this.handleLockView.bind(this); this.handleClearStatus = this.handleClearStatus.bind(this); } @@ -44,11 +42,6 @@ export default class UserOptionsContainer extends Component { muteAllExceptPresenter(currentUser.userId); } - handleLockView() { - // Temporary lock method, will be changed in future PR - logger.info('handleLockView function'); - } - handleClearStatus() { const { users, setEmojiStatus } = this.props; @@ -71,7 +64,6 @@ export default class UserOptionsContainer extends Component { : null diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx index 1c7fe511e3..24095302e5 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/component.jsx @@ -388,7 +388,7 @@ class VideoProvider extends Component { } async createWebRTCPeer(id, shareWebcam) { - const { meetingId, sessionToken } = this.props; + const { meetingId, sessionToken, voiceBridge } = this.props; let iceServers = []; try { @@ -448,6 +448,7 @@ class VideoProvider extends Component { sdpOffer: offerSdp, cameraId: id, meetingId, + voiceBridge, }; this.sendMessage(message); diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/container.jsx b/bigbluebutton-html5/imports/ui/components/video-provider/container.jsx index 12bab47d13..eb6bbd51d1 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/container.jsx +++ b/bigbluebutton-html5/imports/ui/components/video-provider/container.jsx @@ -14,4 +14,5 @@ export default withTracker(() => ({ sessionToken: VideoService.sessionToken(), userName: VideoService.userName(), enableVideoStats: getFromUserSettings('enableVideoStats', Meteor.settings.public.kurento.enableVideoStats), + voiceBridge: VideoService.voiceBridge(), }))(VideoProviderContainer); diff --git a/bigbluebutton-html5/imports/ui/components/video-provider/service.js b/bigbluebutton-html5/imports/ui/components/video-provider/service.js index 5c672116d7..0637da6234 100755 --- a/bigbluebutton-html5/imports/ui/components/video-provider/service.js +++ b/bigbluebutton-html5/imports/ui/components/video-provider/service.js @@ -126,6 +126,11 @@ class VideoService { return Auth.sessionToken; } + voiceBridge() { + const voiceBridge = Meetings.findOne({ meetingId: Auth.meetingID }).voiceProp.voiceConf; + return voiceBridge; + } + isConnected() { return this.isConnected; } @@ -157,4 +162,5 @@ export default { meetingId: () => videoService.meetingId(), getAllUsersVideo: () => videoService.getAllUsersVideo(), sessionToken: () => videoService.sessionToken(), + voiceBridge: () => videoService.voiceBridge(), }; diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml index 195bbb60d4..e5d6ce1ded 100755 --- a/bigbluebutton-html5/private/config/settings.yml +++ b/bigbluebutton-html5/private/config/settings.yml @@ -75,7 +75,6 @@ public: branding: displayBrandingArea: false allowHTML5Moderator: true - allowModeratorToUnmuteAudio: true httpsConnection: false connectionTimeout: 60000 showHelpButton: true diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json index 7e39055685..abc96fb5fd 100755 --- a/bigbluebutton-html5/private/locales/en.json +++ b/bigbluebutton-html5/private/locales/en.json @@ -359,6 +359,16 @@ "app.shortcut-help.closePrivateChat": "Close Private Chat", "app.shortcut-help.openActions": "Open Actions Menu", "app.shortcut-help.openStatus": "Open Status Menu", + "app.lock-viewers.title": "Lock Viewers", + "app.lock-viewers.description": "These options enable you to restrict certain features available to viewers, such as locking out their ability to use private chat. (These restrictions do no apply to moderators)", + "app.lock-viewers.featuresLable": "Feature", + "app.lock-viewers.lockStatusLabel": "Locked Status", + "app.lock-viewers.webcamLabel": "Webcam", + "app.lock-viewers.otherViewersWebcamLabel": "See other viewsers webcams", + "app.lock-viewers.microphoneLable": "Microphone", + "app.lock-viewers.PublicChatLabel": "Public Chat", + "app.lock-viewers.PrivateChatLable": "Private Chat", + "app.lock-viewers.Layout": "Layout", "app.videoPreview.cameraLabel": "Camera", "app.videoPreview.cancelLabel": "Cancel", "app.videoPreview.closeLabel": "Close", diff --git a/build_script.sh b/build_script.sh index 42265a3dba..a83ccde4ea 100755 --- a/build_script.sh +++ b/build_script.sh @@ -8,8 +8,17 @@ if [[ $files = *"bigbluebutton-html5"* ]]; then meteor npm install if [ $1 = linter ] then + html5_files="" + list=$(echo $files | tr " " "\n") + for file in $list + do + if [[ $file = bigbluebutton-html5* ]] ; then + html5_files+=" $file" + fi + done + cd .. - bigbluebutton-html5/node_modules/.bin/eslint --ext .jsx,.js $files + bigbluebutton-html5/node_modules/.bin/eslint --ext .jsx,.js $html5_files elif [ $1 = acceptance_tests ] then {