Adjusted multi-user for 2.1

This commit is contained in:
Oleksandr Zhurbenko 2018-04-09 16:18:49 -07:00
parent a3f21ee1ce
commit 0c8f1a3bfd
29 changed files with 137 additions and 115 deletions

View File

@ -1,5 +1,6 @@
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';
@ -7,9 +8,12 @@ export default function handleWhiteboardAnnotations({ body }, meetingId) {
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 = [];
@ -18,5 +22,7 @@ export default function handleWhiteboardAnnotations({ body }, meetingId) {
annotationsAdded.push(addAnnotation(meetingId, wbId, userId, annotation));
});
modifyWhiteboardAccess(meetingId, whiteboardId, multiUser);
return annotationsAdded;
}

View File

@ -16,7 +16,7 @@ export default function clearWhiteboard(credentials, whiteboardId) {
check(requesterToken, String);
check(whiteboardId, String);
const allowed = Acl.can('methods.clearWhiteboard', credentials) || getMultiUserStatus(meetingId);
const allowed = Acl.can('methods.clearWhiteboard', credentials) || getMultiUserStatus(meetingId, whiteboardId);
if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to clear the whiteboard`);
}

View File

@ -21,7 +21,7 @@ function isLastMessage(annotation, userId) {
return false;
}
export default function sendAnnotation(credentials, annotation) {
export default function sendAnnotation(credentials, annotation, whiteboardId) {
const REDIS_CONFIG = Meteor.settings.private.redis;
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
const EVENT_NAME = 'SendWhiteboardAnnotationPubMsg';
@ -32,6 +32,7 @@ export default function sendAnnotation(credentials, annotation) {
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)
@ -41,7 +42,7 @@ export default function sendAnnotation(credentials, annotation) {
// 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) ||
getMultiUserStatus(meetingId, whiteboardId) ||
isLastMessage(annotation, requesterUserId);
if (!allowed) {

View File

@ -16,7 +16,7 @@ export default function undoAnnotation(credentials, whiteboardId) {
check(requesterToken, String);
check(whiteboardId, String);
const allowed = Acl.can('methods.undoAnnotation', credentials) || getMultiUserStatus(meetingId);
const allowed = Acl.can('methods.undoAnnotation', credentials) || getMultiUserStatus(meetingId, whiteboardId);
if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to undo the annotation`);
}

View File

@ -13,8 +13,8 @@ export const indexOf = [].indexOf || function (item) {
// used in 1.1
export const inReplyToHTML5Client = arg => arg.routing.userId === 'nodeJSapp';
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;

View File

@ -18,9 +18,10 @@ export default function publishCursorUpdate(credentials, payload) {
check(payload, {
xPercent: Number,
yPercent: Number,
whiteboardId: String,
});
const allowed = Acl.can('methods.moveCursor', credentials) || getMultiUserStatus(meetingId);
const allowed = Acl.can('methods.moveCursor', credentials) || getMultiUserStatus(meetingId, payload.whiteboardId);
if (!allowed) {
throw new Meteor.Error('not-allowed', `User ${requesterUserId} is not allowed to move the cursor`);
}

View File

@ -1,7 +1,4 @@
import RedisPubSub from '/imports/startup/server/redis';
import handleGetWhiteboardAccess from './handlers/getWhiteboardAccess';
import handleModifyWhiteboardAccess from './handlers/modifyWhiteboardAccess';
RedisPubSub.on('GetWhiteboardAccessRespMsg', handleGetWhiteboardAccess);
RedisPubSub.on('SyncGetWhiteboardAccessRespMsg', handleGetWhiteboardAccess);
RedisPubSub.on('ModifyWhiteboardAccessEvtMsg', handleModifyWhiteboardAccess);

View File

@ -1,37 +1,12 @@
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
import modifyWhiteboardAccess from '../modifiers/modifyWhiteboardAccess';
export default function handleModifyWhiteboardAccess({ body }, meetingId) {
const { multiUser } = body;
const { multiUser, whiteboardId } = body;
check(multiUser, Boolean);
check(whiteboardId, String);
check(meetingId, String);
const selector = {
meetingId,
};
const modifier = {
$set: {
meetingId,
multiUser,
},
};
const cb = (err, numChanged) => {
if (err) {
return Logger.error(`Error while adding an entry to Multi-User collection: ${err}`);
}
const { insertedId } = numChanged;
if (insertedId) {
return Logger.info(`Added multiUser flag to the meetingId=${meetingId}`);
}
return Logger.info(`Upserted multiUser flag into meetingId=${meetingId}`);
};
return WhiteboardMultiUser.upsert(selector, modifier, cb);
return modifyWhiteboardAccess(meetingId, whiteboardId, multiUser);
}

View File

@ -2,21 +2,21 @@ import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
export default function handleGetWhiteboardAccess({ body }, meetingId) {
const { multiUser } = body;
check(multiUser, Boolean);
export default function modifyWhiteboardAccess(meetingId, whiteboardId, multiUser) {
check(meetingId, String);
check(whiteboardId, String);
check(multiUser, Boolean);
const selector = {
meetingId,
whiteboardId,
};
const modifier = {
$set: {
meetingId,
multiUser,
},
meetingId,
whiteboardId,
multiUser,
};
@ -27,10 +27,10 @@ export default function handleGetWhiteboardAccess({ body }, meetingId) {
const { insertedId } = numChanged;
if (insertedId) {
return Logger.info(`Added multiUser flag to the meetingId=${meetingId}`);
return Logger.info(`Added multiUser flag meetingId=${meetingId} whiteboardId=${whiteboardId}`);
}
return Logger.info(`Upserted multiUser flag into meetingId=${meetingId}`);
return Logger.info(`Upserted multiUser flag meetingId=${meetingId} whiteboardId=${whiteboardId}`);
};
return WhiteboardMultiUser.upsert(selector, modifier, cb);

View File

@ -200,6 +200,7 @@ export default class PresentationArea extends Component {
whiteboardId={slideObj.id}
/>
<CursorWrapperContainer
whiteboardId={slideObj.id}
widthRatio={slideObj.widthRatio}
physicalWidthRatio={adjustedSizes.width / width}
slideWidth={width}
@ -231,6 +232,7 @@ export default class PresentationArea extends Component {
return (
<PresentationOverlayContainer
whiteboardId={slideObj.id}
slideWidth={width}
slideHeight={height}
getSvgRef={this.getSvgRef}

View File

@ -7,8 +7,18 @@ const PresentationAreaContainer = props => (
<PresentationArea {...props} />
);
export default withTracker(() => ({
currentSlide: PresentationAreaService.getCurrentSlide(),
userIsPresenter: PresentationAreaService.isPresenter(),
multiUser: PresentationAreaService.getMultiUserStatus(),
}))(PresentationAreaContainer);
export default withTracker(() => {
const currentSlide = PresentationAreaService.getCurrentSlide();
const userIsPresenter = PresentationAreaService.isPresenter();
const multiUser = currentSlide ?
PresentationAreaService.getMultiUserStatus(currentSlide.id) :
false;
const data = {
currentSlide,
userIsPresenter,
multiUser,
};
return data;
})(PresentationAreaContainer);

View File

@ -39,9 +39,10 @@ const CursorWrapperContainer = ({ presenterCursorId, multiUserCursorIds, ...rest
</g>
);
export default withTracker(() => {
const { presenterCursorId, multiUserCursorIds } = CursorWrapperService.getCurrentCursorIds();
const isMultiUser = CursorWrapperService.getMultiUserStatus();
export default withTracker((params) => {
const { whiteboardId } = params;
const { presenterCursorId, multiUserCursorIds } = CursorWrapperService.getCurrentCursorIds(whiteboardId);
const isMultiUser = CursorWrapperService.getMultiUserStatus(whiteboardId);
return {
presenterCursorId,

View File

@ -3,14 +3,14 @@ import Auth from '/imports/ui/services/auth';
import Cursor from '/imports/api/cursor';
import Users from '/imports/api/users';
const getMultiUserStatus = () => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID });
const getMultiUserStatus = (whiteboardId) => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
return data ? data.multiUser : false;
};
const getPresenterCursorId = userId => Cursor.findOne({ userId }, { fields: { _id: 1 } });
const getCurrentCursorIds = () => {
const getCurrentCursorIds = (whiteboardId) => {
// object to return
const data = {};
@ -23,7 +23,7 @@ const getCurrentCursorIds = () => {
}
// checking whether multiUser mode is on or off
const isMultiUser = getMultiUserStatus();
const isMultiUser = getMultiUserStatus(whiteboardId);
// it's a multi-user mode - fetching all the cursors except the presenter's
if (isMultiUser) {

View File

@ -64,7 +64,11 @@ export default class PresentationOverlay extends Component {
this.lastSentClientY = currentClientY;
// sending the update to the server
this.props.updateCursor({ xPercent: transformedSvgPoint.x, yPercent: transformedSvgPoint.y });
this.props.updateCursor({
xPercent: transformedSvgPoint.x,
yPercent: transformedSvgPoint.y,
whiteboardId: this.props.whiteboardId,
});
}
}
@ -204,6 +208,8 @@ export default class PresentationOverlay extends Component {
}
PresentationOverlay.propTypes = {
whiteboardId: PropTypes.string.isRequired,
// Defines a function which returns a reference to the main svg object
getSvgRef: PropTypes.func.isRequired,

View File

@ -37,8 +37,8 @@ const isPresenter = () => {
return currentUser ? currentUser.presenter : false;
};
const getMultiUserStatus = () => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID });
const getMultiUserStatus = (whiteboardId) => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
return data ? data.multiUser : false;
};

View File

@ -14,8 +14,7 @@ const ANNOTATION_CONFIG = Meteor.settings.public.whiteboard.annotations;
const DRAW_END = ANNOTATION_CONFIG.status.end;
export default class AnnotationFactory extends Component {
static renderStaticAnnotation(annotationInfo, slideWidth, slideHeight, drawObject) {
static renderStaticAnnotation(annotationInfo, slideWidth, slideHeight, drawObject, whiteboardId) {
return (
<StaticAnnotation
key={annotationInfo._id}
@ -23,11 +22,12 @@ export default class AnnotationFactory extends Component {
drawObject={drawObject}
slideWidth={slideWidth}
slideHeight={slideHeight}
whiteboardId={whiteboardId}
/>
);
}
static renderReactiveAnnotation(annotationInfo, slideWidth, slideHeight, drawObject) {
static renderReactiveAnnotation(annotationInfo, slideWidth, slideHeight, drawObject, whiteboardId) {
return (
<ReactiveAnnotationContainer
key={annotationInfo._id}
@ -35,6 +35,7 @@ export default class AnnotationFactory extends Component {
drawObject={drawObject}
slideWidth={slideWidth}
slideHeight={slideHeight}
whiteboardId={whiteboardId}
/>
);
}
@ -49,18 +50,20 @@ export default class AnnotationFactory extends Component {
if (annotationInfo.status === DRAW_END) {
return AnnotationFactory.renderStaticAnnotation(
annotationInfo,
this.props.slideWidth,
this.props.slideHeight,
drawObject,
);
annotationInfo,
this.props.slideWidth,
this.props.slideHeight,
drawObject,
this.props.whiteboardId,
);
}
return AnnotationFactory.renderReactiveAnnotation(
annotationInfo,
this.props.slideWidth,
this.props.slideHeight,
drawObject,
);
annotationInfo,
this.props.slideWidth,
this.props.slideHeight,
drawObject,
this.props.whiteboardId,
);
}
render() {
@ -76,6 +79,7 @@ export default class AnnotationFactory extends Component {
}
AnnotationFactory.propTypes = {
whiteboardId: PropTypes.string.isRequired,
// initial width and height of the slide are required
// to calculate the coordinates for each annotation
slideWidth: PropTypes.number.isRequired,

View File

@ -10,11 +10,13 @@ const ReactiveAnnotation = (props) => {
annotation={props.annotation.annotationInfo}
slideWidth={props.slideWidth}
slideHeight={props.slideHeight}
whiteboardId={props.whiteboardId}
/>
);
};
ReactiveAnnotation.propTypes = {
whiteboardId: PropTypes.string.isRequired,
annotation: PropTypes.objectOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,

View File

@ -12,6 +12,7 @@ const ReactiveAnnotationContainer = (props) => {
slideWidth={props.slideWidth}
slideHeight={props.slideHeight}
drawObject={props.drawObject}
whiteboardId={props.whiteboardId}
/>
);
}
@ -29,6 +30,7 @@ export default withTracker((params) => {
})(ReactiveAnnotationContainer);
ReactiveAnnotationContainer.propTypes = {
whiteboardId: PropTypes.string.isRequired,
annotation: PropTypes.objectOf(PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,

View File

@ -3,7 +3,6 @@ import PropTypes from 'prop-types';
import StaticAnnotationService from './service';
export default class StaticAnnotation extends React.Component {
// completed annotations should never update
shouldComponentUpdate() {
return false;
@ -19,12 +18,14 @@ export default class StaticAnnotation extends React.Component {
annotation={annotation.annotationInfo}
slideWidth={this.props.slideWidth}
slideHeight={this.props.slideHeight}
whiteboardId={this.props.whiteboardId}
/>
);
}
}
StaticAnnotation.propTypes = {
whiteboardId: PropTypes.string.isRequired,
shapeId: PropTypes.string.isRequired,
drawObject: PropTypes.func.isRequired,
slideWidth: PropTypes.number.isRequired,

View File

@ -7,10 +7,12 @@ const AnnotationGroup = props => (
annotationsInfo={props.annotationsInfo}
slideWidth={props.slideWidth}
slideHeight={props.slideHeight}
whiteboardId={props.whiteboardId}
/>
);
AnnotationGroup.propTypes = {
whiteboardId: PropTypes.string.isRequired,
// initial width and height of the slide are required
// to calculate the coordinates for each annotation
slideWidth: PropTypes.number.isRequired,

View File

@ -9,6 +9,7 @@ const AnnotationGroupContainer = props => (
annotationsInfo={props.annotationsInfo}
slideWidth={props.width}
slideHeight={props.height}
whiteboardId={props.whiteboardId}
/>
);
@ -22,6 +23,7 @@ export default withTracker((params) => {
})(AnnotationGroupContainer);
AnnotationGroupContainer.propTypes = {
whiteboardId: PropTypes.string.isRequired,
// initial width and height of the slide; required to calculate the annotations' coordinates
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,

View File

@ -8,8 +8,9 @@ const TextDrawContainer = props => (
);
export default withTracker((params) => {
const { whiteboardId } = params;
const isPresenter = TextShapeService.isPresenter();
const isMultiUser = TextShapeService.getMultiUserStatus();
const isMultiUser = TextShapeService.getMultiUserStatus(whiteboardId);
const activeTextShapeId = TextShapeService.activeTextShapeId();
let isActive = false;

View File

@ -26,8 +26,8 @@ const isPresenter = () => {
return currentUser ? currentUser.presenter : false;
};
const getMultiUserStatus = () => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID });
const getMultiUserStatus = (whiteboardId) => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
return data ? data.multiUser : false;
};

View File

@ -182,7 +182,7 @@ export default class PencilDrawListener extends Component {
annotation.annotationInfo.dimensions = dimensions;
}
sendAnnotation(annotation);
sendAnnotation(annotation, whiteboardId);
}
sendLastMessage() {

View File

@ -4,8 +4,8 @@ import Auth from '/imports/ui/services/auth';
const DRAW_SETTINGS = 'drawSettings';
const sendAnnotation = (annotation) => {
makeCall('sendAnnotation', annotation);
const sendAnnotation = (annotation, whiteboardId) => {
makeCall('sendAnnotation', annotation, whiteboardId);
};
const getWhiteboardToolbarValues = () => {

View File

@ -258,14 +258,16 @@ export default class ShapeDrawListener extends Component {
// we use the same function for all of them
handleDrawCommonAnnotation(startPoint, endPoint, status, id, shapeType) {
const { normalizeThickness, sendAnnotation } = this.props.actions;
const { whiteboardId, userId } = this.props;
const { color, thickness } = this.props.drawSettings;
const annotation = {
id,
status,
annotationType: shapeType,
annotationInfo: {
color: this.props.drawSettings.color,
thickness: normalizeThickness(this.props.drawSettings.thickness),
color,
thickness: normalizeThickness(thickness),
points: [
startPoint.x,
startPoint.y,
@ -273,16 +275,16 @@ export default class ShapeDrawListener extends Component {
endPoint.y,
],
id,
whiteboardId: this.props.whiteboardId,
whiteboardId,
status,
type: shapeType,
},
wbId: this.props.whiteboardId,
userId: this.props.userId,
wbId: whiteboardId,
userId,
position: 0,
};
sendAnnotation(annotation);
sendAnnotation(annotation, whiteboardId);
}
render() {

View File

@ -340,6 +340,8 @@ export default class TextDrawListener extends Component {
handleDrawText(startPoint, width, height, status, id, text) {
const { normalizeFont, sendAnnotation } = this.props.actions;
const { whiteboardId, userId } = this.props;
const { color, textFontSize } = this.props.drawSettings;
const annotation = {
id,
@ -348,24 +350,24 @@ export default class TextDrawListener extends Component {
annotationInfo: {
x: startPoint.x, // left corner
y: startPoint.y, // left corner
fontColor: this.props.drawSettings.color,
calcedFontSize: normalizeFont(this.props.drawSettings.textFontSize), // fontsize
fontColor: color,
calcedFontSize: normalizeFont(textFontSize), // fontsize
textBoxWidth: width, // width
text,
textBoxHeight: height, // height
id,
whiteboardId: this.props.whiteboardId,
whiteboardId,
status,
fontSize: this.props.drawSettings.textFontSize,
dataPoints: `${startPoint.x},${startPoint.y}`,
type: 'text',
},
wbId: this.props.whiteboardId,
userId: this.props.userId,
wbId: whiteboardId,
userId,
position: 0,
};
sendAnnotation(annotation);
sendAnnotation(annotation, whiteboardId);
}
render() {

View File

@ -7,20 +7,25 @@ const WhiteboardToolbarContainer = props => (
<WhiteboardToolbar {...props} />
);
export default withTracker(() => ({
actions: {
undoAnnotation: WhiteboardToolbarService.undoAnnotation,
clearWhiteboard: WhiteboardToolbarService.clearWhiteboard,
changeWhiteboardMode: WhiteboardToolbarService.changeWhiteboardMode,
setInitialWhiteboardToolbarValues: WhiteboardToolbarService.setInitialWhiteboardToolbarValues,
getCurrentDrawSettings: WhiteboardToolbarService.getCurrentDrawSettings,
setFontSize: WhiteboardToolbarService.setFontSize,
setTool: WhiteboardToolbarService.setTool,
setThickness: WhiteboardToolbarService.setThickness,
setColor: WhiteboardToolbarService.setColor,
setTextShapeObject: WhiteboardToolbarService.setTextShapeObject,
},
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
multiUser: WhiteboardToolbarService.getMultiUserStatus(),
isPresenter: WhiteboardToolbarService.isPresenter(),
}))(WhiteboardToolbarContainer);
export default withTracker((params) => {
const { whiteboardId } = params;
const data = {
actions: {
undoAnnotation: WhiteboardToolbarService.undoAnnotation,
clearWhiteboard: WhiteboardToolbarService.clearWhiteboard,
changeWhiteboardMode: WhiteboardToolbarService.changeWhiteboardMode,
setInitialWhiteboardToolbarValues: WhiteboardToolbarService.setInitialWhiteboardToolbarValues,
getCurrentDrawSettings: WhiteboardToolbarService.getCurrentDrawSettings,
setFontSize: WhiteboardToolbarService.setFontSize,
setTool: WhiteboardToolbarService.setTool,
setThickness: WhiteboardToolbarService.setThickness,
setColor: WhiteboardToolbarService.setColor,
setTextShapeObject: WhiteboardToolbarService.setTextShapeObject,
},
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
multiUser: WhiteboardToolbarService.getMultiUserStatus(whiteboardId),
isPresenter: WhiteboardToolbarService.isPresenter(),
};
return data;
})(WhiteboardToolbarContainer);

View File

@ -57,8 +57,8 @@ const getTextShapeActiveId = () => {
return drawSettings ? drawSettings.textShape.textShapeActiveId : '';
};
const getMultiUserStatus = () => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID });
const getMultiUserStatus = (whiteboardId) => {
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
return data ? data.multiUser : false;
};