Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Presentation pods support #5932

Merged
merged 25 commits into from
Aug 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e5a4bd0
Handle CreateNewPresentationPod message
OZhurbenko Apr 5, 2018
65cf1d6
Handle RemovePresentationPod
OZhurbenko Apr 5, 2018
b2708d2
Handling SetPresenterInPod
OZhurbenko Apr 5, 2018
69d8ded
Corrected the collection name
OZhurbenko Apr 5, 2018
df98f39
Handle SyncGetPresentationPods
OZhurbenko Apr 5, 2018
f4ab6b7
Corrected handlers.js
OZhurbenko Apr 5, 2018
a3f21ee
Adjustments to support presentation pods in 2.1
OZhurbenko Apr 9, 2018
0c8f1a3
Adjusted multi-user for 2.1
OZhurbenko Apr 9, 2018
04d6b06
Forgotten file
OZhurbenko Apr 9, 2018
1ad1707
Combined traits for group chats and group chat messages
OZhurbenko Apr 10, 2018
7c61e4c
Corrected a publisher for presentation-pods
OZhurbenko Apr 10, 2018
6c1e791
Added a layer for the presentation pods component
OZhurbenko Apr 10, 2018
a39700b
Corrected cursor messages, added whiteboardId
OZhurbenko Apr 10, 2018
4afc455
Corrected indexing for Slides, Presentation, Pods, and Annotations
OZhurbenko Apr 10, 2018
6045dfd
Ignoring annotation history messages that don't target Meteor
OZhurbenko Apr 10, 2018
0ae0d56
Adjusted switchSlide to the new message format
OZhurbenko Apr 11, 2018
68aba8e
Ajusted multi-user change to the new message format
OZhurbenko Apr 11, 2018
b7823c4
Merge remote-tracking branch 'upstream/v2.2-dev' into presentation-pods
oswaldoacauan Jul 24, 2018
adb34da
Fixes for cursor
oswaldoacauan Jul 26, 2018
047b23f
Fix for annotations
oswaldoacauan Jul 26, 2018
9eb5323
Fix remote cursors not showing
oswaldoacauan Jul 26, 2018
0f94c33
Fix cursor while mwb is on
oswaldoacauan Jul 26, 2018
ce021e6
Fix race condition
oswaldoacauan Jul 27, 2018
3c2bb87
Fix Acl for cursor/annotations for pods
oswaldoacauan Aug 1, 2018
0ed7c45
Fix Acl for cursor/annotations for pods
oswaldoacauan Aug 1, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 7 additions & 7 deletions bigbluebutton-html5/imports/api/annotations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ const Annotations = new Mongo.Collection('annotations');
const Streamer = new Meteor.Streamer('annotations', { retransmit: false, });

if (Meteor.isServer) {
// types of queries for the annotations:
// 1. meetingId, whiteboardId
// 2. meetingId, whiteboardId, userId
// 3. meetingId, id, userId
// 4. meetingId, whiteboardId, id
// types of queries for the annotations (Total):
// 1. meetingId, id, userId ( 8 )
// 2. meetingId, id, userId, whiteboardId ( 1 )
// 3. meetingId ( 1 )
// 4. meetingId, whiteboardId ( 1 )
// 5. meetingId, whiteboardId, id ( 1 )
// 6. meetingId, whiteboardId, userId ( 1 )
// These 2 indexes seem to cover all of the cases
// Either mongo uses a whole or a part of the compound index
// Or it uses 'id' and then matches other fields

Annotations._ensureIndex({ id: 1 });
Annotations._ensureIndex({ meetingId: 1, whiteboardId: 1, userId: 1 });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import _ from 'lodash';
import { check } from 'meteor/check';
import modifyWhiteboardAccess from '/imports/api/whiteboard-multi-user/server/modifiers/modifyWhiteboardAccess';
import clearAnnotations from '../modifiers/clearAnnotations';
import addAnnotation from '../modifiers/addAnnotation';

export default function handleWhiteboardAnnotations({ body }, meetingId) {
export default function handleWhiteboardAnnotations({ header, body }, meetingId) {
check(header, Object);
if (header.userId !== 'nodeJSapp') { return false; }

check(meetingId, String);
check(body, Object);

const { annotations, whiteboardId } = body;
const { annotations, whiteboardId, multiUser } = body;

check(annotations, Array);
check(whiteboardId, String);
check(multiUser, Boolean);

clearAnnotations(meetingId, whiteboardId);

const annotationsAdded = [];
Expand All @@ -18,5 +25,7 @@ export default function handleWhiteboardAnnotations({ body }, meetingId) {
annotationsAdded.push(addAnnotation(meetingId, wbId, userId, annotation));
});

modifyWhiteboardAccess(meetingId, whiteboardId, multiUser);

return annotationsAdded;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import RedisPubSub from '/imports/startup/server/redis';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

import isPodPresenter from '/imports/api/presentation-pods/server/utils/isPodPresenter';

export default function clearWhiteboard(credentials, whiteboardId) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
Expand All @@ -16,7 +18,8 @@ export default function clearWhiteboard(credentials, whiteboardId) {
check(requesterToken, String);
check(whiteboardId, String);

const allowed = Acl.can('methods.clearWhiteboard', credentials) || getMultiUserStatus(meetingId);
const allowed = isPodPresenter(meetingId, whiteboardId, requesterUserId)
|| getMultiUserStatus(meetingId, whiteboardId);
if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to clear the whiteboard`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Annotations from '/imports/api/annotations';

function isLastMessage(annotation, userId) {
import isPodPresenter from '/imports/api/presentation-pods/server/utils/isPodPresenter';

function isLastMessage(meetingId, annotation, userId) {
const DRAW_END = Meteor.settings.public.whiteboard.annotations.status.end;

if (annotation.status === DRAW_END) {
const selector = {
meetingId,
id: annotation.id,
userId,
};
Expand All @@ -27,11 +30,13 @@ export default function sendAnnotation(credentials, annotation) {
const EVENT_NAME = 'SendWhiteboardAnnotationPubMsg';

const { meetingId, requesterUserId, requesterToken } = credentials;
const whiteboardId = annotation.wbId;

check(meetingId, String);
check(requesterUserId, String);
check(requesterToken, String);
check(annotation, Object);
check(whiteboardId, String);

// We allow messages to pass through in 3 cases:
// 1. When it's a standard message in presenter mode (Acl check)
Expand All @@ -40,9 +45,9 @@ export default function sendAnnotation(credentials, annotation) {
// and then slide/presentation changes, the user lost presenter rights,
// or multi-user whiteboard gets turned off
// So we allow the last "DRAW_END" message to pass through, to finish the shape.
const allowed = Acl.can('methods.sendAnnotation', credentials) ||
getMultiUserStatus(meetingId) ||
isLastMessage(annotation, requesterUserId);
const allowed = isPodPresenter(meetingId, whiteboardId, requesterUserId) ||
getMultiUserStatus(meetingId, whiteboardId) ||
isLastMessage(meetingId, annotation, requesterUserId);

if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to send an annotation`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import RedisPubSub from '/imports/startup/server/redis';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

import isPodPresenter from '/imports/api/presentation-pods/server/utils/isPodPresenter';

export default function undoAnnotation(credentials, whiteboardId) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
Expand All @@ -16,7 +18,9 @@ export default function undoAnnotation(credentials, whiteboardId) {
check(requesterToken, String);
check(whiteboardId, String);

const allowed = Acl.can('methods.undoAnnotation', credentials) || getMultiUserStatus(meetingId);
const allowed = isPodPresenter(meetingId, whiteboardId, requesterUserId)
|| getMultiUserStatus(meetingId, whiteboardId);

if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to undo the annotation`);
}
Expand Down
4 changes: 2 additions & 2 deletions bigbluebutton-html5/imports/api/common/server/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export const processForHTML5ServerOnly = fn => (message, ...args) => {
};


export const getMultiUserStatus = (meetingId) => {
const data = WhiteboardMultiUser.findOne({ meetingId });
export const getMultiUserStatus = (meetingId, whiteboardId) => {
const data = WhiteboardMultiUser.findOne({ meetingId, whiteboardId });

if (data) {
return data.multiUser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const proccess = () => {
return;
}
cursorRecieverIsRunning = true;

Object.keys(cursorQueue).forEach(meetingId => {
CursorStreamer.emit('message', { meetingId, cursors: cursorQueue[meetingId] });
});
Expand All @@ -21,18 +22,16 @@ const proccess = () => {
};

export default function handleCursorUpdate({ header, body }, meetingId) {
const userId = header.userId;
const x = body.xPercent;
const y = body.yPercent;
const { userId } = header;
check(body, Object);

check(meetingId, String);
check(userId, String);
check(x, Number);
check(y, Number);

if(!cursorQueue.hasOwnProperty(meetingId)) {
cursorQueue[meetingId] = {};
}
// overwrite since we dont care about the other positions
cursorQueue[meetingId][userId] = { x, y };
cursorQueue[meetingId][userId] = body;
if (!cursorRecieverIsRunning) proccess();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Acl from '/imports/startup/acl';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

import isPodPresenter from '/imports/api/presentation-pods/server/utils/isPodPresenter';

export default function publishCursorUpdate(credentials, payload) {
const REDIS_CONFIG = Meteor.settings.private.redis;
Expand All @@ -18,9 +19,13 @@ export default function publishCursorUpdate(credentials, payload) {
check(payload, {
xPercent: Number,
yPercent: Number,
whiteboardId: String,
});

const allowed = Acl.can('methods.moveCursor', credentials) || getMultiUserStatus(meetingId);
const { whiteboardId } = payload;

const allowed = isPodPresenter(meetingId, whiteboardId, requesterUserId)
|| getMultiUserStatus(meetingId, whiteboardId);
if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to move the cursor`);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Logger from '/imports/startup/server/logger';
import Cursor from '/imports/api/cursor';
import { check } from 'meteor/check';

export default function updateCursor(meetingId, whiteboardId, userId, x = -1, y = -1) {
check(meetingId, String);
check(userId, String);
check(x, Number);
check(y, Number);

const selector = {
meetingId,
whiteboardId,
userId,
};

const modifier = {
$set: {
meetingId,
whiteboardId,
userId,
x,
y,
},
};

const cb = (err, numChanged) => {
if (err) {
Logger.error(`Upserting cursor to collection: ${err}`);
return;
}

const { insertedId } = numChanged;
if (insertedId) {
Logger.info(`Initialized cursor meeting=${meetingId}`);
}

if (numChanged) {
Logger.debug(`Updated cursor meeting=${meetingId}`);
}
};

return Cursor.upsert(selector, modifier, cb);
}
12 changes: 12 additions & 0 deletions bigbluebutton-html5/imports/api/presentation-pods/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Meteor } from 'meteor/meteor';

const PresentationPods = new Mongo.Collection('presentation-pods');

if (Meteor.isServer) {
// types of queries for the presentation pods:
// 1. meetingId, podId ( 4 )

PresentationPods._ensureIndex({ meetingId: 1, podId: 1 });
}

export default PresentationPods;
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import RedisPubSub from '/imports/startup/server/redis';
import handleCreateNewPresentationPod from './handlers/createNewPresentationPod';
import handleRemovePresentationPod from './handlers/removePresentationPod';
import handleSyncGetPresentationPods from './handlers/syncGetPresentationPods';
import handleSetPresenterInPod from './handlers/setPresenterInPod';

RedisPubSub.on('CreateNewPresentationPodEvtMsg', handleCreateNewPresentationPod);
RedisPubSub.on('RemovePresentationPodEvtMsg', handleRemovePresentationPod);
RedisPubSub.on('SetPresenterInPodRespMsg', handleSetPresenterInPod);
RedisPubSub.on('SyncGetPresentationPodsRespMsg', handleSyncGetPresentationPods);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { check } from 'meteor/check';
import addPresentationPod from '../modifiers/addPresentationPod';

export default function handleCreateNewPresentationPod({ body }, meetingId) {
check(body, {
currentPresenterId: String,
podId: String,
});
check(meetingId, String);

const { currentPresenterId, podId } = body;

const pod = {
currentPresenterId,
podId,
};

addPresentationPod(meetingId, pod);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { check } from 'meteor/check';
import removePresentationPod from '../modifiers/removePresentationPod';

export default function handleRemovePresentationPod({ body }, meetingId) {
check(body, Object);
check(meetingId, String);

const { podId } = body;

check(podId, String);

removePresentationPod(meetingId, podId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { check } from 'meteor/check';
import setPresenterInPod from '../modifiers/setPresenterInPod';

export default function handleSetPresenterInPod({ body }, meetingId) {
check(body, Object);

const { podId, nextPresenterId } = body;

check(podId, String);
check(nextPresenterId, String);

setPresenterInPod(meetingId, podId, nextPresenterId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { check } from 'meteor/check';
import PresentationPods from '/imports/api/presentation-pods';
import removePresentationPod from '../modifiers/removePresentationPod';
import addPresentationPod from '../modifiers/addPresentationPod';

export default function handleSyncGetPresentationPods({ body }, meetingId) {
check(body, Object);
check(meetingId, String);

const { pods } = body;
check(pods, Array);

const presentationPodIds = pods.map(pod => pod.id);

const presentationPodsToRemove = PresentationPods.find({
meetingId,
podId: { $nin: presentationPodIds },
}).fetch();

presentationPodsToRemove.forEach(p => removePresentationPod(meetingId, p.podId));

pods.forEach((pod) => {
// 'podId' and 'currentPresenterId' for some reason called 'id' and 'currentPresenter'
// in this message
const {
id: podId,
currentPresenter: currentPresenterId,
presentations,
} = pod;
addPresentationPod(meetingId, { podId, currentPresenterId }, presentations);
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import './eventHandlers';
// import './methods';
import './publishers';