Merge branch 'master' of github.com:bigbluebutton/bigbluebutton into iframe-outside-commands
This commit is contained in:
commit
98ac77dc03
@ -12,7 +12,7 @@ env:
|
||||
- BBB_SERVER_URL=http://localhost/bigbluebutton/api
|
||||
|
||||
script:
|
||||
- bash ./build_script.sh
|
||||
- travis_wait bash ./build_script.sh
|
||||
|
||||
after_script:
|
||||
- docker stop $docker
|
||||
|
@ -1,92 +0,0 @@
|
||||
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import deepMerge from '/imports/utils/deepMerge';
|
||||
|
||||
export default class Acl {
|
||||
constructor(config, Users) {
|
||||
this.Users = Users;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
can(permission, credentials) {
|
||||
check(permission, String);
|
||||
const permissions = this.getPermissions(credentials);
|
||||
|
||||
return this.checkToken(credentials) && this.fetchPermission(permission, permissions);
|
||||
}
|
||||
|
||||
checkToken(credentials) {
|
||||
// skip token check in client `can` calls since we dont have the authToken in the collection
|
||||
if (!Meteor.isServer) return true;
|
||||
|
||||
const { meetingId, requesterUserId: userId, requesterToken: authToken } = credentials;
|
||||
|
||||
const User = this.Users.findOne({
|
||||
meetingId,
|
||||
userId,
|
||||
authToken,
|
||||
validated: true,
|
||||
connectionStatus: 'online',
|
||||
// TODO: We cant check for approved until we move subscription login out of <Base /> // TODO 4767
|
||||
// approved: true,
|
||||
});
|
||||
|
||||
return !!User; // if he found a user means the meeting/user/token is valid
|
||||
}
|
||||
|
||||
fetchPermission(permission, permissions) {
|
||||
if (!permission) return false;
|
||||
|
||||
if (Match.test(permissions, String)) {
|
||||
return permissions.indexOf(permission) > -1;
|
||||
} else if (Match.test(permissions, Array)) {
|
||||
return permissions.some(internalAcl => (this.fetchPermission(permission, internalAcl)));
|
||||
} else if (Match.test(permissions, Object)) {
|
||||
if (permission.indexOf('.') > -1) {
|
||||
return this.fetchPermission(
|
||||
permission.substring(permission.indexOf('.') + 1),
|
||||
permissions[permission.substring(0, permission.indexOf('.'))],
|
||||
);
|
||||
}
|
||||
return permissions[permission];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getPermissions(credentials) {
|
||||
if (!credentials) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { meetingId, requesterUserId: userId } = credentials;
|
||||
|
||||
const user = this.Users.findOne({
|
||||
meetingId,
|
||||
userId,
|
||||
});
|
||||
|
||||
const containRole = Acl.containsRole(user);
|
||||
|
||||
if (containRole) {
|
||||
const { roles } = user;
|
||||
let permissions = {};
|
||||
|
||||
roles.forEach((role) => {
|
||||
// There is a big issue here, if we just send the content from the this.config
|
||||
// inside the deepMerge, we change both permissions and the config.
|
||||
// Couldn't find a better way to prevent the changing.
|
||||
// The problems occurs in the `sources.shift()`.
|
||||
permissions = deepMerge(permissions, JSON.parse(JSON.stringify(this.config[role])));
|
||||
});
|
||||
|
||||
return permissions;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static containsRole(user) {
|
||||
return Match.test(user, Object) &&
|
||||
Match.test(user.roles, Array);
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import Acl from '/imports/startup/acl';
|
||||
import { getMultiUserStatus } from '/imports/api/common/server/helpers';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
@ -1,4 +1,3 @@
|
||||
import Acl from '/imports/startup/acl';
|
||||
import { getMultiUserStatus } from '/imports/api/common/server/helpers';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
@ -1,4 +1,3 @@
|
||||
import Acl from '/imports/startup/acl';
|
||||
import { getMultiUserStatus } from '/imports/api/common/server/helpers';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
@ -2,7 +2,6 @@ import Annotations from '/imports/api/annotations';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function annotations(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -18,7 +17,7 @@ function annotations(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundAnnotations = annotations.bind(this);
|
||||
return mapToAcl('subscriptions.annotations', boundAnnotations)(args);
|
||||
return boundAnnotations(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('annotations', publish);
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import createBreakoutRoom from '/imports/api/breakouts/server/methods/createBreakout';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import requestJoinURL from './methods/requestJoinURL';
|
||||
import endAllBreakouts from './methods/endAllBreakouts';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.requestJoinURL', 'methods.createBreakoutRoom', 'methods.endAllBreakouts'], {
|
||||
Meteor.methods({
|
||||
requestJoinURL,
|
||||
createBreakoutRoom,
|
||||
endAllBreakouts,
|
||||
}));
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import Breakouts from '/imports/api/breakouts';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
|
||||
@ -32,7 +31,7 @@ function breakouts(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundBreakouts = breakouts.bind(this);
|
||||
return mapToAcl('subscriptions.breakouts', boundBreakouts)(args);
|
||||
return boundBreakouts(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('breakouts', publish);
|
||||
|
@ -2,7 +2,6 @@ import Captions from '/imports/api/captions';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function captions(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -18,7 +17,7 @@ function captions(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundCaptions = captions.bind(this);
|
||||
return mapToAcl('subscriptions.captions', boundCaptions)(args);
|
||||
return boundCaptions(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('captions', publish);
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { getMultiUserStatus } from '/imports/api/common/server/helpers';
|
||||
import RedisPubSub from '/imports/startup/server/redis';
|
||||
import Acl from '/imports/startup/acl';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import sendGroupChatMsg from './methods/sendGroupChatMsg';
|
||||
import clearPublicChatHistory from './methods/clearPublicChatHistory';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.sendGroupChatMsg', 'methods.clearPublicChatHistory'], {
|
||||
Meteor.methods({
|
||||
sendGroupChatMsg,
|
||||
clearPublicChatHistory,
|
||||
}));
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function groupChatMsg(credentials, chatsIds) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -27,7 +26,7 @@ function groupChatMsg(credentials, chatsIds) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundGroupChat = groupChatMsg.bind(this);
|
||||
return mapToAcl('subscriptions.group-chat-msg', boundGroupChat)(args);
|
||||
return boundGroupChat(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('group-chat-msg', publish);
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import createGroupChat from './methods/createGroupChat';
|
||||
import destroyGroupChat from './methods/destroyGroupChat';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.createGroupChat', 'methods.destroyGroupChat'], {
|
||||
Meteor.methods({
|
||||
createGroupChat,
|
||||
destroyGroupChat,
|
||||
}));
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function groupChat(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -28,7 +27,7 @@ function groupChat(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundGroupChat = groupChat.bind(this);
|
||||
return mapToAcl('subscriptions.group-chat', boundGroupChat)(args);
|
||||
return boundGroupChat(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('group-chat', publish);
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import endMeeting from './methods/endMeeting';
|
||||
import toggleRecording from './methods/toggleRecording';
|
||||
import transferUser from './methods/transferUser';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.endMeeting', 'methods.toggleRecording', 'methods.transferUser'], {
|
||||
Meteor.methods({
|
||||
endMeeting,
|
||||
toggleRecording,
|
||||
transferUser,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Meetings from '/imports/api/meetings';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function meetings(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -32,7 +31,7 @@ function meetings(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundMeetings = meetings.bind(this);
|
||||
return mapToAcl('subscriptions.meetings', boundMeetings)(args);
|
||||
return boundMeetings(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('meetings', publish);
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import publishVote from './methods/publishVote';
|
||||
import publishPoll from './methods/publishPoll';
|
||||
import startPoll from './methods/startPoll';
|
||||
import stopPoll from './methods/stopPoll';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.publishVote', 'methods.startPoll', 'methods.stopPoll', 'methods.publishPoll'], {
|
||||
Meteor.methods({
|
||||
publishVote,
|
||||
publishPoll,
|
||||
startPoll,
|
||||
stopPoll,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import Polls from '/imports/api/polls';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
Meteor.publish('current-poll', (meetingId) => {
|
||||
check(meetingId, String);
|
||||
@ -36,7 +35,7 @@ function polls(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundPolls = polls.bind(this);
|
||||
return mapToAcl('subscriptions.polls', boundPolls)(args);
|
||||
return boundPolls(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('polls', publish);
|
||||
|
@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import PresentationPods from '/imports/api/presentation-pods';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function presentationPods(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -18,7 +17,7 @@ function presentationPods(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundPresentationPods = presentationPods.bind(this);
|
||||
return mapToAcl('subscriptions.presentation-pods', boundPresentationPods)(args);
|
||||
return boundPresentationPods(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('presentation-pods', publish);
|
||||
|
@ -1,9 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import requestPresentationUploadToken from './methods/requestPresentationUploadToken';
|
||||
|
||||
Meteor.methods(mapToAcl([
|
||||
'methods.requestPresentationUploadToken',
|
||||
], {
|
||||
Meteor.methods({
|
||||
requestPresentationUploadToken,
|
||||
}));
|
||||
});
|
||||
|
@ -1,12 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import removePresentation from './methods/removePresentation';
|
||||
import setPresentation from './methods/setPresentation';
|
||||
|
||||
Meteor.methods(mapToAcl([
|
||||
'methods.removePresentation',
|
||||
'methods.setPresentation',
|
||||
], {
|
||||
Meteor.methods({
|
||||
removePresentation,
|
||||
setPresentation,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Presentations from '/imports/api/presentations';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function presentations(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -18,7 +17,7 @@ function presentations(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundPresentations = presentations.bind(this);
|
||||
return mapToAcl('subscriptions.presentations', boundPresentations)(args);
|
||||
return boundPresentations(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('presentations', publish);
|
||||
|
@ -2,7 +2,6 @@ import Screenshare from '/imports/api/screenshare';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function screenshare(credentials) {
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
@ -17,7 +16,7 @@ function screenshare(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundScreenshare = screenshare.bind(this);
|
||||
return mapToAcl('subscriptions.screenshare', boundScreenshare)(args);
|
||||
return boundScreenshare(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('screenshare', publish);
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import switchSlide from './methods/switchSlide';
|
||||
import zoomSlide from './methods/zoomSlide';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.switchSlide', 'methods.zoomSlide'], {
|
||||
Meteor.methods({
|
||||
switchSlide,
|
||||
zoomSlide,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import Slides from '/imports/api/slides';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function slides(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -18,7 +17,7 @@ function slides(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundSlides = slides.bind(this);
|
||||
return mapToAcl('subscriptions.slides', boundSlides)(args);
|
||||
return boundSlides(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('slides', publish);
|
||||
|
@ -2,7 +2,6 @@ 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;
|
||||
@ -17,7 +16,7 @@ function userSettings(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundUserSettings = userSettings.bind(this);
|
||||
return mapToAcl('subscriptions.users-settings', boundUserSettings)(args);
|
||||
return boundUserSettings(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('users-settings', publish);
|
||||
|
@ -1,17 +1,14 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import validateAuthToken from './methods/validateAuthToken';
|
||||
import setEmojiStatus from './methods/setEmojiStatus';
|
||||
import assignPresenter from './methods/assignPresenter';
|
||||
import changeRole from './methods/changeRole';
|
||||
import removeUser from './methods/removeUser';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.setEmojiStatus', 'methods.assignPresenter', 'methods.changeRole',
|
||||
'methods.removeUser'], {
|
||||
Meteor.methods({
|
||||
setEmojiStatus,
|
||||
assignPresenter,
|
||||
changeRole,
|
||||
removeUser,
|
||||
}));
|
||||
|
||||
Meteor.methods({ validateAuthToken });
|
||||
validateAuthToken,
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import Users from '/imports/api/users';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
import userLeaving from './methods/userLeaving';
|
||||
|
||||
@ -68,7 +67,7 @@ function users(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundUsers = users.bind(this);
|
||||
return mapToAcl('subscriptions.users', boundUsers)(args);
|
||||
return boundUsers(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('users', publish);
|
||||
|
@ -1,13 +1,11 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import listenOnlyToggle from './methods/listenOnlyToggle';
|
||||
import muteToggle from './methods/muteToggle';
|
||||
import ejectUserFromVoice from './methods/ejectUserFromVoice';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.listenOnlyToggle', 'methods.toggleSelfVoice',
|
||||
'methods.toggleVoice', 'methods.ejectUserFromVoice'], {
|
||||
Meteor.methods({
|
||||
listenOnlyToggle,
|
||||
toggleSelfVoice: (credentials) => { muteToggle(credentials, credentials.requesterUserId); },
|
||||
toggleVoice: muteToggle,
|
||||
ejectUserFromVoice,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import VoiceUsers from '/imports/api/voice-users';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function voiceUser(credentials) {
|
||||
const { meetingId, requesterUserId } = credentials;
|
||||
@ -17,7 +16,7 @@ function voiceUser(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundVoiceUser = voiceUser.bind(this);
|
||||
return mapToAcl('subscriptions.voiceUser', boundVoiceUser)(args);
|
||||
return boundVoiceUser(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('voiceUsers', publish);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
import changeWhiteboardAccess from './methods/changeWhiteboardAccess';
|
||||
|
||||
Meteor.methods(mapToAcl(['methods.modifyWhiteboardAccess'], {
|
||||
Meteor.methods({
|
||||
changeWhiteboardAccess,
|
||||
}));
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { check } from 'meteor/check';
|
||||
import Logger from '/imports/startup/server/logger';
|
||||
import mapToAcl from '/imports/startup/mapToAcl';
|
||||
|
||||
function whiteboardMultiUser(credentials) {
|
||||
const { meetingId, requesterUserId, requesterToken } = credentials;
|
||||
@ -16,7 +15,7 @@ function whiteboardMultiUser(credentials) {
|
||||
|
||||
function publish(...args) {
|
||||
const boundMultiUser = whiteboardMultiUser.bind(this);
|
||||
return mapToAcl('subscriptions.whiteboard-multi-user', boundMultiUser)(args);
|
||||
return boundMultiUser(...args);
|
||||
}
|
||||
|
||||
Meteor.publish('whiteboard-multi-user', publish);
|
||||
|
@ -1,12 +0,0 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import Users from '/imports/api/users';
|
||||
import Acl from '/imports/api/acl/Acl';
|
||||
|
||||
const AclSingleton = new Acl();
|
||||
|
||||
Meteor.startup(() => {
|
||||
AclSingleton.config = Meteor.settings.public.acl;
|
||||
AclSingleton.Users = Users;
|
||||
});
|
||||
|
||||
export default AclSingleton;
|
@ -1,45 +0,0 @@
|
||||
import Acl from '/imports/startup/acl';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
|
||||
const injectAclActionCheck = (name, handler) => (
|
||||
(...args) => {
|
||||
const credentials = args[0];
|
||||
if (!Acl.can(name, credentials)) {
|
||||
throw new Meteor.Error(
|
||||
'acl-not-allowed',
|
||||
`The user can't perform the action "${name}".`,
|
||||
);
|
||||
}
|
||||
|
||||
return handler(...args);
|
||||
}
|
||||
);
|
||||
|
||||
const injectAclSubscribeCheck = (name, handler) => (
|
||||
(...args) => {
|
||||
const credentials = args[args.length - 1];
|
||||
if (!Acl.can(name, ...credentials)) {
|
||||
throw new Meteor.Error(
|
||||
'acl-not-allowed',
|
||||
`The user can't perform the subscription "${name}".`,
|
||||
);
|
||||
}
|
||||
|
||||
return handler(...credentials);
|
||||
}
|
||||
);
|
||||
|
||||
const mapToAcl = (name, handler) => {
|
||||
// The Meteor#methods require an object, while the Meteor#subscribe an function.
|
||||
if (handler instanceof Function) {
|
||||
return injectAclSubscribeCheck(name, handler);
|
||||
}
|
||||
|
||||
return Object.keys(handler).reduce((previous, current, index) => {
|
||||
const newPrevious = previous;
|
||||
newPrevious[current] = injectAclActionCheck(name[index], handler[current]);
|
||||
return newPrevious;
|
||||
}, {});
|
||||
};
|
||||
|
||||
export default mapToAcl;
|
@ -149,7 +149,7 @@ class ActionsDropdown extends Component {
|
||||
onClick={toggleRecording}
|
||||
/>
|
||||
: null),
|
||||
(isUserPresenter && !meetingIsBreakout && !hasBreakoutRoom ?
|
||||
(isUserModerator && !meetingIsBreakout && !hasBreakoutRoom ?
|
||||
<DropdownListItem
|
||||
icon="rooms"
|
||||
label={intl.formatMessage(intlMessages.createBreakoutRoom)}
|
||||
|
@ -36,9 +36,8 @@ const intlMessages = defineMessages({
|
||||
description: 'room intl to name the breakout meetings',
|
||||
},
|
||||
});
|
||||
const BREAKOUT_CONFIG = Meteor.settings.public.breakout;
|
||||
const MIN_BREAKOUT_ROOMS = BREAKOUT_CONFIG.rooms.min;
|
||||
const MAX_BREAKOUT_ROOMS = BREAKOUT_CONFIG.rooms.max;
|
||||
const MIN_BREAKOUT_ROOMS = 2;
|
||||
const MAX_BREAKOUT_ROOMS = 8;
|
||||
|
||||
class BreakoutRoom extends Component {
|
||||
constructor(props) {
|
||||
@ -60,7 +59,7 @@ class BreakoutRoom extends Component {
|
||||
const {
|
||||
createBreakoutRoom,
|
||||
meetingName,
|
||||
intl
|
||||
intl,
|
||||
} = this.props;
|
||||
|
||||
const { numberOfRooms, durationTime } = this.state;
|
||||
@ -113,7 +112,12 @@ class BreakoutRoom extends Component {
|
||||
<div className={styles.breakoutSettings}>
|
||||
<label>
|
||||
<p className={styles.labelText}>{intl.formatMessage(intlMessages.numberOfRooms)}</p>
|
||||
<select name="numberOfRooms" className={styles.inputRooms} value={this.state.numberOfRooms} onChange={this.changeNumberOfRooms}>
|
||||
<select
|
||||
name="numberOfRooms"
|
||||
className={styles.inputRooms}
|
||||
value={this.state.numberOfRooms}
|
||||
onChange={this.changeNumberOfRooms}
|
||||
>
|
||||
{
|
||||
_.range(MIN_BREAKOUT_ROOMS, MAX_BREAKOUT_ROOMS + 1).map(item => (<option key={_.uniqueId('value-')}>{item}</option>))
|
||||
}
|
||||
@ -122,7 +126,13 @@ class BreakoutRoom extends Component {
|
||||
<label >
|
||||
<p className={styles.labelText}>{intl.formatMessage(intlMessages.duration)}</p>
|
||||
<div className={styles.durationArea}>
|
||||
<input type="number" className={styles.duration} min={MIN_BREAKOUT_ROOMS} value={this.state.durationTime} onChange={this.changeDurationTime} />
|
||||
<input
|
||||
type="number"
|
||||
className={styles.duration}
|
||||
min={MIN_BREAKOUT_ROOMS}
|
||||
value={this.state.durationTime}
|
||||
onChange={this.changeDurationTime}
|
||||
/>
|
||||
<span>
|
||||
<HoldButton
|
||||
key="decrease-breakout-time"
|
||||
|
@ -6,8 +6,8 @@ import Modal from 'react-modal';
|
||||
import cx from 'classnames';
|
||||
import Resizable from 're-resizable';
|
||||
import browser from 'browser-detect';
|
||||
import BreakoutRoomContainer from '/imports/ui/components/breakout-room/container';
|
||||
import PollingContainer from '/imports/ui/components/polling/container';
|
||||
import BreakoutRoomContainer from '/imports/ui/components/Breakout-room/container';
|
||||
import ToastContainer from '../toast/container';
|
||||
import ModalContainer from '../modal/container';
|
||||
import NotificationsBarContainer from '../notifications-bar/container';
|
||||
|
@ -92,8 +92,8 @@ class BreakoutRoom extends Component {
|
||||
}
|
||||
|
||||
transferUserToBreakoutRoom(breakoutId) {
|
||||
const { transferToBreakout, meetingId } = this.props;
|
||||
transferToBreakout(meetingId, breakoutId);
|
||||
const { transferToBreakout } = this.props;
|
||||
transferToBreakout(breakoutId);
|
||||
this.setState({ joinedAudioOnly: true, breakoutId });
|
||||
}
|
||||
returnBackToMeeeting(breakoutId) {
|
||||
@ -105,7 +105,7 @@ class BreakoutRoom extends Component {
|
||||
renderUserActions(breakoutId) {
|
||||
const {
|
||||
isMicrophoneUser,
|
||||
isPresenter,
|
||||
isModerator,
|
||||
intl,
|
||||
} = this.props;
|
||||
|
||||
@ -117,7 +117,7 @@ class BreakoutRoom extends Component {
|
||||
waiting,
|
||||
} = this.state;
|
||||
|
||||
const presenterJoinedAudio = isMicrophoneUser && isPresenter;
|
||||
const moderatorJoinedAudio = isMicrophoneUser && isModerator;
|
||||
const disable = waiting && requestedBreakoutId !== breakoutId;
|
||||
const audioAction = joinedAudioOnly ?
|
||||
() => this.returnBackToMeeeting(breakoutId) :
|
||||
@ -133,13 +133,13 @@ class BreakoutRoom extends Component {
|
||||
className={styles.joinButton}
|
||||
/>
|
||||
{
|
||||
presenterJoinedAudio ?
|
||||
moderatorJoinedAudio ?
|
||||
[
|
||||
('|'),
|
||||
(
|
||||
<Button
|
||||
label={
|
||||
presenterJoinedAudio &&
|
||||
moderatorJoinedAudio &&
|
||||
stateBreakoutId === breakoutId &&
|
||||
joinedAudioOnly
|
||||
?
|
@ -21,7 +21,6 @@ export default withTracker((props) => {
|
||||
closeBreakoutPanel,
|
||||
} = Service;
|
||||
const breakoutRooms = findBreakouts();
|
||||
|
||||
const isMicrophoneUser = AudioService.isConnected() && !AudioService.isListenOnly();
|
||||
|
||||
return {
|
||||
@ -33,7 +32,7 @@ export default withTracker((props) => {
|
||||
transferUserToMeeting,
|
||||
transferToBreakout,
|
||||
isMicrophoneUser,
|
||||
meetingId,
|
||||
meetingId: meetingId(),
|
||||
isPresenter: isPresenter(),
|
||||
isModerator: isModerator(),
|
||||
closeBreakoutPanel,
|
@ -38,7 +38,7 @@ const requestJoinURL = (breakoutId) => {
|
||||
|
||||
const transferUserToMeeting = (fromMeetingId, toMeetingId) => makeCall('transferUser', fromMeetingId, toMeetingId);
|
||||
|
||||
const transferToBreakout = (fromMeetingId, breakoutId) => {
|
||||
const transferToBreakout = (breakoutId) => {
|
||||
const breakoutRooms = findBreakouts();
|
||||
const breakoutRoom = breakoutRooms.filter(breakout => breakout.breakoutId === breakoutId).shift();
|
||||
const breakoutMeeting = Meetings.findOne({
|
||||
@ -48,7 +48,7 @@ const transferToBreakout = (fromMeetingId, breakoutId) => {
|
||||
{ 'meetingProp.isBreakout': true },
|
||||
],
|
||||
});
|
||||
transferUserToMeeting(fromMeetingId, breakoutMeeting.meetingId);
|
||||
transferUserToMeeting(Auth.meetingID, breakoutMeeting.meetingId);
|
||||
};
|
||||
|
||||
const isPresenter = () => {
|
||||
@ -63,6 +63,7 @@ const isModerator = () => {
|
||||
return mappedUser.isModerator;
|
||||
};
|
||||
|
||||
|
||||
const closeBreakoutPanel = () => Session.set('breakoutRoomIsOpen', false);
|
||||
|
||||
export default {
|
||||
@ -72,7 +73,7 @@ export default {
|
||||
breakoutRoomUser,
|
||||
transferUserToMeeting,
|
||||
transferToBreakout,
|
||||
meetingId: Auth.meetingID,
|
||||
meetingId: () => Auth.meetingID,
|
||||
isPresenter,
|
||||
closeBreakoutPanel,
|
||||
isModerator,
|
@ -9,7 +9,6 @@ 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 Auth from '/imports/ui/services/auth';
|
||||
import Acl from '/imports/startup/acl';
|
||||
import Button from '/imports/ui/components/button/component';
|
||||
|
||||
import ChatService from './../service';
|
||||
@ -80,6 +79,8 @@ class ChatDropdown extends Component {
|
||||
const saveIcon = 'save_notes';
|
||||
const copyIcon = 'copy';
|
||||
|
||||
const user = ChatService.getUser(Auth.userID);
|
||||
|
||||
return _.compact([
|
||||
<DropdownListItem
|
||||
icon={saveIcon}
|
||||
@ -104,7 +105,7 @@ class ChatDropdown extends Component {
|
||||
label={intl.formatMessage(intlMessages.copy)}
|
||||
key={this.actionsKey[1]}
|
||||
/>,
|
||||
Acl.can('methods.clearPublicChatHistory', Auth.credentials) ? (
|
||||
user.isModerator ? (
|
||||
<DropdownListItem
|
||||
icon={clearIcon}
|
||||
label={intl.formatMessage(intlMessages.clear)}
|
||||
|
@ -23,6 +23,10 @@ const intlMessage = defineMessages({
|
||||
id: 'app.error.meeting.ended',
|
||||
description: 'user logged conference',
|
||||
},
|
||||
'acl-not-allowed': {
|
||||
id: 'app.error.removed',
|
||||
description: 'Message to display when user is removed from the conference',
|
||||
},
|
||||
messageEnded: {
|
||||
id: 'app.meeting.endedMessage',
|
||||
description: 'message saying to go back to home screen',
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { Match } from 'meteor/check';
|
||||
|
||||
export default function deepMerge(merge, ...sources) {
|
||||
if (!sources.length) return merge;
|
||||
|
||||
const source = sources.shift();
|
||||
|
||||
let merged = merge;
|
||||
|
||||
if (Match.test(merged, Array)) {
|
||||
if (Match.test(source, Array)) {
|
||||
merged.push(...source);
|
||||
} else {
|
||||
merged.push(source);
|
||||
}
|
||||
} else if (Match.test(merged, Object)) {
|
||||
if (Match.test(source, Object)) {
|
||||
Object.keys(source).forEach((key) => {
|
||||
if (!merged[key]) {
|
||||
merged[key] = source[key];
|
||||
} else {
|
||||
deepMerge(merged[key], source[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
merged = source;
|
||||
}
|
||||
|
||||
return deepMerge(merged, ...sources);
|
||||
}
|
@ -102,72 +102,6 @@ public:
|
||||
allowOutsideCommands:
|
||||
toggleRecording: false
|
||||
toggleSelfVoice: false
|
||||
acl:
|
||||
viewer:
|
||||
subscriptions:
|
||||
- users
|
||||
- cursor
|
||||
- screenshare
|
||||
- meetings
|
||||
- polls
|
||||
- chat
|
||||
- presentations
|
||||
- annotations
|
||||
- slides
|
||||
- captions
|
||||
- breakouts
|
||||
- voiceUsers
|
||||
- whiteboard-multi-user
|
||||
- presentation-pods
|
||||
- group-chat
|
||||
- group-chat-msg
|
||||
- users-settings
|
||||
methods:
|
||||
- listenOnlyToggle
|
||||
- userLogout
|
||||
- setEmojiStatus
|
||||
- toggleSelfVoice
|
||||
- publishVote
|
||||
- sendChat
|
||||
- createGroupChat
|
||||
- destroyGroupChat
|
||||
- sendGroupChatMsg
|
||||
- requestJoinURL
|
||||
moderator:
|
||||
methods:
|
||||
- assignPresenter
|
||||
- removeUser
|
||||
- muteUser
|
||||
- unmuteUser
|
||||
- endMeeting
|
||||
- toggleVoice
|
||||
- clearPublicChatHistory
|
||||
- changeRole
|
||||
- ejectUserFromVoice
|
||||
- toggleRecording
|
||||
- endAllBreakouts
|
||||
presenter:
|
||||
methods:
|
||||
- assignPresenter
|
||||
- switchSlide
|
||||
- modifyWhiteboardAccess
|
||||
- undoAnnotation
|
||||
- clearWhiteboard
|
||||
- moveCursor
|
||||
- sendAnnotation
|
||||
- removePresentation
|
||||
- setPresentation
|
||||
- zoomSlide
|
||||
- requestPresentationUploadToken
|
||||
- transferUser
|
||||
- createBreakoutRoom
|
||||
- startPoll
|
||||
- stopPoll
|
||||
- publishPoll
|
||||
breakout:
|
||||
rooms:
|
||||
min: 2
|
||||
max: 8
|
||||
poll:
|
||||
max_custom: 5
|
||||
chat:
|
||||
|
Loading…
Reference in New Issue
Block a user