Add users-settings collection and handle dynamic configuration
This commit is contained in:
parent
45cd830f96
commit
4c35608c2b
@ -2,6 +2,7 @@ import Meetings from '/imports/api/meetings';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
import clearUsers from '/imports/api/users/server/modifiers/clearUsers';
|
||||
import clearUsersSettings from '/imports/api/users-settings/server/modifiers/clearUsersSettings';
|
||||
import clearGroupChat from '/imports/api/group-chat/server/modifiers/clearGroupChat';
|
||||
import clearBreakouts from '/imports/api/breakouts/server/modifiers/clearBreakouts';
|
||||
import clearAnnotations from '/imports/api/annotations/server/modifiers/clearAnnotations';
|
||||
@ -21,6 +22,7 @@ export default function removeMeeting(meetingId) {
|
||||
clearAnnotations(meetingId);
|
||||
clearSlides(meetingId);
|
||||
clearUsers(meetingId);
|
||||
clearUsersSettings(meetingId);
|
||||
clearVoiceUsers(meetingId);
|
||||
|
||||
return Logger.info(`Cleared Meetings with id ${meetingId}`);
|
||||
|
11
bigbluebutton-html5/imports/api/users-settings/index.js
Normal file
11
bigbluebutton-html5/imports/api/users-settings/index.js
Normal file
@ -0,0 +1,11 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
const UserSettings = new Mongo.Collection('users-settings');
|
||||
|
||||
if (Meteor.isServer) {
|
||||
UserSettings._ensureIndex({
|
||||
meetingId: 1, userId: 1,
|
||||
});
|
||||
}
|
||||
|
||||
export default UserSettings;
|
@ -0,0 +1,2 @@
|
||||
import './methods';
|
||||
import './publishers';
|
@ -0,0 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import addUserSettings from './methods/addUserSettings';
|
||||
|
||||
Meteor.methods({
|
||||
addUserSettings,
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import addUserSetting from '/imports/api/users-settings/server/modifiers/addUserSetting';
|
||||
|
||||
export default function addUserSettings(credentials, meetingId, userId, setting, value) {
|
||||
check(meetingId, String);
|
||||
check(userId, String);
|
||||
check(setting, String);
|
||||
check(value, Match.Any);
|
||||
|
||||
return addUserSetting(meetingId, userId, setting, value);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
import { check } from 'meteor/check';
|
||||
import UserSettings from '/imports/api/users-settings';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function addUserSetting(meetingId, userId, setting, value) {
|
||||
check(meetingId, String);
|
||||
check(userId, String);
|
||||
check(setting, String);
|
||||
check(value, Match.Any);
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
userId,
|
||||
setting,
|
||||
};
|
||||
const modifier = {
|
||||
$set: {
|
||||
meetingId,
|
||||
userId,
|
||||
setting,
|
||||
value,
|
||||
},
|
||||
};
|
||||
|
||||
const cb = (err) => {
|
||||
if (err) {
|
||||
return Logger.error(`Adding user setting to collection: ${err}`);
|
||||
}
|
||||
|
||||
return Logger.verbose(`Upserted user setting for meetingId=${meetingId} userId=${userId} setting=${setting}`);
|
||||
};
|
||||
|
||||
return UserSettings.upsert(selector, modifier, cb);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import UserSettings from '/imports/api/users-settings';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
export default function clearUsersSettings(meetingId) {
|
||||
return UserSettings.remove({ meetingId }, Logger.info(`Cleared User Settings (${meetingId})`));
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import UserSettings from '/imports/api/users-settings';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function userSettings(credentials) {
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
|
||||
check(meetingId, String);
|
||||
check(requesterUserId, String);
|
||||
|
||||
Logger.info(`Publishing user settings for user=${requesterUserId}`);
|
||||
|
||||
return UserSettings.find({ meetingId, userId: requesterUserId });
|
||||
}
|
||||
|
||||
function publish(...args) {
|
||||
const boundUserSettings = userSettings.bind(this);
|
||||
return mapToAcl('subscriptions.users-settings', boundUserSettings)(args);
|
||||
}
|
||||
|
||||
Meteor.publish('users-settings', publish);
|
@ -1,7 +1,7 @@
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import SessionStorage from '/imports/ui/services/storage/session';
|
||||
import { setCustomLogoUrl } from '/imports/ui/components/user-list/service';
|
||||
import { log } from '/imports/ui/services/api';
|
||||
import { log, makeCall } from '/imports/ui/services/api';
|
||||
import deviceInfo from '/imports/utils/deviceInfo';
|
||||
import logger from '/imports/startup/client/logger';
|
||||
|
||||
@ -67,6 +67,21 @@ export function joinRouteHandler(nextState, replace, callback) {
|
||||
|
||||
const handledHTML5Parameters = [
|
||||
'html5recordingbot',
|
||||
// APP
|
||||
'autoJoin', // OK
|
||||
'listenOnlyMode', // OK
|
||||
'forceListenOnly', // OK
|
||||
'skipCheck', // OK
|
||||
'clientTitle', // OK
|
||||
'lockOnJoin', // NOT IMPLEMENTED YET
|
||||
'askForFeedbackOnLogout', // OK
|
||||
// BRANDING
|
||||
'displayBrandingArea', // OK
|
||||
// KURENTO
|
||||
'enableScreensharing', // OK
|
||||
'enableVideo', // OK
|
||||
'enableVideoStats', // COULDN'T TEST
|
||||
// WHITEBOARD
|
||||
];
|
||||
if (handledHTML5Parameters.indexOf(key) === -1) {
|
||||
return acc;
|
||||
@ -79,6 +94,8 @@ export function joinRouteHandler(nextState, replace, callback) {
|
||||
log('error', `Caught: ${e.message}`);
|
||||
}
|
||||
|
||||
makeCall('addUserSettings', meetingID, internalUserID, key, value);
|
||||
|
||||
return { ...acc, [key]: value };
|
||||
}, {}) : {};
|
||||
|
||||
|
@ -119,7 +119,7 @@ Base.defaultProps = defaultProps;
|
||||
const SUBSCRIPTIONS_NAME = [
|
||||
'users', 'meetings', 'polls', 'presentations',
|
||||
'slides', 'captions', 'breakouts', 'voiceUsers', 'whiteboard-multi-user', 'screenshare',
|
||||
'group-chat', 'presentation-pods',
|
||||
'group-chat', 'presentation-pods', 'users-settings',
|
||||
];
|
||||
|
||||
const BaseContainer = withRouter(withTracker(({ params, router }) => {
|
||||
|
@ -18,6 +18,8 @@ class ActionsBar extends React.PureComponent {
|
||||
isUserModerator,
|
||||
recordSettingsList,
|
||||
toggleRecording,
|
||||
screenSharingCheck,
|
||||
enableVideo,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
@ -45,7 +47,7 @@ class ActionsBar extends React.PureComponent {
|
||||
</div>
|
||||
<div className={isUserPresenter ? cx(styles.centerWithActions, actionBarClasses) : styles.center}>
|
||||
<AudioControlsContainer />
|
||||
{Meteor.settings.public.kurento.enableVideo ?
|
||||
{enableVideo ?
|
||||
<JoinVideoOptionsContainer
|
||||
handleJoinVideo={handleJoinVideo}
|
||||
handleCloseVideo={handleExitVideo}
|
||||
@ -56,6 +58,7 @@ class ActionsBar extends React.PureComponent {
|
||||
handleUnshareScreen,
|
||||
isVideoBroadcasting,
|
||||
isUserPresenter,
|
||||
screenSharingCheck,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import ActionsBar from './component';
|
||||
import Service from './service';
|
||||
import VideoService from '../video-provider/service';
|
||||
@ -17,4 +18,6 @@ export default withTracker(() => ({
|
||||
isVideoBroadcasting: isVideoBroadcasting(),
|
||||
recordSettingsList: Service.recordSettingsList(),
|
||||
toggleRecording: Service.toggleRecording,
|
||||
screenSharingCheck: getFromUserSettings('enableScreensharing', Meteor.settings.public.kurento.enableScreensharing),
|
||||
enableVideo: getFromUserSettings('enableVideo', Meteor.settings.public.kurento.enableVideo),
|
||||
}))(ActionsBarContainer);
|
||||
|
@ -13,6 +13,7 @@ const propTypes = {
|
||||
handleShareScreen: PropTypes.func.isRequired,
|
||||
handleUnshareScreen: PropTypes.func.isRequired,
|
||||
isVideoBroadcasting: PropTypes.bool.isRequired,
|
||||
screenSharingCheck: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
const intlMessages = defineMessages({
|
||||
@ -43,7 +44,7 @@ const isMobileBrowser = (BROWSER_RESULTS ? BROWSER_RESULTS.mobile : false) ||
|
||||
(BROWSER_RESULTS && BROWSER_RESULTS.os ?
|
||||
BROWSER_RESULTS.os.includes('Android') : // mobile flag doesn't always work
|
||||
false);
|
||||
const screenSharingCheck = Meteor.settings.public.kurento.enableScreensharing;
|
||||
|
||||
const ICE_CONNECTION_FAILED = 'ICE connection failed';
|
||||
|
||||
const DesktopShare = ({
|
||||
@ -52,6 +53,7 @@ const DesktopShare = ({
|
||||
handleUnshareScreen,
|
||||
isVideoBroadcasting,
|
||||
isUserPresenter,
|
||||
screenSharingCheck,
|
||||
}) => {
|
||||
const onFail = (error) => {
|
||||
switch (error) {
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { withModalMounter } from '/imports/ui/components/modal/service';
|
||||
import browser from 'browser-detect';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import AudioModal from './component';
|
||||
import Service from '../service';
|
||||
|
||||
@ -9,10 +10,13 @@ const AudioModalContainer = props => <AudioModal {...props} />;
|
||||
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
|
||||
const { listenOnlyMode, forceListenOnly, skipCheck } = APP_CONFIG;
|
||||
|
||||
export default withModalMounter(withTracker(({ mountModal }) =>
|
||||
({
|
||||
export default withModalMounter(withTracker(({ mountModal }) => {
|
||||
const listenOnlyMode = getFromUserSettings('listenOnlyMode', APP_CONFIG.listenOnlyMode);
|
||||
const forceListenOnly = getFromUserSettings('forceListenOnly', APP_CONFIG.forceListenOnly);
|
||||
const skipCheck = getFromUserSettings('skipCheck', APP_CONFIG.skipCheck);
|
||||
|
||||
return ({
|
||||
closeModal: () => {
|
||||
if (!Service.isConnecting()) mountModal(null);
|
||||
},
|
||||
@ -58,4 +62,5 @@ export default withModalMounter(withTracker(({ mountModal }) =>
|
||||
joinFullAudioEchoTest: !listenOnlyMode && !skipCheck,
|
||||
forceListenOnlyAttendee: listenOnlyMode && forceListenOnly && !Service.isUserModerator(),
|
||||
isIOSChrome: browser().name === 'crios',
|
||||
}))(AudioModalContainer));
|
||||
});
|
||||
})(AudioModalContainer));
|
||||
|
@ -5,6 +5,7 @@ import { injectIntl, defineMessages } from 'react-intl';
|
||||
import _ from 'lodash';
|
||||
import Breakouts from '/imports/api/breakouts';
|
||||
import { notify } from '/imports/ui/services/notification';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import Service from './service';
|
||||
import AudioModalContainer from './audio-modal/container';
|
||||
|
||||
@ -77,7 +78,7 @@ let didMountAutoJoin = false;
|
||||
export default withModalMounter(injectIntl(withTracker(({ mountModal, intl }) => {
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
|
||||
const { autoJoin } = APP_CONFIG;
|
||||
const autoJoin = getFromUserSettings('autoJoin', APP_CONFIG.autoJoin);
|
||||
const openAudioModal = mountModal.bind(
|
||||
null,
|
||||
<AudioModalContainer />,
|
||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||
import { meetingIsBreakout } from '/imports/ui/components/app/service';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { withRouter } from 'react-router';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import LogoutConfirmation from './component';
|
||||
import {
|
||||
isModerator,
|
||||
@ -14,7 +15,7 @@ const LogoutConfirmationContainer = props => (
|
||||
|
||||
export default withRouter(withTracker(({ router }) => {
|
||||
const APP_CONFIG = Meteor.settings.public.app;
|
||||
const shouldShowFeedback = !meetingIsBreakout() && APP_CONFIG.askForFeedbackOnLogout;
|
||||
const shouldShowFeedback = !meetingIsBreakout() && getFromUserSettings('askForFeedbackOnLogout', APP_CONFIG.askForFeedbackOnLogout);
|
||||
const showFeedback = shouldShowFeedback ? () => router.push('/ended/430') : () => router.push('/logout');
|
||||
|
||||
return {
|
||||
|
@ -5,6 +5,7 @@ import Settings from '/imports/ui/services/settings';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import { notify } from '/imports/ui/services/notification';
|
||||
import VideoService from '/imports/ui/components/video-provider/service';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import Media from './component';
|
||||
import MediaService, { getSwapLayout } from './service';
|
||||
import PresentationPodsContainer from '../presentation-pod/container';
|
||||
@ -120,7 +121,7 @@ export default withTracker(() => {
|
||||
data.hideOverlay = hidePresentation;
|
||||
}
|
||||
|
||||
const { enableVideo } = Meteor.settings.public.kurento;
|
||||
const enableVideo = getFromUserSettings('enableVideo', Meteor.settings.public.kurento.enableVideo);
|
||||
const autoShareWebcam = SessionStorage.getItem('metadata').html5autosharewebcam || false;
|
||||
|
||||
if (enableVideo && autoShareWebcam) {
|
||||
|
@ -6,6 +6,7 @@ import Users from '/imports/api/users';
|
||||
import Settings from '/imports/ui/services/settings';
|
||||
import VideoService from '/imports/ui/components/video-provider/service';
|
||||
import PollingService from '/imports/ui/components/polling/service';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
|
||||
const getPresentationInfo = () => {
|
||||
const currentPresentation = Presentations.findOne({
|
||||
@ -24,11 +25,11 @@ function shouldShowWhiteboard() {
|
||||
}
|
||||
|
||||
function shouldShowScreenshare() {
|
||||
return isVideoBroadcasting() && Meteor.settings.public.kurento.enableScreensharing;
|
||||
return isVideoBroadcasting() && getFromUserSettings('enableScreensharing', Meteor.settings.public.kurento.enableScreensharing);
|
||||
}
|
||||
|
||||
function shouldShowOverlay() {
|
||||
return Meteor.settings.public.kurento.enableVideo;
|
||||
return getFromUserSettings('enableVideo', Meteor.settings.public.kurento.enableVideo);
|
||||
}
|
||||
|
||||
const swapLayout = {
|
||||
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import Rating from './rating/component';
|
||||
import { styles } from './styles';
|
||||
|
||||
@ -82,7 +83,7 @@ class MeetingEnded extends React.PureComponent {
|
||||
};
|
||||
this.setSelectedStar = this.setSelectedStar.bind(this);
|
||||
this.sendFeedback = this.sendFeedback.bind(this);
|
||||
this.shouldShowFeedback = Meteor.settings.public.app.askForFeedbackOnLogout;
|
||||
this.shouldShowFeedback = getFromUserSettings('askForFeedbackOnLogout', Meteor.settings.public.app.askForFeedbackOnLogout);
|
||||
}
|
||||
setSelectedStar(starNumber) {
|
||||
this.setState({
|
||||
|
@ -5,6 +5,7 @@ import { withRouter } from 'react-router';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import { meetingIsBreakout } from '/imports/ui/components/app/service';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import userListService from '../user-list/service';
|
||||
import ChatService from '../chat/service';
|
||||
import Service from './service';
|
||||
@ -12,7 +13,6 @@ import NavBar from './component';
|
||||
|
||||
const PUBLIC_CONFIG = Meteor.settings.public;
|
||||
const PUBLIC_GROUP_CHAT_ID = PUBLIC_CONFIG.chat.public_group_id;
|
||||
const CLIENT_TITLE = PUBLIC_CONFIG.app.clientTitle;
|
||||
|
||||
const NavBarContainer = ({ children, ...props }) => (
|
||||
<NavBar {...props}>
|
||||
@ -21,6 +21,8 @@ const NavBarContainer = ({ children, ...props }) => (
|
||||
);
|
||||
|
||||
export default withRouter(withTracker(({ location, router }) => {
|
||||
const CLIENT_TITLE = getFromUserSettings('clientTitle', PUBLIC_CONFIG.app.clientTitle);
|
||||
|
||||
let meetingTitle;
|
||||
let meetingRecorded;
|
||||
|
||||
|
@ -28,8 +28,9 @@ const propTypes = {
|
||||
changeRole: PropTypes.func.isRequired,
|
||||
roving: PropTypes.func.isRequired,
|
||||
getGroupChatPrivate: PropTypes.func.isRequired,
|
||||
showBranding: PropTypes.bool.isRequired,
|
||||
};
|
||||
const SHOW_BRANDING = Meteor.settings.public.app.branding.displayBrandingArea;
|
||||
|
||||
const defaultProps = {
|
||||
compact: false,
|
||||
isBreakoutRoom: false,
|
||||
@ -67,12 +68,13 @@ class UserList extends Component {
|
||||
handleEmojiChange,
|
||||
getEmojiList,
|
||||
getEmoji,
|
||||
showBranding,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={styles.userList}>
|
||||
{
|
||||
SHOW_BRANDING
|
||||
showBranding
|
||||
&& !this.props.compact
|
||||
&& CustomLogoUrl
|
||||
? <CustomLogo CustomLogoUrl={CustomLogoUrl} /> : null
|
||||
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import { meetingIsBreakout } from '/imports/ui/components/app/service';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import Service from './service';
|
||||
import UserList from './component';
|
||||
|
||||
@ -51,4 +52,5 @@ export default withTracker(({ chatID, compact }) => ({
|
||||
handleEmojiChange: Service.setEmojiStatus,
|
||||
getEmojiList: Service.getEmojiList(),
|
||||
getEmoji: Service.getEmoji(),
|
||||
showBranding: getFromUserSettings('displayBrandingArea', Meteor.settings.public.app.branding.displayBrandingArea),
|
||||
}))(UserListContainer);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { withTracker } from 'meteor/react-meteor-data';
|
||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||
import VideoProvider from './component';
|
||||
import VideoService from './service';
|
||||
|
||||
@ -12,5 +13,5 @@ export default withTracker(() => ({
|
||||
userId: VideoService.userId(),
|
||||
sessionToken: VideoService.sessionToken(),
|
||||
userName: VideoService.userName(),
|
||||
enableVideoStats: Meteor.settings.public.kurento.enableVideoStats,
|
||||
enableVideoStats: getFromUserSettings('enableVideoStats', Meteor.settings.public.kurento.enableVideoStats),
|
||||
}))(VideoProviderContainer);
|
||||
|
@ -0,0 +1,22 @@
|
||||
import Auth from '/imports/ui/services/auth';
|
||||
import UserSettings from '/imports/api/users-settings';
|
||||
|
||||
export default function getFromUserSettings(setting, defaultValue) {
|
||||
const { meetingID: meetingId, userID: userId } = Auth;
|
||||
|
||||
const selector = {
|
||||
meetingId,
|
||||
userId,
|
||||
setting,
|
||||
};
|
||||
|
||||
const userSetting = UserSettings.findOne(selector);
|
||||
|
||||
console.log('XIMIRA', selector, userSetting);
|
||||
|
||||
if (userSetting !== undefined) {
|
||||
return userSetting.value;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
@ -111,7 +111,8 @@
|
||||
"whiteboard-multi-user",
|
||||
"presentation-pods",
|
||||
"group-chat",
|
||||
"group-chat-msg"
|
||||
"group-chat-msg",
|
||||
"users-settings"
|
||||
],
|
||||
"methods": [
|
||||
"listenOnlyToggle",
|
||||
|
@ -111,7 +111,8 @@
|
||||
"whiteboard-multi-user",
|
||||
"presentation-pods",
|
||||
"group-chat",
|
||||
"group-chat-msg"
|
||||
"group-chat-msg",
|
||||
"users-settings"
|
||||
],
|
||||
"methods": [
|
||||
"listenOnlyToggle",
|
||||
|
@ -14,6 +14,7 @@ import '/imports/api/breakouts/server';
|
||||
import '/imports/api/group-chat/server';
|
||||
import '/imports/api/group-chat-msg/server';
|
||||
import '/imports/api/screenshare/server';
|
||||
import '/imports/api/users-settings/server';
|
||||
import '/imports/api/voice-users/server';
|
||||
import '/imports/api/whiteboard-multi-user/server';
|
||||
import '/imports/api/video/server';
|
||||
|
Loading…
Reference in New Issue
Block a user