Merge pull request #11669 from pedrobmarin/2.3-per-user-wb-v2
[Refactor] Whiteboard individual access
This commit is contained in:
commit
ba9665a2c8
@ -49,7 +49,6 @@ trait SystemConfiguration {
|
|||||||
|
|
||||||
lazy val endMeetingWhenNoMoreAuthedUsers = Try(config.getBoolean("apps.endMeetingWhenNoMoreAuthedUsers")).getOrElse(false)
|
lazy val endMeetingWhenNoMoreAuthedUsers = Try(config.getBoolean("apps.endMeetingWhenNoMoreAuthedUsers")).getOrElse(false)
|
||||||
lazy val endMeetingWhenNoMoreAuthedUsersAfterMinutes = Try(config.getInt("apps.endMeetingWhenNoMoreAuthedUsersAfterMinutes")).getOrElse(2)
|
lazy val endMeetingWhenNoMoreAuthedUsersAfterMinutes = Try(config.getInt("apps.endMeetingWhenNoMoreAuthedUsersAfterMinutes")).getOrElse(2)
|
||||||
lazy val multiUserWhiteboardDefault = Try(config.getBoolean("whiteboard.multiUserDefault")).getOrElse(false)
|
|
||||||
|
|
||||||
// Redis server configuration
|
// Redis server configuration
|
||||||
lazy val redisHost = Try(config.getString("redis.host")).getOrElse("127.0.0.1")
|
lazy val redisHost = Try(config.getString("redis.host")).getOrElse("127.0.0.1")
|
||||||
|
@ -25,7 +25,14 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def createWhiteboard(wbId: String): Whiteboard = {
|
private def createWhiteboard(wbId: String): Whiteboard = {
|
||||||
new Whiteboard(wbId, multiUserWhiteboardDefault, System.currentTimeMillis(), 0, new HashMap[String, List[AnnotationVO]]())
|
new Whiteboard(
|
||||||
|
wbId,
|
||||||
|
Array.empty[String],
|
||||||
|
Array.empty[String],
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
0,
|
||||||
|
new HashMap[String, List[AnnotationVO]]()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def getAnnotationsByUserId(wb: Whiteboard, id: String): List[AnnotationVO] = {
|
private def getAnnotationsByUserId(wb: Whiteboard, id: String): List[AnnotationVO] = {
|
||||||
@ -184,7 +191,7 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
if (hasWhiteboard(wbId)) {
|
if (hasWhiteboard(wbId)) {
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
|
|
||||||
if (wb.multiUser) {
|
if (wb.multiUser.contains(userId)) {
|
||||||
if (wb.annotationsMap.contains(userId)) {
|
if (wb.annotationsMap.contains(userId)) {
|
||||||
val newWb = wb.copy(annotationsMap = wb.annotationsMap - userId)
|
val newWb = wb.copy(annotationsMap = wb.annotationsMap - userId)
|
||||||
saveWhiteboard(newWb)
|
saveWhiteboard(newWb)
|
||||||
@ -205,7 +212,7 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
var last: Option[AnnotationVO] = None
|
var last: Option[AnnotationVO] = None
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
|
|
||||||
if (wb.multiUser) {
|
if (wb.multiUser.contains(userId)) {
|
||||||
val usersAnnotations = getAnnotationsByUserId(wb, userId)
|
val usersAnnotations = getAnnotationsByUserId(wb, userId)
|
||||||
|
|
||||||
//not empty and head id equals annotation id
|
//not empty and head id equals annotation id
|
||||||
@ -234,13 +241,21 @@ class WhiteboardModel extends SystemConfiguration {
|
|||||||
wb.copy(annotationsMap = newAnnotationsMap)
|
wb.copy(annotationsMap = newAnnotationsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
def modifyWhiteboardAccess(wbId: String, multiUser: Boolean) {
|
def modifyWhiteboardAccess(wbId: String, multiUser: Array[String]) {
|
||||||
val wb = getWhiteboard(wbId)
|
val wb = getWhiteboard(wbId)
|
||||||
val newWb = wb.copy(multiUser = multiUser, changedModeOn = System.currentTimeMillis())
|
val newWb = wb.copy(multiUser = multiUser, oldMultiUser = wb.multiUser, changedModeOn = System.currentTimeMillis())
|
||||||
saveWhiteboard(newWb)
|
saveWhiteboard(newWb)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getWhiteboardAccess(wbId: String): Boolean = getWhiteboard(wbId).multiUser
|
def getWhiteboardAccess(wbId: String): Array[String] = getWhiteboard(wbId).multiUser
|
||||||
|
|
||||||
|
def hasWhiteboardAccess(wbId: String, userId: String): Boolean = {
|
||||||
|
val wb = getWhiteboard(wbId)
|
||||||
|
wb.multiUser.contains(userId) || {
|
||||||
|
val lastChange = System.currentTimeMillis() - wb.changedModeOn
|
||||||
|
wb.oldMultiUser.contains(userId) && lastChange < 5000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def getChangedModeOn(wbId: String): Long = getWhiteboard(wbId).changedModeOn
|
def getChangedModeOn(wbId: String): Long = getWhiteboard(wbId).changedModeOn
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ trait ClearWhiteboardPubMsgHdlr extends RightsManagementTrait {
|
|||||||
bus.outGW.send(msgEvent)
|
bus.outGW.send(msgEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterWhiteboardMessage(msg.body.whiteboardId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
if (filterWhiteboardMessage(msg.body.whiteboardId, msg.header.userId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
val reason = "No permission to clear the whiteboard."
|
val reason = "No permission to clear the whiteboard."
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
|
@ -9,7 +9,7 @@ trait GetWhiteboardAnnotationsReqMsgHdlr {
|
|||||||
|
|
||||||
def handle(msg: GetWhiteboardAnnotationsReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
def handle(msg: GetWhiteboardAnnotationsReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
|
||||||
|
|
||||||
def broadcastEvent(msg: GetWhiteboardAnnotationsReqMsg, history: Array[AnnotationVO], multiUser: Boolean): Unit = {
|
def broadcastEvent(msg: GetWhiteboardAnnotationsReqMsg, history: Array[AnnotationVO], multiUser: Array[String]): Unit = {
|
||||||
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
val routing = Routing.addMsgToHtml5InstanceIdRouting(liveMeeting.props.meetingProp.intId, liveMeeting.props.systemProps.html5InstanceId.toString)
|
||||||
|
|
||||||
val envelope = BbbCoreEnvelope(GetWhiteboardAnnotationsRespMsg.NAME, routing)
|
val envelope = BbbCoreEnvelope(GetWhiteboardAnnotationsRespMsg.NAME, routing)
|
||||||
|
@ -21,7 +21,7 @@ trait ModifyWhiteboardAccessPubMsgHdlr extends RightsManagementTrait {
|
|||||||
bus.outGW.send(msgEvent)
|
bus.outGW.send(msgEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterWhiteboardMessage(msg.body.whiteboardId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
if (filterWhiteboardMessage(msg.body.whiteboardId, msg.header.userId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
val reason = "No permission to modify access to the whiteboard."
|
val reason = "No permission to modify access to the whiteboard."
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
|
@ -21,7 +21,7 @@ trait SendCursorPositionPubMsgHdlr extends RightsManagementTrait {
|
|||||||
bus.outGW.send(msgEvent)
|
bus.outGW.send(msgEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterWhiteboardMessage(msg.body.whiteboardId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
if (filterWhiteboardMessage(msg.body.whiteboardId, msg.header.userId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
val reason = "No permission to send your cursor position."
|
val reason = "No permission to send your cursor position."
|
||||||
// Just drop messages as these might be delayed messages from multi-user whiteboard. Don't want to
|
// Just drop messages as these might be delayed messages from multi-user whiteboard. Don't want to
|
||||||
|
@ -71,7 +71,7 @@ trait SendWhiteboardAnnotationPubMsgHdlr extends RightsManagementTrait {
|
|||||||
WhiteboardKeyUtil.DRAW_UPDATE_STATUS == annotation.status)
|
WhiteboardKeyUtil.DRAW_UPDATE_STATUS == annotation.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!excludedWbMsg(msg.body.annotation) && filterWhiteboardMessage(msg.body.annotation.wbId, liveMeeting) && permissionFailed(
|
if (!excludedWbMsg(msg.body.annotation) && filterWhiteboardMessage(msg.body.annotation.wbId, msg.header.userId, liveMeeting) && permissionFailed(
|
||||||
PermissionCheck.GUEST_LEVEL,
|
PermissionCheck.GUEST_LEVEL,
|
||||||
PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId
|
PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId
|
||||||
)) {
|
)) {
|
||||||
|
@ -21,7 +21,7 @@ trait UndoWhiteboardPubMsgHdlr extends RightsManagementTrait {
|
|||||||
bus.outGW.send(msgEvent)
|
bus.outGW.send(msgEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterWhiteboardMessage(msg.body.whiteboardId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
if (filterWhiteboardMessage(msg.body.whiteboardId, msg.header.userId, liveMeeting) && permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
|
||||||
val meetingId = liveMeeting.props.meetingProp.intId
|
val meetingId = liveMeeting.props.meetingProp.intId
|
||||||
val reason = "No permission to undo an annotation."
|
val reason = "No permission to undo an annotation."
|
||||||
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
|
||||||
|
@ -5,8 +5,16 @@ import akka.event.Logging
|
|||||||
import org.bigbluebutton.core.running.LiveMeeting
|
import org.bigbluebutton.core.running.LiveMeeting
|
||||||
import org.bigbluebutton.common2.msgs.AnnotationVO
|
import org.bigbluebutton.common2.msgs.AnnotationVO
|
||||||
import org.bigbluebutton.core.apps.WhiteboardKeyUtil
|
import org.bigbluebutton.core.apps.WhiteboardKeyUtil
|
||||||
|
import scala.collection.immutable.{ Map, List }
|
||||||
|
|
||||||
case class Whiteboard(id: String, multiUser: Boolean, changedModeOn: Long, annotationCount: Int, annotationsMap: scala.collection.immutable.Map[String, scala.collection.immutable.List[AnnotationVO]])
|
case class Whiteboard(
|
||||||
|
id: String,
|
||||||
|
multiUser: Array[String],
|
||||||
|
oldMultiUser: Array[String],
|
||||||
|
changedModeOn: Long,
|
||||||
|
annotationCount: Int,
|
||||||
|
annotationsMap: Map[String, List[AnnotationVO]]
|
||||||
|
)
|
||||||
|
|
||||||
class WhiteboardApp2x(implicit val context: ActorContext)
|
class WhiteboardApp2x(implicit val context: ActorContext)
|
||||||
extends SendCursorPositionPubMsgHdlr
|
extends SendCursorPositionPubMsgHdlr
|
||||||
@ -56,18 +64,18 @@ class WhiteboardApp2x(implicit val context: ActorContext)
|
|||||||
liveMeeting.wbModel.undoWhiteboard(whiteboardId, requesterId)
|
liveMeeting.wbModel.undoWhiteboard(whiteboardId, requesterId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getWhiteboardAccess(whiteboardId: String, liveMeeting: LiveMeeting): Boolean = {
|
def getWhiteboardAccess(whiteboardId: String, liveMeeting: LiveMeeting): Array[String] = {
|
||||||
liveMeeting.wbModel.getWhiteboardAccess(whiteboardId)
|
liveMeeting.wbModel.getWhiteboardAccess(whiteboardId)
|
||||||
}
|
}
|
||||||
|
|
||||||
def modifyWhiteboardAccess(whiteboardId: String, multiUser: Boolean, liveMeeting: LiveMeeting) {
|
def modifyWhiteboardAccess(whiteboardId: String, multiUser: Array[String], liveMeeting: LiveMeeting) {
|
||||||
liveMeeting.wbModel.modifyWhiteboardAccess(whiteboardId, multiUser)
|
liveMeeting.wbModel.modifyWhiteboardAccess(whiteboardId, multiUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
def filterWhiteboardMessage(whiteboardId: String, liveMeeting: LiveMeeting): Boolean = {
|
def filterWhiteboardMessage(whiteboardId: String, userId: String, liveMeeting: LiveMeeting): Boolean = {
|
||||||
// Need to check if the wb mode change from multi-user to single-user. Give 5sec allowance to
|
// Need to check if the wb mode change from multi-user to single-user. Give 5sec allowance to
|
||||||
// allow delayed messages to be handled as clients may have been sending messages while the wb
|
// allow delayed messages to be handled as clients may have been sending messages while the wb
|
||||||
// mode was changed. (ralam nov 22, 2017)
|
// mode was changed. (ralam nov 22, 2017)
|
||||||
if (!liveMeeting.wbModel.getWhiteboardAccess(whiteboardId) && liveMeeting.wbModel.getChangedModeOn(whiteboardId) > 5000) true else false
|
!liveMeeting.wbModel.hasWhiteboardAccess(whiteboardId, userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,3 @@ recording {
|
|||||||
# set zero to disable chapter break
|
# set zero to disable chapter break
|
||||||
chapterBreakLengthInMinutes = 0
|
chapterBreakLengthInMinutes = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
whiteboard {
|
|
||||||
multiUserDefault = false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ case class GetWhiteboardAnnotationsReqMsgBody(whiteboardId: String)
|
|||||||
|
|
||||||
object ModifyWhiteboardAccessPubMsg { val NAME = "ModifyWhiteboardAccessPubMsg" }
|
object ModifyWhiteboardAccessPubMsg { val NAME = "ModifyWhiteboardAccessPubMsg" }
|
||||||
case class ModifyWhiteboardAccessPubMsg(header: BbbClientMsgHeader, body: ModifyWhiteboardAccessPubMsgBody) extends StandardMsg
|
case class ModifyWhiteboardAccessPubMsg(header: BbbClientMsgHeader, body: ModifyWhiteboardAccessPubMsgBody) extends StandardMsg
|
||||||
case class ModifyWhiteboardAccessPubMsgBody(whiteboardId: String, multiUser: Boolean)
|
case class ModifyWhiteboardAccessPubMsgBody(whiteboardId: String, multiUser: Array[String])
|
||||||
|
|
||||||
object SendCursorPositionPubMsg { val NAME = "SendCursorPositionPubMsg" }
|
object SendCursorPositionPubMsg { val NAME = "SendCursorPositionPubMsg" }
|
||||||
case class SendCursorPositionPubMsg(header: BbbClientMsgHeader, body: SendCursorPositionPubMsgBody) extends StandardMsg
|
case class SendCursorPositionPubMsg(header: BbbClientMsgHeader, body: SendCursorPositionPubMsgBody) extends StandardMsg
|
||||||
@ -48,11 +48,11 @@ case class ClearWhiteboardEvtMsgBody(whiteboardId: String, userId: String, fullC
|
|||||||
|
|
||||||
object GetWhiteboardAnnotationsRespMsg { val NAME = "GetWhiteboardAnnotationsRespMsg" }
|
object GetWhiteboardAnnotationsRespMsg { val NAME = "GetWhiteboardAnnotationsRespMsg" }
|
||||||
case class GetWhiteboardAnnotationsRespMsg(header: BbbClientMsgHeader, body: GetWhiteboardAnnotationsRespMsgBody) extends BbbCoreMsg
|
case class GetWhiteboardAnnotationsRespMsg(header: BbbClientMsgHeader, body: GetWhiteboardAnnotationsRespMsgBody) extends BbbCoreMsg
|
||||||
case class GetWhiteboardAnnotationsRespMsgBody(whiteboardId: String, annotations: Array[AnnotationVO], multiUser: Boolean)
|
case class GetWhiteboardAnnotationsRespMsgBody(whiteboardId: String, annotations: Array[AnnotationVO], multiUser: Array[String])
|
||||||
|
|
||||||
object ModifyWhiteboardAccessEvtMsg { val NAME = "ModifyWhiteboardAccessEvtMsg" }
|
object ModifyWhiteboardAccessEvtMsg { val NAME = "ModifyWhiteboardAccessEvtMsg" }
|
||||||
case class ModifyWhiteboardAccessEvtMsg(header: BbbClientMsgHeader, body: ModifyWhiteboardAccessEvtMsgBody) extends BbbCoreMsg
|
case class ModifyWhiteboardAccessEvtMsg(header: BbbClientMsgHeader, body: ModifyWhiteboardAccessEvtMsgBody) extends BbbCoreMsg
|
||||||
case class ModifyWhiteboardAccessEvtMsgBody(whiteboardId: String, multiUser: Boolean)
|
case class ModifyWhiteboardAccessEvtMsgBody(whiteboardId: String, multiUser: Array[String])
|
||||||
|
|
||||||
object SendCursorPositionEvtMsg { val NAME = "SendCursorPositionEvtMsg" }
|
object SendCursorPositionEvtMsg { val NAME = "SendCursorPositionEvtMsg" }
|
||||||
case class SendCursorPositionEvtMsg(header: BbbClientMsgHeader, body: SendCursorPositionEvtMsgBody) extends BbbCoreMsg
|
case class SendCursorPositionEvtMsg(header: BbbClientMsgHeader, body: SendCursorPositionEvtMsgBody) extends BbbCoreMsg
|
||||||
|
@ -15,7 +15,7 @@ export default function handleWhiteboardAnnotations({ header, body }, meetingId)
|
|||||||
|
|
||||||
check(annotations, Array);
|
check(annotations, Array);
|
||||||
check(whiteboardId, String);
|
check(whiteboardId, String);
|
||||||
check(multiUser, Boolean);
|
check(multiUser, Array);
|
||||||
|
|
||||||
clearAnnotations(meetingId, whiteboardId);
|
clearAnnotations(meetingId, whiteboardId);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import modifyWhiteboardAccess from '../modifiers/modifyWhiteboardAccess';
|
|||||||
export default function handleModifyWhiteboardAccess({ body }, meetingId) {
|
export default function handleModifyWhiteboardAccess({ body }, meetingId) {
|
||||||
const { multiUser, whiteboardId } = body;
|
const { multiUser, whiteboardId } = body;
|
||||||
|
|
||||||
check(multiUser, Boolean);
|
check(multiUser, Array);
|
||||||
check(whiteboardId, String);
|
check(whiteboardId, String);
|
||||||
check(meetingId, String);
|
check(meetingId, String);
|
||||||
|
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import Users from '/imports/api/users';
|
||||||
|
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
||||||
|
|
||||||
|
const getMultiUser = (meetingId, whiteboardId) => {
|
||||||
|
const data = WhiteboardMultiUser.findOne(
|
||||||
|
{
|
||||||
|
meetingId,
|
||||||
|
whiteboardId,
|
||||||
|
}, { fields: { multiUser: 1 } },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.multiUser || !Array.isArray(data.multiUser)) return [];
|
||||||
|
|
||||||
|
return data.multiUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUsers = (meetingId) => {
|
||||||
|
const data = Users.find(
|
||||||
|
{ meetingId },
|
||||||
|
{ fields: { userId: 1 } },
|
||||||
|
).fetch();
|
||||||
|
|
||||||
|
if (!data) return [];
|
||||||
|
|
||||||
|
return data.map(user => user.userId);
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
getMultiUser,
|
||||||
|
getUsers,
|
||||||
|
};
|
@ -1,6 +1,12 @@
|
|||||||
import { Meteor } from 'meteor/meteor';
|
import { Meteor } from 'meteor/meteor';
|
||||||
import changeWhiteboardAccess from './methods/changeWhiteboardAccess';
|
import addGlobalAccess from './methods/addGlobalAccess';
|
||||||
|
import addIndividualAccess from './methods/addIndividualAccess';
|
||||||
|
import removeGlobalAccess from './methods/removeGlobalAccess';
|
||||||
|
import removeIndividualAccess from './methods/removeIndividualAccess';
|
||||||
|
|
||||||
Meteor.methods({
|
Meteor.methods({
|
||||||
changeWhiteboardAccess,
|
addGlobalAccess,
|
||||||
|
addIndividualAccess,
|
||||||
|
removeGlobalAccess,
|
||||||
|
removeIndividualAccess,
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
import { getUsers } from '/imports/api/whiteboard-multi-user/server/helpers';
|
||||||
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
|
||||||
|
export default function addGlobalAccess(whiteboardId) {
|
||||||
|
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||||
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
|
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
||||||
|
|
||||||
|
check(whiteboardId, String);
|
||||||
|
|
||||||
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
check(requesterUserId, String);
|
||||||
|
|
||||||
|
const multiUser = getUsers(meetingId);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
multiUser,
|
||||||
|
whiteboardId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
import { getMultiUser } from '/imports/api/whiteboard-multi-user/server/helpers';
|
||||||
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
|
||||||
|
export default function addIndividualAccess(whiteboardId, userId) {
|
||||||
|
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||||
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
|
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
||||||
|
|
||||||
|
check(whiteboardId, String);
|
||||||
|
check(userId, String);
|
||||||
|
|
||||||
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
check(requesterUserId, String);
|
||||||
|
|
||||||
|
const multiUser = getMultiUser(meetingId, whiteboardId);
|
||||||
|
|
||||||
|
if (!multiUser.includes(userId)) {
|
||||||
|
multiUser.push(userId);
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
multiUser,
|
||||||
|
whiteboardId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||||
|
}
|
||||||
|
}
|
@ -3,20 +3,20 @@ import { Meteor } from 'meteor/meteor';
|
|||||||
import { check } from 'meteor/check';
|
import { check } from 'meteor/check';
|
||||||
import { extractCredentials } from '/imports/api/common/server/helpers';
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
|
||||||
export default function changeWhiteboardAccess(multiUser, whiteboardId) {
|
export default function removeGlobalAccess(whiteboardId) {
|
||||||
const REDIS_CONFIG = Meteor.settings.private.redis;
|
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||||
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
||||||
|
|
||||||
|
check(whiteboardId, String);
|
||||||
|
|
||||||
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
check(meetingId, String);
|
check(meetingId, String);
|
||||||
check(requesterUserId, String);
|
check(requesterUserId, String);
|
||||||
check(multiUser, Boolean);
|
|
||||||
check(whiteboardId, String);
|
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
multiUser,
|
multiUser: [],
|
||||||
whiteboardId,
|
whiteboardId,
|
||||||
};
|
};
|
||||||
|
|
@ -0,0 +1,30 @@
|
|||||||
|
import RedisPubSub from '/imports/startup/server/redis';
|
||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
import { getMultiUser } from '/imports/api/whiteboard-multi-user/server/helpers';
|
||||||
|
import { extractCredentials } from '/imports/api/common/server/helpers';
|
||||||
|
|
||||||
|
export default function removeIndividualAccess(whiteboardId, userId) {
|
||||||
|
const REDIS_CONFIG = Meteor.settings.private.redis;
|
||||||
|
const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
|
||||||
|
const EVENT_NAME = 'ModifyWhiteboardAccessPubMsg';
|
||||||
|
|
||||||
|
check(whiteboardId, String);
|
||||||
|
check(userId, String);
|
||||||
|
|
||||||
|
const { meetingId, requesterUserId } = extractCredentials(this.userId);
|
||||||
|
|
||||||
|
check(meetingId, String);
|
||||||
|
check(requesterUserId, String);
|
||||||
|
|
||||||
|
const multiUser = getMultiUser(meetingId, whiteboardId);
|
||||||
|
|
||||||
|
if (multiUser.includes(userId)) {
|
||||||
|
const payload = {
|
||||||
|
multiUser: multiUser.filter(id => id !== userId),
|
||||||
|
whiteboardId,
|
||||||
|
};
|
||||||
|
|
||||||
|
return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
|||||||
export default function modifyWhiteboardAccess(meetingId, whiteboardId, multiUser) {
|
export default function modifyWhiteboardAccess(meetingId, whiteboardId, multiUser) {
|
||||||
check(meetingId, String);
|
check(meetingId, String);
|
||||||
check(whiteboardId, String);
|
check(whiteboardId, String);
|
||||||
check(multiUser, Boolean);
|
check(multiUser, Array);
|
||||||
|
|
||||||
const selector = {
|
const selector = {
|
||||||
meetingId,
|
meetingId,
|
||||||
|
@ -663,12 +663,9 @@ class PresentationArea extends PureComponent {
|
|||||||
currentSlide,
|
currentSlide,
|
||||||
podId,
|
podId,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { zoom, fitToWidth, isFullscreen } = this.state;
|
const { zoom, fitToWidth, isFullscreen } = this.state;
|
||||||
|
|
||||||
if (!currentSlide) {
|
if (!currentSlide) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PresentationToolbarContainer
|
<PresentationToolbarContainer
|
||||||
|
@ -10,6 +10,7 @@ import Auth from '/imports/ui/services/auth';
|
|||||||
import Meetings from '/imports/api/meetings';
|
import Meetings from '/imports/api/meetings';
|
||||||
import Users from '/imports/api/users';
|
import Users from '/imports/api/users';
|
||||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
|
|
||||||
const ROLE_VIEWER = Meteor.settings.public.user.role_viewer;
|
const ROLE_VIEWER = Meteor.settings.public.user.role_viewer;
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ export default withTracker(({ podId }) => {
|
|||||||
slidePosition,
|
slidePosition,
|
||||||
downloadPresentationUri: PresentationAreaService.downloadPresentationUri(podId),
|
downloadPresentationUri: PresentationAreaService.downloadPresentationUri(podId),
|
||||||
userIsPresenter: PresentationAreaService.isPresenter(podId) && !layoutSwapped,
|
userIsPresenter: PresentationAreaService.isPresenter(podId) && !layoutSwapped,
|
||||||
multiUser: PresentationAreaService.getMultiUserStatus(currentSlide && currentSlide.id)
|
multiUser: WhiteboardService.hasMultiUserAccess(currentSlide && currentSlide.id, Auth.userID)
|
||||||
&& !layoutSwapped,
|
&& !layoutSwapped,
|
||||||
presentationIsDownloadable,
|
presentationIsDownloadable,
|
||||||
mountPresentationArea: !!currentSlide,
|
mountPresentationArea: !!currentSlide,
|
||||||
|
@ -16,7 +16,7 @@ import PropTypes from 'prop-types';
|
|||||||
import { withTracker } from 'meteor/react-meteor-data';
|
import { withTracker } from 'meteor/react-meteor-data';
|
||||||
import CursorWrapperService from './service';
|
import CursorWrapperService from './service';
|
||||||
import CursorContainer from '../container';
|
import CursorContainer from '../container';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
|
|
||||||
const CursorWrapperContainer = ({ presenterCursorId, multiUserCursorIds, ...rest }) => (
|
const CursorWrapperContainer = ({ presenterCursorId, multiUserCursorIds, ...rest }) => (
|
||||||
<g>
|
<g>
|
||||||
@ -47,7 +47,7 @@ export default withTracker((params) => {
|
|||||||
const cursorIds = CursorWrapperService.getCurrentCursorIds(podId, whiteboardId);
|
const cursorIds = CursorWrapperService.getCurrentCursorIds(podId, whiteboardId);
|
||||||
const { presenterCursorId, multiUserCursorIds } = cursorIds;
|
const { presenterCursorId, multiUserCursorIds } = cursorIds;
|
||||||
|
|
||||||
const isMultiUser = CursorWrapperService.getMultiUserStatus(whiteboardId);
|
const isMultiUser = WhiteboardService.isMultiUserActive(whiteboardId);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
presenterCursorId,
|
presenterCursorId,
|
||||||
|
@ -1,15 +1,9 @@
|
|||||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
|
||||||
import PresentationPods from '/imports/api/presentation-pods';
|
import PresentationPods from '/imports/api/presentation-pods';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import Cursor from '/imports/ui/components/cursor/service';
|
import Cursor from '/imports/ui/components/cursor/service';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
import Users from '/imports/api/users';
|
import Users from '/imports/api/users';
|
||||||
|
|
||||||
const getMultiUserStatus = (whiteboardId) => {
|
|
||||||
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
|
|
||||||
return data ? data.multiUser : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPresenterCursorId = (whiteboardId, userId) =>
|
const getPresenterCursorId = (whiteboardId, userId) =>
|
||||||
Cursor.findOne(
|
Cursor.findOne(
|
||||||
{
|
{
|
||||||
@ -31,7 +25,7 @@ const getCurrentCursorIds = (podId, whiteboardId) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checking whether multiUser mode is on or off
|
// checking whether multiUser mode is on or off
|
||||||
const isMultiUser = getMultiUserStatus(whiteboardId);
|
const isMultiUser = WhiteboardService.isMultiUserActive(whiteboardId);
|
||||||
|
|
||||||
// it's a multi-user mode - fetching all the cursors except the presenter's
|
// it's a multi-user mode - fetching all the cursors except the presenter's
|
||||||
if (isMultiUser) {
|
if (isMultiUser) {
|
||||||
@ -60,5 +54,4 @@ const getCurrentCursorIds = (podId, whiteboardId) => {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
getCurrentCursorIds,
|
getCurrentCursorIds,
|
||||||
getMultiUserStatus,
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
|
||||||
import PresentationPods from '/imports/api/presentation-pods';
|
import PresentationPods from '/imports/api/presentation-pods';
|
||||||
import Presentations from '/imports/api/presentations';
|
import Presentations from '/imports/api/presentations';
|
||||||
import { Slides, SlidePositions } from '/imports/api/slides';
|
import { Slides, SlidePositions } from '/imports/api/slides';
|
||||||
@ -185,21 +184,12 @@ const isPresenter = (podId) => {
|
|||||||
return pod.currentPresenterId === Auth.userID;
|
return pod.currentPresenterId === Auth.userID;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMultiUserStatus = (whiteboardId) => {
|
|
||||||
const data = WhiteboardMultiUser.findOne({
|
|
||||||
meetingId: Auth.meetingID,
|
|
||||||
whiteboardId,
|
|
||||||
});
|
|
||||||
return data ? data.multiUser : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getCurrentSlide,
|
getCurrentSlide,
|
||||||
getSlidePosition,
|
getSlidePosition,
|
||||||
isPresenter,
|
isPresenter,
|
||||||
isPresentationDownloadable,
|
isPresentationDownloadable,
|
||||||
downloadPresentationUri,
|
downloadPresentationUri,
|
||||||
getMultiUserStatus,
|
|
||||||
currentSlidHasContent,
|
currentSlidHasContent,
|
||||||
parseCurrentSlideContent,
|
parseCurrentSlideContent,
|
||||||
getCurrentPresentation,
|
getCurrentPresentation,
|
||||||
|
@ -46,6 +46,7 @@ const UserAvatar = ({
|
|||||||
avatar,
|
avatar,
|
||||||
noVoice,
|
noVoice,
|
||||||
className,
|
className,
|
||||||
|
whiteboardAccess,
|
||||||
}) => (
|
}) => (
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@ -54,6 +55,7 @@ const UserAvatar = ({
|
|||||||
className={cx(styles.avatar, {
|
className={cx(styles.avatar, {
|
||||||
[styles.moderator]: moderator,
|
[styles.moderator]: moderator,
|
||||||
[styles.presenter]: presenter,
|
[styles.presenter]: presenter,
|
||||||
|
[styles.whiteboardAccess]: whiteboardAccess && !presenter,
|
||||||
[styles.muted]: muted,
|
[styles.muted]: muted,
|
||||||
[styles.listenOnly]: listenOnly,
|
[styles.listenOnly]: listenOnly,
|
||||||
[styles.voice]: voice,
|
[styles.voice]: voice,
|
||||||
|
@ -117,6 +117,15 @@
|
|||||||
@include presenterIndicator();
|
@include presenterIndicator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.whiteboardAccess {
|
||||||
|
&:before {
|
||||||
|
content: "\00a0\e925\00a0";
|
||||||
|
padding: var(--md-padding-y);
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
@include presenterIndicator();
|
||||||
|
}
|
||||||
|
|
||||||
.voice {
|
.voice {
|
||||||
&:after {
|
&:after {
|
||||||
content: "\00a0\e931\00a0";
|
content: "\00a0\e931\00a0";
|
||||||
|
@ -11,6 +11,7 @@ import _ from 'lodash';
|
|||||||
import KEY_CODES from '/imports/utils/keyCodes';
|
import KEY_CODES from '/imports/utils/keyCodes';
|
||||||
import AudioService from '/imports/ui/components/audio/service';
|
import AudioService from '/imports/ui/components/audio/service';
|
||||||
import logger from '/imports/startup/client/logger';
|
import logger from '/imports/startup/client/logger';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
|
|
||||||
const CHAT_CONFIG = Meteor.settings.public.chat;
|
const CHAT_CONFIG = Meteor.settings.public.chat;
|
||||||
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
|
const PUBLIC_GROUP_CHAT_ID = CHAT_CONFIG.public_group_id;
|
||||||
@ -43,6 +44,14 @@ export const setModeratorOnlyMessage = msg => Storage.setItem('ModeratorOnlyMess
|
|||||||
|
|
||||||
const getCustomLogoUrl = () => Storage.getItem(CUSTOM_LOGO_URL_KEY);
|
const getCustomLogoUrl = () => Storage.getItem(CUSTOM_LOGO_URL_KEY);
|
||||||
|
|
||||||
|
const sortByWhiteboardAccess = (a, b) => {
|
||||||
|
const _a = a.whiteboardAccess;
|
||||||
|
const _b = b.whiteboardAccess;
|
||||||
|
if (!_b && _a) return -1;
|
||||||
|
if (!_a && _b) return 1;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
const sortUsersByName = (a, b) => {
|
const sortUsersByName = (a, b) => {
|
||||||
const aName = a.name.toLowerCase();
|
const aName = a.name.toLowerCase();
|
||||||
const bName = b.name.toLowerCase();
|
const bName = b.name.toLowerCase();
|
||||||
@ -125,6 +134,10 @@ const sortUsers = (a, b) => {
|
|||||||
sort = sortUsersByPhoneUser(a, b);
|
sort = sortUsersByPhoneUser(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sort === 0) {
|
||||||
|
sort = sortByWhiteboardAccess(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
if (sort === 0) {
|
if (sort === 0) {
|
||||||
sort = sortUsersByName(a, b);
|
sort = sortUsersByName(a, b);
|
||||||
}
|
}
|
||||||
@ -189,6 +202,30 @@ const userFindSorting = {
|
|||||||
userId: 1,
|
userId: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addWhiteboardAccess = (users) => {
|
||||||
|
const whiteboardId = WhiteboardService.getCurrentWhiteboardId();
|
||||||
|
|
||||||
|
if (whiteboardId) {
|
||||||
|
const multiUserWhiteboard = WhiteboardService.getMultiUser(whiteboardId);
|
||||||
|
return users.map(user => {
|
||||||
|
const whiteboardAccess = multiUserWhiteboard.includes(user.userId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
whiteboardAccess,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return users.map(user => {
|
||||||
|
const whiteboardAccess = false;
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
whiteboardAccess,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getUsers = () => {
|
const getUsers = () => {
|
||||||
let users = Users
|
let users = Users
|
||||||
.find({
|
.find({
|
||||||
@ -206,7 +243,7 @@ const getUsers = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return users.sort(sortUsers);
|
return addWhiteboardAccess(users).sort(sortUsers);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasBreakoutRoom = () => Breakouts.find({ parentMeetingId: Auth.meetingID },
|
const hasBreakoutRoom = () => Breakouts.find({ parentMeetingId: Auth.meetingID },
|
||||||
@ -334,7 +371,7 @@ const curatedVoiceUser = (intId) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAvailableActions = (amIModerator, isBreakoutRoom, subjectUser, subjectVoiceUser, usersProp) => {
|
const getAvailableActions = (amIModerator, isBreakoutRoom, subjectUser, subjectVoiceUser, usersProp, amIPresenter) => {
|
||||||
const isDialInUser = isVoiceOnlyUser(subjectUser.userId) || subjectUser.phone_user;
|
const isDialInUser = isVoiceOnlyUser(subjectUser.userId) || subjectUser.phone_user;
|
||||||
const amISubjectUser = isMe(subjectUser.userId);
|
const amISubjectUser = isMe(subjectUser.userId);
|
||||||
const isSubjectUserModerator = subjectUser.role === ROLE_MODERATOR;
|
const isSubjectUserModerator = subjectUser.role === ROLE_MODERATOR;
|
||||||
@ -386,6 +423,9 @@ const getAvailableActions = (amIModerator, isBreakoutRoom, subjectUser, subjectV
|
|||||||
&& !isSubjectUserModerator
|
&& !isSubjectUserModerator
|
||||||
&& isMeetingLocked(Auth.meetingID);
|
&& isMeetingLocked(Auth.meetingID);
|
||||||
|
|
||||||
|
const allowedToChangeWhiteboardAccess = amIPresenter
|
||||||
|
&& !amISubjectUser;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
allowedToChatPrivately,
|
allowedToChatPrivately,
|
||||||
allowedToMuteAudio,
|
allowedToMuteAudio,
|
||||||
@ -397,6 +437,7 @@ const getAvailableActions = (amIModerator, isBreakoutRoom, subjectUser, subjectV
|
|||||||
allowedToDemote,
|
allowedToDemote,
|
||||||
allowedToChangeStatus,
|
allowedToChangeStatus,
|
||||||
allowedToChangeUserLockStatus,
|
allowedToChangeUserLockStatus,
|
||||||
|
allowedToChangeWhiteboardAccess,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ import { Session } from 'meteor/session';
|
|||||||
import { styles } from './styles';
|
import { styles } from './styles';
|
||||||
import UserName from '../user-name/component';
|
import UserName from '../user-name/component';
|
||||||
import UserIcons from '../user-icons/component';
|
import UserIcons from '../user-icons/component';
|
||||||
import Service from '../../../../service';
|
import Service from '/imports/ui/components/user-list/service';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
presenter: {
|
presenter: {
|
||||||
@ -65,6 +66,14 @@ const messages = defineMessages({
|
|||||||
id: 'app.userList.menu.makePresenter.label',
|
id: 'app.userList.menu.makePresenter.label',
|
||||||
description: 'label to make another user presenter',
|
description: 'label to make another user presenter',
|
||||||
},
|
},
|
||||||
|
giveWhiteboardAccess: {
|
||||||
|
id: 'app.userList.menu.giveWhiteboardAccess.label',
|
||||||
|
description: 'label to give user whiteboard access',
|
||||||
|
},
|
||||||
|
removeWhiteboardAccess: {
|
||||||
|
id: 'app.userList.menu.removeWhiteboardAccess.label',
|
||||||
|
description: 'label to remove user whiteboard access',
|
||||||
|
},
|
||||||
RemoveUserLabel: {
|
RemoveUserLabel: {
|
||||||
id: 'app.userList.menu.removeUser.label',
|
id: 'app.userList.menu.removeUser.label',
|
||||||
description: 'Forcefully remove this user from the meeting',
|
description: 'Forcefully remove this user from the meeting',
|
||||||
@ -237,8 +246,9 @@ class UserDropdown extends PureComponent {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
const { showNestedOptions } = this.state;
|
const { showNestedOptions } = this.state;
|
||||||
|
|
||||||
|
const amIPresenter = currentUser.presenter;
|
||||||
const amIModerator = currentUser.role === ROLE_MODERATOR;
|
const amIModerator = currentUser.role === ROLE_MODERATOR;
|
||||||
const actionPermissions = getAvailableActions(amIModerator, meetingIsBreakout, user, voiceUser, usersProp);
|
const actionPermissions = getAvailableActions(amIModerator, meetingIsBreakout, user, voiceUser, usersProp, amIPresenter);
|
||||||
const actions = [];
|
const actions = [];
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -252,6 +262,7 @@ class UserDropdown extends PureComponent {
|
|||||||
allowedToDemote,
|
allowedToDemote,
|
||||||
allowedToChangeStatus,
|
allowedToChangeStatus,
|
||||||
allowedToChangeUserLockStatus,
|
allowedToChangeUserLockStatus,
|
||||||
|
allowedToChangeWhiteboardAccess,
|
||||||
} = actionPermissions;
|
} = actionPermissions;
|
||||||
|
|
||||||
const { disablePrivateChat } = lockSettingsProps;
|
const { disablePrivateChat } = lockSettingsProps;
|
||||||
@ -357,6 +368,17 @@ class UserDropdown extends PureComponent {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allowedToChangeWhiteboardAccess && !user.presenter && isMeteorConnected) {
|
||||||
|
const label = user.whiteboardAccess ? intl.formatMessage(messages.removeWhiteboardAccess) : intl.formatMessage(messages.giveWhiteboardAccess);
|
||||||
|
|
||||||
|
actions.push(this.makeDropdownItem(
|
||||||
|
'changeWhiteboardAccess',
|
||||||
|
label,
|
||||||
|
() => WhiteboardService.changeWhiteboardAccess(user.userId, !user.whiteboardAccess),
|
||||||
|
'pen_tool',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
if (allowedToSetPresenter && isMeteorConnected) {
|
if (allowedToSetPresenter && isMeteorConnected) {
|
||||||
actions.push(this.makeDropdownItem(
|
actions.push(this.makeDropdownItem(
|
||||||
'setPresenter',
|
'setPresenter',
|
||||||
@ -535,6 +557,7 @@ class UserDropdown extends PureComponent {
|
|||||||
voice={voiceUser.isVoiceUser}
|
voice={voiceUser.isVoiceUser}
|
||||||
noVoice={!voiceUser.isVoiceUser}
|
noVoice={!voiceUser.isVoiceUser}
|
||||||
color={user.color}
|
color={user.color}
|
||||||
|
whiteboardAccess={user.whiteboardAccess}
|
||||||
emoji={user.emoji !== 'none'}
|
emoji={user.emoji !== 'none'}
|
||||||
avatar={user.avatar}
|
avatar={user.avatar}
|
||||||
>
|
>
|
||||||
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||||||
import { withTracker } from 'meteor/react-meteor-data';
|
import { withTracker } from 'meteor/react-meteor-data';
|
||||||
import TextShapeService from './service';
|
import TextShapeService from './service';
|
||||||
import TextDrawComponent from './component';
|
import TextDrawComponent from './component';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
|
|
||||||
const TextDrawContainer = props => (
|
const TextDrawContainer = props => (
|
||||||
<TextDrawComponent {...props} />
|
<TextDrawComponent {...props} />
|
||||||
@ -10,7 +11,7 @@ const TextDrawContainer = props => (
|
|||||||
export default withTracker((params) => {
|
export default withTracker((params) => {
|
||||||
const { whiteboardId } = params;
|
const { whiteboardId } = params;
|
||||||
const isPresenter = TextShapeService.isPresenter();
|
const isPresenter = TextShapeService.isPresenter();
|
||||||
const isMultiUser = TextShapeService.getMultiUserStatus(whiteboardId);
|
const isMultiUser = WhiteboardService.isMultiUserActive(whiteboardId);
|
||||||
const activeTextShapeId = TextShapeService.activeTextShapeId();
|
const activeTextShapeId = TextShapeService.activeTextShapeId();
|
||||||
let isActive = false;
|
let isActive = false;
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import Storage from '/imports/ui/services/storage/session';
|
import Storage from '/imports/ui/services/storage/session';
|
||||||
import Users from '/imports/api/users';
|
import Users from '/imports/api/users';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
|
||||||
|
|
||||||
const DRAW_SETTINGS = 'drawSettings';
|
const DRAW_SETTINGS = 'drawSettings';
|
||||||
|
|
||||||
@ -26,11 +25,6 @@ const isPresenter = () => {
|
|||||||
return currentUser ? currentUser.presenter : false;
|
return currentUser ? currentUser.presenter : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMultiUserStatus = (whiteboardId) => {
|
|
||||||
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
|
|
||||||
return data ? data.multiUser : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const activeTextShapeId = () => {
|
const activeTextShapeId = () => {
|
||||||
const drawSettings = Storage.getItem(DRAW_SETTINGS);
|
const drawSettings = Storage.getItem(DRAW_SETTINGS);
|
||||||
return drawSettings ? drawSettings.textShape.textShapeActiveId : '';
|
return drawSettings ? drawSettings.textShape.textShapeActiveId : '';
|
||||||
@ -41,5 +35,4 @@ export default {
|
|||||||
activeTextShapeId,
|
activeTextShapeId,
|
||||||
isPresenter,
|
isPresenter,
|
||||||
resetTextShapeActiveId,
|
resetTextShapeActiveId,
|
||||||
getMultiUserStatus,
|
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import Users from '/imports/api/users';
|
import Users from '/imports/api/users';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user';
|
||||||
import addAnnotationQuery from '/imports/api/annotations/addAnnotation';
|
import addAnnotationQuery from '/imports/api/annotations/addAnnotation';
|
||||||
|
import { Slides } from '/imports/api/slides';
|
||||||
import { makeCall } from '/imports/ui/services/api';
|
import { makeCall } from '/imports/ui/services/api';
|
||||||
import logger from '/imports/startup/client/logger';
|
import logger from '/imports/startup/client/logger';
|
||||||
|
|
||||||
@ -184,9 +185,104 @@ Users.find({ userId: Auth.userID }, { fields: { presenter: 1 } }).observeChanges
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getMultiUser = (whiteboardId) => {
|
||||||
|
const data = WhiteboardMultiUser.findOne(
|
||||||
|
{
|
||||||
|
meetingId: Auth.meetingID,
|
||||||
|
whiteboardId,
|
||||||
|
}, { fields: { multiUser: 1 } },
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data || !data.multiUser || !Array.isArray(data.multiUser)) return [];
|
||||||
|
|
||||||
|
return data.multiUser;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMultiUserSize = (whiteboardId) => {
|
||||||
|
const multiUser = getMultiUser(whiteboardId);
|
||||||
|
|
||||||
|
if (multiUser.length === 0) return 0;
|
||||||
|
|
||||||
|
// Individual whiteboard access is controlled by an array of userIds.
|
||||||
|
// When an user leaves the meeting or the presenter role moves from an
|
||||||
|
// user to another we applying a filter at the whiteboard collection.
|
||||||
|
// Ideally this should change to something more cohese but this would
|
||||||
|
// require extra changes at multiple backend modules.
|
||||||
|
const multiUserSize = Users.find(
|
||||||
|
{
|
||||||
|
meetingId: Auth.meetingID,
|
||||||
|
userId: { $in: multiUser },
|
||||||
|
presenter: false,
|
||||||
|
}, { fields: { userId: 1 } },
|
||||||
|
).fetch();
|
||||||
|
|
||||||
|
return multiUserSize.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCurrentWhiteboardId = () => {
|
||||||
|
const currentSlide = Slides.findOne({
|
||||||
|
podId: 'DEFAULT_PRESENTATION_POD',
|
||||||
|
meetingId: Auth.meetingID,
|
||||||
|
current: true,
|
||||||
|
}, { fields: { id: 1 } },
|
||||||
|
);
|
||||||
|
|
||||||
|
return currentSlide && currentSlide.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMultiUserActive = (whiteboardId) => {
|
||||||
|
const multiUser = getMultiUser(whiteboardId);
|
||||||
|
|
||||||
|
return multiUser.length !== 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasMultiUserAccess = (whiteboardId, userId) => {
|
||||||
|
const multiUser = getMultiUser(whiteboardId);
|
||||||
|
|
||||||
|
return multiUser.includes(userId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeWhiteboardAccess = (userId, access) => {
|
||||||
|
const whiteboardId = getCurrentWhiteboardId();
|
||||||
|
|
||||||
|
if (!whiteboardId) return;
|
||||||
|
|
||||||
|
if (access) {
|
||||||
|
addIndividualAccess(whiteboardId, userId);
|
||||||
|
} else {
|
||||||
|
removeIndividualAccess(whiteboardId, userId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addGlobalAccess = (whiteboardId) => {
|
||||||
|
makeCall('addGlobalAccess', whiteboardId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addIndividualAccess = (whiteboardId, userId) => {
|
||||||
|
makeCall('addIndividualAccess', whiteboardId, userId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeGlobalAccess = (whiteboardId) => {
|
||||||
|
makeCall('removeGlobalAccess', whiteboardId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeIndividualAccess = (whiteboardId, userId) => {
|
||||||
|
makeCall('removeIndividualAccess', whiteboardId, userId);
|
||||||
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Annotations,
|
Annotations,
|
||||||
UnsentAnnotations,
|
UnsentAnnotations,
|
||||||
sendAnnotation,
|
sendAnnotation,
|
||||||
clearPreview,
|
clearPreview,
|
||||||
|
getMultiUser,
|
||||||
|
getMultiUserSize,
|
||||||
|
getCurrentWhiteboardId,
|
||||||
|
isMultiUserActive,
|
||||||
|
hasMultiUserAccess,
|
||||||
|
changeWhiteboardAccess,
|
||||||
|
addGlobalAccess,
|
||||||
|
addIndividualAccess,
|
||||||
|
removeGlobalAccess,
|
||||||
|
removeIndividualAccess,
|
||||||
};
|
};
|
||||||
|
@ -71,14 +71,18 @@ class WhiteboardToolbar extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const { annotations, multiUser, isPresenter } = this.props;
|
const {
|
||||||
|
annotations,
|
||||||
|
multiUserSize,
|
||||||
|
isPresenter,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
let annotationSelected = {
|
let annotationSelected = {
|
||||||
icon: 'hand',
|
icon: 'hand',
|
||||||
value: 'hand',
|
value: 'hand',
|
||||||
};
|
};
|
||||||
|
|
||||||
if (multiUser && !isPresenter) {
|
if (multiUserSize !== 0 && !isPresenter) {
|
||||||
annotationSelected = {
|
annotationSelected = {
|
||||||
icon: 'pen_tool',
|
icon: 'pen_tool',
|
||||||
value: 'pencil',
|
value: 'pencil',
|
||||||
@ -132,7 +136,12 @@ class WhiteboardToolbar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { actions, multiUser, isPresenter } = this.props;
|
const {
|
||||||
|
actions,
|
||||||
|
multiUserSize,
|
||||||
|
isPresenter,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
const drawSettings = actions.getCurrentDrawSettings();
|
const drawSettings = actions.getCurrentDrawSettings();
|
||||||
const {
|
const {
|
||||||
annotationSelected, thicknessSelected, colorSelected, fontSizeSelected,
|
annotationSelected, thicknessSelected, colorSelected, fontSizeSelected,
|
||||||
@ -144,7 +153,7 @@ class WhiteboardToolbar extends Component {
|
|||||||
// if there are saved drawSettings in the session storage
|
// if there are saved drawSettings in the session storage
|
||||||
// - retrieve them and update toolbar values
|
// - retrieve them and update toolbar values
|
||||||
if (drawSettings) {
|
if (drawSettings) {
|
||||||
if (multiUser && !isPresenter) {
|
if (multiUserSize !== 0 && !isPresenter) {
|
||||||
drawSettings.whiteboardAnnotationTool = 'pencil';
|
drawSettings.whiteboardAnnotationTool = 'pencil';
|
||||||
this.handleAnnotationChange({ icon: 'pen_tool', value: 'pencil' });
|
this.handleAnnotationChange({ icon: 'pen_tool', value: 'pencil' });
|
||||||
}
|
}
|
||||||
@ -357,12 +366,16 @@ class WhiteboardToolbar extends Component {
|
|||||||
|
|
||||||
handleSwitchWhiteboardMode() {
|
handleSwitchWhiteboardMode() {
|
||||||
const {
|
const {
|
||||||
multiUser,
|
multiUserSize,
|
||||||
whiteboardId,
|
whiteboardId,
|
||||||
actions,
|
actions,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
actions.changeWhiteboardMode(!multiUser, whiteboardId);
|
if (multiUserSize !== 0) {
|
||||||
|
actions.removeWhiteboardGlobalAccess(whiteboardId);
|
||||||
|
} else {
|
||||||
|
actions.addWhiteboardGlobalAccess(whiteboardId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// changes a current selected annotation both in the state and in the session
|
// changes a current selected annotation both in the state and in the session
|
||||||
@ -758,19 +771,26 @@ class WhiteboardToolbar extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderMultiUserItem() {
|
renderMultiUserItem() {
|
||||||
const { intl, multiUser, isMeteorConnected } = this.props;
|
const {
|
||||||
|
intl,
|
||||||
|
isMeteorConnected,
|
||||||
|
multiUserSize,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToolbarMenuItem
|
<span className={styles.multiUserToolItem}>
|
||||||
disabled={!isMeteorConnected}
|
{multiUserSize > 0 && <span className={styles.multiUserTool}>{multiUserSize}</span>}
|
||||||
label={multiUser
|
<ToolbarMenuItem
|
||||||
? intl.formatMessage(intlMessages.toolbarMultiUserOff)
|
disabled={!isMeteorConnected}
|
||||||
: intl.formatMessage(intlMessages.toolbarMultiUserOn)
|
label={multiUserSize > 0
|
||||||
}
|
? intl.formatMessage(intlMessages.toolbarMultiUserOff)
|
||||||
icon={multiUser ? 'multi_whiteboard' : 'whiteboard'}
|
: intl.formatMessage(intlMessages.toolbarMultiUserOn)
|
||||||
onItemClick={this.handleSwitchWhiteboardMode}
|
}
|
||||||
className={styles.toolbarButton}
|
icon={multiUserSize > 0 ? 'multi_whiteboard' : 'whiteboard'}
|
||||||
/>
|
onItemClick={this.handleSwitchWhiteboardMode}
|
||||||
|
className={styles.toolbarButton}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,9 +820,6 @@ WhiteboardToolbar.defaultProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
WhiteboardToolbar.propTypes = {
|
WhiteboardToolbar.propTypes = {
|
||||||
// defines a current mode of the whiteboard, multi/single user
|
|
||||||
multiUser: PropTypes.bool.isRequired,
|
|
||||||
|
|
||||||
// defines whether a current user is a presenter or not
|
// defines whether a current user is a presenter or not
|
||||||
isPresenter: PropTypes.bool.isRequired,
|
isPresenter: PropTypes.bool.isRequired,
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { withTracker } from 'meteor/react-meteor-data';
|
import { withTracker } from 'meteor/react-meteor-data';
|
||||||
|
import WhiteboardService from '/imports/ui/components/whiteboard/service';
|
||||||
import WhiteboardToolbarService from './service';
|
import WhiteboardToolbarService from './service';
|
||||||
import WhiteboardToolbar from './component';
|
import WhiteboardToolbar from './component';
|
||||||
|
|
||||||
@ -9,11 +10,13 @@ const WhiteboardToolbarContainer = props => (
|
|||||||
|
|
||||||
export default withTracker((params) => {
|
export default withTracker((params) => {
|
||||||
const { whiteboardId } = params;
|
const { whiteboardId } = params;
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
actions: {
|
actions: {
|
||||||
undoAnnotation: WhiteboardToolbarService.undoAnnotation,
|
undoAnnotation: WhiteboardToolbarService.undoAnnotation,
|
||||||
clearWhiteboard: WhiteboardToolbarService.clearWhiteboard,
|
clearWhiteboard: WhiteboardToolbarService.clearWhiteboard,
|
||||||
changeWhiteboardMode: WhiteboardToolbarService.changeWhiteboardMode,
|
addWhiteboardGlobalAccess: WhiteboardService.addGlobalAccess,
|
||||||
|
removeWhiteboardGlobalAccess: WhiteboardService.removeGlobalAccess,
|
||||||
setInitialWhiteboardToolbarValues: WhiteboardToolbarService.setInitialWhiteboardToolbarValues,
|
setInitialWhiteboardToolbarValues: WhiteboardToolbarService.setInitialWhiteboardToolbarValues,
|
||||||
getCurrentDrawSettings: WhiteboardToolbarService.getCurrentDrawSettings,
|
getCurrentDrawSettings: WhiteboardToolbarService.getCurrentDrawSettings,
|
||||||
setFontSize: WhiteboardToolbarService.setFontSize,
|
setFontSize: WhiteboardToolbarService.setFontSize,
|
||||||
@ -23,10 +26,10 @@ export default withTracker((params) => {
|
|||||||
setTextShapeObject: WhiteboardToolbarService.setTextShapeObject,
|
setTextShapeObject: WhiteboardToolbarService.setTextShapeObject,
|
||||||
},
|
},
|
||||||
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
|
textShapeActiveId: WhiteboardToolbarService.getTextShapeActiveId(),
|
||||||
multiUser: WhiteboardToolbarService.getMultiUserStatus(whiteboardId),
|
|
||||||
isPresenter: WhiteboardToolbarService.isPresenter(),
|
isPresenter: WhiteboardToolbarService.isPresenter(),
|
||||||
annotations: WhiteboardToolbarService.filterAnnotationList(),
|
annotations: WhiteboardToolbarService.filterAnnotationList(),
|
||||||
isMeteorConnected: Meteor.status().connected,
|
isMeteorConnected: Meteor.status().connected,
|
||||||
|
multiUserSize: WhiteboardService.getMultiUserSize(whiteboardId),
|
||||||
};
|
};
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -2,7 +2,6 @@ import { makeCall } from '/imports/ui/services/api';
|
|||||||
import Storage from '/imports/ui/services/storage/session';
|
import Storage from '/imports/ui/services/storage/session';
|
||||||
import Users from '/imports/api/users';
|
import Users from '/imports/api/users';
|
||||||
import Auth from '/imports/ui/services/auth';
|
import Auth from '/imports/ui/services/auth';
|
||||||
import WhiteboardMultiUser from '/imports/api/whiteboard-multi-user/';
|
|
||||||
import getFromUserSettings from '/imports/ui/services/users-settings';
|
import getFromUserSettings from '/imports/ui/services/users-settings';
|
||||||
|
|
||||||
const DRAW_SETTINGS = 'drawSettings';
|
const DRAW_SETTINGS = 'drawSettings';
|
||||||
@ -24,10 +23,6 @@ const clearWhiteboard = (whiteboardId) => {
|
|||||||
makeCall('clearWhiteboard', whiteboardId);
|
makeCall('clearWhiteboard', whiteboardId);
|
||||||
};
|
};
|
||||||
|
|
||||||
const changeWhiteboardMode = (multiUser, whiteboardId) => {
|
|
||||||
makeCall('changeWhiteboardAccess', multiUser, whiteboardId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const setInitialWhiteboardToolbarValues = (tool, thickness, color, fontSize, textShape) => {
|
const setInitialWhiteboardToolbarValues = (tool, thickness, color, fontSize, textShape) => {
|
||||||
const _drawSettings = Storage.getItem(DRAW_SETTINGS);
|
const _drawSettings = Storage.getItem(DRAW_SETTINGS);
|
||||||
if (!_drawSettings) {
|
if (!_drawSettings) {
|
||||||
@ -59,11 +54,6 @@ const getTextShapeActiveId = () => {
|
|||||||
return drawSettings ? drawSettings.textShape.textShapeActiveId : '';
|
return drawSettings ? drawSettings.textShape.textShapeActiveId : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getMultiUserStatus = (whiteboardId) => {
|
|
||||||
const data = WhiteboardMultiUser.findOne({ meetingId: Auth.meetingID, whiteboardId });
|
|
||||||
return data ? data.multiUser : false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const isPresenter = () => {
|
const isPresenter = () => {
|
||||||
const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { presenter: 1 } });
|
const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { presenter: 1 } });
|
||||||
return currentUser ? currentUser.presenter : false;
|
return currentUser ? currentUser.presenter : false;
|
||||||
@ -71,10 +61,11 @@ const isPresenter = () => {
|
|||||||
|
|
||||||
const filterAnnotationList = () => {
|
const filterAnnotationList = () => {
|
||||||
const multiUserPenOnly = getFromUserSettings('bbb_multi_user_pen_only', WHITEBOARD_TOOLBAR.multiUserPenOnly);
|
const multiUserPenOnly = getFromUserSettings('bbb_multi_user_pen_only', WHITEBOARD_TOOLBAR.multiUserPenOnly);
|
||||||
|
const amIPresenter = isPresenter();
|
||||||
|
|
||||||
let filteredAnnotationList = WHITEBOARD_TOOLBAR.tools;
|
let filteredAnnotationList = WHITEBOARD_TOOLBAR.tools;
|
||||||
|
|
||||||
if (!isPresenter() && multiUserPenOnly) {
|
if (!amIPresenter && multiUserPenOnly) {
|
||||||
filteredAnnotationList = [{
|
filteredAnnotationList = [{
|
||||||
icon: 'pen_tool',
|
icon: 'pen_tool',
|
||||||
value: 'pencil',
|
value: 'pencil',
|
||||||
@ -82,13 +73,13 @@ const filterAnnotationList = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const presenterTools = getFromUserSettings('bbb_presenter_tools', WHITEBOARD_TOOLBAR.presenterTools);
|
const presenterTools = getFromUserSettings('bbb_presenter_tools', WHITEBOARD_TOOLBAR.presenterTools);
|
||||||
if (isPresenter() && Array.isArray(presenterTools)) {
|
if (amIPresenter && Array.isArray(presenterTools)) {
|
||||||
filteredAnnotationList = WHITEBOARD_TOOLBAR.tools.filter(el =>
|
filteredAnnotationList = WHITEBOARD_TOOLBAR.tools.filter(el =>
|
||||||
presenterTools.includes(el.value));
|
presenterTools.includes(el.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
const multiUserTools = getFromUserSettings('bbb_multi_user_tools', WHITEBOARD_TOOLBAR.multiUserTools);
|
const multiUserTools = getFromUserSettings('bbb_multi_user_tools', WHITEBOARD_TOOLBAR.multiUserTools);
|
||||||
if (!isPresenter() && !multiUserPenOnly && Array.isArray(multiUserTools)) {
|
if (!amIPresenter && !multiUserPenOnly && Array.isArray(multiUserTools)) {
|
||||||
filteredAnnotationList = WHITEBOARD_TOOLBAR.tools.filter(el =>
|
filteredAnnotationList = WHITEBOARD_TOOLBAR.tools.filter(el =>
|
||||||
multiUserTools.includes(el.value));
|
multiUserTools.includes(el.value));
|
||||||
}
|
}
|
||||||
@ -99,7 +90,6 @@ const filterAnnotationList = () => {
|
|||||||
export default {
|
export default {
|
||||||
undoAnnotation,
|
undoAnnotation,
|
||||||
clearWhiteboard,
|
clearWhiteboard,
|
||||||
changeWhiteboardMode,
|
|
||||||
setInitialWhiteboardToolbarValues,
|
setInitialWhiteboardToolbarValues,
|
||||||
getCurrentDrawSettings,
|
getCurrentDrawSettings,
|
||||||
setFontSize,
|
setFontSize,
|
||||||
@ -108,7 +98,6 @@ export default {
|
|||||||
setColor,
|
setColor,
|
||||||
setTextShapeObject,
|
setTextShapeObject,
|
||||||
getTextShapeActiveId,
|
getTextShapeActiveId,
|
||||||
getMultiUserStatus,
|
|
||||||
isPresenter,
|
isPresenter,
|
||||||
filterAnnotationList,
|
filterAnnotationList,
|
||||||
};
|
};
|
||||||
|
@ -244,3 +244,26 @@
|
|||||||
color: var(--toolbar-list-color);
|
color: var(--toolbar-list-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multiUserTool {
|
||||||
|
background-color: var(--color-danger);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: var(--lg-padding-x);
|
||||||
|
height: var(--lg-padding-x);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
right: 0px;
|
||||||
|
color: var(--color-white);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 1px 1px var(--border-size-large) var(--color-gray-dark);
|
||||||
|
font-size: var(--sm-padding-x);
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiUserToolItem {
|
||||||
|
.toolbarButton {
|
||||||
|
border-top-right-radius: 0 !important;
|
||||||
|
border-top-left-radius: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -520,7 +520,6 @@ public:
|
|||||||
- triangle
|
- triangle
|
||||||
- rectangle
|
- rectangle
|
||||||
- pencil
|
- pencil
|
||||||
- hand
|
|
||||||
clientLog:
|
clientLog:
|
||||||
server:
|
server:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
@ -82,6 +82,8 @@
|
|||||||
"app.userlist.menu.removeConfirmation.desc": "Prevent this user from rejoining the session.",
|
"app.userlist.menu.removeConfirmation.desc": "Prevent this user from rejoining the session.",
|
||||||
"app.userList.menu.muteUserAudio.label": "Mute user",
|
"app.userList.menu.muteUserAudio.label": "Mute user",
|
||||||
"app.userList.menu.unmuteUserAudio.label": "Unmute user",
|
"app.userList.menu.unmuteUserAudio.label": "Unmute user",
|
||||||
|
"app.userList.menu.giveWhiteboardAccess.label" : "Give whiteboard access",
|
||||||
|
"app.userList.menu.removeWhiteboardAccess.label": "Remove whiteboard access",
|
||||||
"app.userList.userAriaLabel": "{0} {1} {2} Status {3}",
|
"app.userList.userAriaLabel": "{0} {1} {2} Status {3}",
|
||||||
"app.userList.menu.promoteUser.label": "Promote to moderator",
|
"app.userList.menu.promoteUser.label": "Promote to moderator",
|
||||||
"app.userList.menu.demoteUser.label": "Demote to viewer",
|
"app.userList.menu.demoteUser.label": "Demote to viewer",
|
||||||
|
Loading…
Reference in New Issue
Block a user