resolve merge conflicts
This commit is contained in:
commit
8e2ce8c82c
33
README.md
33
README.md
@ -1,36 +1,15 @@
|
||||
BigBlueButton
|
||||
=============
|
||||
BigBlueButton is an open source web conferencing system for on-line learning. We believe that every student with a web browser should have access to a high-quality on-line learning experience. We intend to make that possible with BigBlueButton.
|
||||
BigBlueButton is an open source web conferencing system for on-line learning.
|
||||
|
||||
BigBlueButton supports real-time sharing of slides (PDF and any document readable by OpenOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop. It can record and playback all content shared in a session. The BigBlueButton project is is supported by a [community of developers] (http://www.bigbluebutton.org/support/) that care about good design and a streamlined user experience.
|
||||
We believe that every student with a web browser should have access to a high-quality on-line learning experience. We intend to make that possible with BigBlueButton.
|
||||
|
||||
BigBlueButton supports real-time sharing of slides (PDF and any document readable by LibreOffice), webcams, whiteboard, chat, voice over IP (using FreeSWITCH), and desktop. It can record and playback all content shared in a session. The use cases for BigBlueButton are
|
||||
|
||||
The use cases for BigBlueButton are
|
||||
* One-to-one on-line tutoring
|
||||
* Small group collaboration
|
||||
* On-line classes (25 or less)
|
||||
* On-line classes (50 or less)
|
||||
|
||||
BigBlueButton is built on the [shoulders of giants] (http://www.bigbluebutton.org/components/).
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
All the core information is at the [Google Code project page] (http://code.google.com/p/bigbluebutton/). Here are a few quick links
|
||||
|
||||
If you want to see how BigBlueButton works, check out these two videos
|
||||
* [presenter] (http://www.bigbluebutton.org/videos/)
|
||||
* [viewer] (http://www.bigbluebutton.org/videos/)
|
||||
|
||||
After watching the videos, if you want to immediately try out BigBlueButton, the project maintains a live [demo server] (http://demo.bigbluebutton.org) that anyone can join.
|
||||
|
||||
To quickly get started running your own BigBlueButton server
|
||||
* [Install on Ubunt 10.04 64-bit] (http://code.google.com/p/bigbluebutton/wiki/InstallationUbuntu)
|
||||
* [Download the BigBlueButton 0.81 Virtual Machine] (http://code.google.com/p/bigbluebutton/wiki/BigBlueButtonVM)
|
||||
|
||||
See also [history of project] (http://www.bigbluebutton.org/history/).
|
||||
|
||||
If you like the work we've done with BigBlueButton and would like to contribute improvemets to the project, see [Contribute to BigBlueButton] (http://code.google.com/p/bigbluebutton/wiki/FAQ#Contributing_to_BigBlueButton).
|
||||
|
||||
License
|
||||
=======
|
||||
BigBlueButton is licensed under the LGPL 3.0.
|
||||
For more information on the latest release -- including installation instructions, demo server, API, and overview of architecture -- see [http://docs.bigbluebutton.org/](http://docs.bigbluebutton.org/).
|
||||
|
||||
BigBlueButton and the BigBlueButton Logo are trademarks of [BigBlueButton Inc] (http://bigbluebutton.org) .
|
||||
|
@ -56,6 +56,4 @@ public class MessagingConstants {
|
||||
public static final String SEND_PUBLIC_CHAT_MESSAGE_REQUEST = "send_public_chat_message_request";
|
||||
public static final String SEND_PRIVATE_CHAT_MESSAGE_REQUEST = "send_private_chat_message_request";
|
||||
public static final String MUTE_USER_REQUEST = "mute_user_request";
|
||||
public static final String USER_CONNECTED_TO_GLOBAL_AUDIO = "user_connected_to_global_audio";
|
||||
public static final String USER_DISCONNECTED_FROM_GLOBAL_AUDIO = "user_disconnected_from_global_audio";
|
||||
}
|
||||
|
@ -45,24 +45,6 @@ public class VoiceMessageListener implements MessageHandler{
|
||||
System.out.println("handling user_left_voice_request");
|
||||
bbbGW.voiceUserLeft(meetingID, userID);
|
||||
}
|
||||
else if (eventName.equalsIgnoreCase(MessagingConstants.USER_CONNECTED_TO_GLOBAL_AUDIO)){
|
||||
|
||||
// String meetingID = payloadObject.get("meeting_id").toString().replace("\"", "");
|
||||
String userID = payloadObject.get("userid").toString().replace("\"", "");
|
||||
String voiceConf = payloadObject.get("voiceConf").toString().replace("\"", "");
|
||||
String userName = payloadObject.get("name").toString().replace("\"", "");
|
||||
|
||||
bbbGW.userConnectedToGlobalAudio(voiceConf, userID, userName);
|
||||
}
|
||||
else if (eventName.equalsIgnoreCase(MessagingConstants.USER_DISCONNECTED_FROM_GLOBAL_AUDIO)){
|
||||
|
||||
// String meetingID = payloadObject.get("meeting_id").toString().replace("\"", "");
|
||||
String userID = payloadObject.get("userid").toString().replace("\"", "");
|
||||
String voiceConf = payloadObject.get("voiceConf").toString().replace("\"", "");
|
||||
String userName = payloadObject.get("name").toString().replace("\"", "");
|
||||
|
||||
bbbGW.userDisconnectedFromGlobalAudio(voiceConf, userID, userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ public class WhiteboardListener implements MessageHandler{
|
||||
@Override
|
||||
public void handleMessage(String pattern, String channel, String message) {
|
||||
if (channel.equalsIgnoreCase(MessagingConstants.TO_WHITEBOARD_CHANNEL)) {
|
||||
System.out.println("AntonChannel=(whiteboard)" + channel);
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject obj = (JsonObject) parser.parse(message);
|
||||
@ -44,7 +43,7 @@ public class WhiteboardListener implements MessageHandler{
|
||||
else {
|
||||
System.out.println("\n DID NOT FIND A whiteboardID \n");
|
||||
}
|
||||
System.out.println("\n\n\n user<" + requesterID + "> requested the shapes.\n\n");
|
||||
System.out.println("\n user<" + requesterID + "> requested the shapes.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +158,9 @@ class BigBlueButtonActor(outGW: MessageOutGateway) extends Actor with LogHelper
|
||||
|
||||
//send chat history
|
||||
this ! (new GetChatHistoryRequest(id, "nodeJSapp", "nodeJSapp"))
|
||||
|
||||
//send lock settings
|
||||
this ! (new GetLockSettings(id, "nodeJSapp"))
|
||||
}
|
||||
|
||||
outGW.send(new GetAllMeetingsReply(resultArray))
|
||||
|
@ -2,7 +2,6 @@ package org.bigbluebutton.core
|
||||
|
||||
import scala.actors.Actor
|
||||
import scala.actors.Actor._
|
||||
import org.bigbluebutton.core.apps.poll.PollApp
|
||||
import org.bigbluebutton.core.apps.poll.Poll
|
||||
import org.bigbluebutton.core.apps.poll.PollApp
|
||||
import org.bigbluebutton.core.apps.users.UsersApp
|
||||
@ -90,6 +89,7 @@ class MeetingActor(val meetingID: String, val externalMeetingID: String, val mee
|
||||
case msg: MuteUserRequest => handleMuteUserRequest(msg)
|
||||
case msg: EjectUserFromVoiceRequest => handleEjectUserRequest(msg)
|
||||
case msg: SetLockSettings => handleSetLockSettings(msg)
|
||||
case msg: GetLockSettings => handleGetLockSettings(msg)
|
||||
case msg: LockUserRequest => handleLockUserRequest(msg)
|
||||
case msg: InitLockSettings => handleInitLockSettings(msg)
|
||||
case msg: InitAudioSettings => handleInitAudioSettings(msg)
|
||||
|
@ -81,18 +81,11 @@ trait UsersApp {
|
||||
//send the reply
|
||||
outGW.send(new ValidateAuthTokenReply(meetingID, msg.userId, msg.token, true, msg.correlationId, msg.sessionId))
|
||||
|
||||
//send the list of users in the meeting
|
||||
outGW.send(new GetUsersReply(meetingID, msg.userId, users.getUsers, msg.sessionId))
|
||||
|
||||
//send chat history
|
||||
this ! (new GetChatHistoryRequest(meetingID, msg.userId, msg.userId))
|
||||
|
||||
//join the user
|
||||
handleUserJoin(new UserJoining(meetingID, msg.userId, msg.token))
|
||||
|
||||
//send the presentation
|
||||
logger.info("ValidateToken success: mid=[" + meetingID + "] uid=[" + msg.userId + "]")
|
||||
this ! (new GetPresentationInfo(meetingID, msg.userId, msg.userId))
|
||||
}
|
||||
case None => {
|
||||
logger.info("ValidateToken failed: mid=[" + meetingID + "] uid=[" + msg.userId + "]")
|
||||
@ -153,11 +146,14 @@ trait UsersApp {
|
||||
case None => // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def handleGetLockSettings(msg: GetLockSettings) {
|
||||
logger.info("Not implemented: handleGetLockSettings")
|
||||
//println("*************** Reply with current lock settings ********************")
|
||||
|
||||
//reusing the existing handle for NewPermissionsSettings to reply to the GetLockSettings request
|
||||
outGW.send(new NewPermissionsSetting(meetingID, msg.userId, permissions, users.getUsers))
|
||||
}
|
||||
|
||||
|
||||
def handleSetLockSettings(msg: SetLockSettings) {
|
||||
// println("*************** Received new lock settings ********************")
|
||||
if (!permissionsEqual(msg.settings)) {
|
||||
@ -306,6 +302,18 @@ trait UsersApp {
|
||||
user foreach { u =>
|
||||
logger.info("User left meeting: mid=[" + meetingID + "] uid=[" + u.userID + "]")
|
||||
outGW.send(new UserLeft(msg.meetingID, recorded, u))
|
||||
|
||||
if (u.presenter) {
|
||||
/* The current presenter has left the meeting. Find a moderator and make
|
||||
* him presenter. This way, if there is a moderator in the meeting, there
|
||||
* will always be a presenter.
|
||||
*/
|
||||
val moderator = users.findAModerator()
|
||||
moderator.foreach { mod =>
|
||||
logger.info("Presenter left meeting: mid=[" + meetingID + "] uid=[" + u.userID + "]. Making user=[" + mod.userID + "] presenter.")
|
||||
assignNewPresenter(mod.userID, mod.name, mod.userID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startCheckingIfWeNeedToEndVoiceConf()
|
||||
|
@ -63,7 +63,7 @@ class UsersModel {
|
||||
getModerators.length
|
||||
}
|
||||
|
||||
def getLoneModerator():Option[UserVO] = {
|
||||
def findAModerator():Option[UserVO] = {
|
||||
uservos.values find (u => u.role == MODERATOR)
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
<mx:HBox width="100%" horizontalAlign="right" horizontalGap="18" paddingTop="20">
|
||||
<mx:Button id="saveBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.save')}"
|
||||
click="onSaveClicked()" tabIndex="{baseIndex+8}"
|
||||
toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.toolTip')}"/>
|
||||
toolTip="{ResourceUtil.getInstance().getString('bbb.lockSettings.save.tooltip')}"/>
|
||||
|
||||
<mx:Button id="cancelBtn" label="{ResourceUtil.getInstance().getString('bbb.lockSettings.cancel')}"
|
||||
click="onCancelClicked()" tabIndex="{baseIndex+9}"
|
||||
|
@ -115,14 +115,16 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
if (isUsingLessThanChrome38OnMac()) {
|
||||
setCurrentState("chromeOnMacWarningState");
|
||||
} else if (isChrome42OrHigher()) {
|
||||
setCurrentState("chrome42WarningState");
|
||||
} else {
|
||||
var javaIssue:String = JavaCheck.checkJava();
|
||||
|
||||
if (javaIssue != null) {
|
||||
setCurrentState("javaIssueWarningState");
|
||||
javaIssueWarningStateLbl.htmlText = javaIssue;
|
||||
if (isChrome42OrHigher()) {
|
||||
setCurrentState("chrome42WarningState");
|
||||
} else {
|
||||
setCurrentState("javaIssueWarningState");
|
||||
javaIssueWarningStateLbl.htmlText = javaIssue;
|
||||
}
|
||||
} else {
|
||||
setCurrentState("dispFullRegionControlBar");
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
BIGBLUEBUTTON_RELEASE=0.9.0-beta
|
||||
BIGBLUEBUTTON_RELEASE=0.9.0-RC
|
||||
|
@ -171,9 +171,9 @@ usage() {
|
||||
echo " --lti View the URL and secret for LTI (if installed)"
|
||||
echo
|
||||
echo "Administration:"
|
||||
echo " --restart Restart BigBueButton"
|
||||
echo " --stop Stop BigBueButton"
|
||||
echo " --start Start BigBueButton"
|
||||
echo " --restart Restart BigBlueButton"
|
||||
echo " --stop Stop BigBlueButton"
|
||||
echo " --start Start BigBlueButton"
|
||||
echo " --clean Restart and clean all log files"
|
||||
echo " --zip Zip up log files for reporting an error"
|
||||
echo
|
||||
|
@ -195,7 +195,7 @@
|
||||
<div class="row">
|
||||
<div class="span twelve center">
|
||||
<p>Copyright © 2015 BigBlueButton Inc.<br>
|
||||
<small>Version <a href="https://code.google.com/p/bigbluebutton/wiki/090Docs">0.9.0-beta</a></small>
|
||||
<small>Version <a href="https://code.google.com/p/bigbluebutton/wiki/090Docs">0.9.0-RC</a></small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -112,7 +112,7 @@ Handlebars.registerHelper "getUsersInMeeting", ->
|
||||
raised.concat lowered
|
||||
|
||||
Handlebars.registerHelper "getWhiteboardTitle", ->
|
||||
"Presentation: " + (getPresentationFilename() or "Loading...")
|
||||
(getPresentationFilename() or "Loading presentaion...")
|
||||
|
||||
Handlebars.registerHelper "isCurrentUser", (userId) ->
|
||||
userId is null or userId is BBB.getCurrentUser()?.userId
|
||||
@ -151,8 +151,8 @@ Handlebars.registerHelper "isUserTalking", (userId) ->
|
||||
Handlebars.registerHelper 'isMobile', () ->
|
||||
isMobile()
|
||||
|
||||
Handlebars.registerHelper 'isMobile', () ->
|
||||
isMobile()
|
||||
Handlebars.registerHelper 'isPortraitMobile', () ->
|
||||
isPortraitMobile()
|
||||
|
||||
Handlebars.registerHelper 'isMobileChromeOrFirefox', () ->
|
||||
isMobile() and ((getBrowserName() is 'Chrome') or (getBrowserName() is 'Firefox'))
|
||||
@ -225,7 +225,7 @@ Handlebars.registerHelper "visibility", (section) ->
|
||||
@introToAudio = (event, {isListenOnly} = {}) ->
|
||||
isListenOnly ?= true
|
||||
joinVoiceCall event, isListenOnly: isListenOnly
|
||||
displayWebRTCNotification()
|
||||
notification_WebRTCAudioJoined()
|
||||
|
||||
# check the chat history of the user and add tabs for the private chats
|
||||
@populateChatTabs = (msg) ->
|
||||
|
@ -87,6 +87,19 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
|
||||
BBB.isUserTalking = (userId, callback) ->
|
||||
BBB.getUser(userId)?.user?.voiceUser?.talking
|
||||
|
||||
# returns true if the current user is marked as locked
|
||||
BBB.amILocked = () ->
|
||||
return BBB.getCurrentUser()?.user.locked
|
||||
|
||||
# check whether the user is locked AND the current lock settings for the room
|
||||
# includes locking the microphone of viewers (listenOnly is still alowed)
|
||||
BBB.isMyMicLocked = () ->
|
||||
lockedMicForRoom = Meteor.Meetings.findOne()?.roomLockSettings.disableMic
|
||||
# note that voiceUser.locked is not used in BigBlueButton at this stage (April 2015)
|
||||
|
||||
return lockedMicForRoom and BBB.amILocked()
|
||||
|
||||
|
||||
###
|
||||
Raise user's hand.
|
||||
|
||||
@ -208,6 +221,8 @@ https://github.com/bigbluebutton/bigbluebutton/blob/master/bigbluebutton-client/
|
||||
isListenOnly: signifies whether the user joining the conference audio requests to join the listen only stream
|
||||
###
|
||||
BBB.joinVoiceConference = (callback, isListenOnly) ->
|
||||
if BBB.isMyMicLocked()
|
||||
callIntoConference(BBB.getMyVoiceBridge(), callback, true) #true because we force isListenOnly mode
|
||||
callIntoConference(BBB.getMyVoiceBridge(), callback, isListenOnly)
|
||||
|
||||
###
|
||||
|
@ -6,8 +6,6 @@ displayAudioSelectionMenu = ({isMobile} = {}) ->
|
||||
|
||||
if isMobile
|
||||
toggleSlidingMenu()
|
||||
|
||||
if isMobile
|
||||
$('.navbarTitle').css('width', '55%')
|
||||
|
||||
# pop open the dialog allowing users to choose the audio options
|
||||
@ -15,8 +13,18 @@ displayAudioSelectionMenu = ({isMobile} = {}) ->
|
||||
$('.joinAudio-dialog').addClass('landscape-mobile-joinAudio-dialog')
|
||||
else
|
||||
$('.joinAudio-dialog').addClass('desktop-joinAudio-dialog')
|
||||
|
||||
$("#joinAudioDialog").dialog("open")
|
||||
|
||||
# helper function to reuse some code for the handling of audio join
|
||||
onAudioJoinHelper = () ->
|
||||
# if the microphone is locked (lock settings), the viewer is only
|
||||
# allowed to join the audio as listenOnly.
|
||||
if BBB.isMyMicLocked()
|
||||
introToAudio(null, isListenOnly: true)
|
||||
else
|
||||
displayAudioSelectionMenu(isMobile: isMobile())
|
||||
|
||||
# Helper to load javascript libraries from the BBB server
|
||||
loadLib = (libname) ->
|
||||
successCallback = ->
|
||||
@ -57,8 +65,7 @@ Template.header.events
|
||||
if !isWebRTCAvailable()
|
||||
notification_WebRTCNotSupported()
|
||||
else
|
||||
notification_WebRTCAudioJoined()
|
||||
displayAudioSelectionMenu(isMobile: false)
|
||||
onAudioJoinHelper()
|
||||
|
||||
"click .chatBarIcon": (event) ->
|
||||
$(".tooltip").hide()
|
||||
@ -131,7 +138,7 @@ Template.header.events
|
||||
|
||||
Template.slidingMenu.events
|
||||
'click .joinAudioButton': (event) ->
|
||||
displayAudioSelectionMenu(isMobile: true)
|
||||
onAudioJoinHelper()
|
||||
|
||||
'click .chatBarIcon': (event) ->
|
||||
$('.tooltip').hide()
|
||||
@ -164,6 +171,10 @@ Template.slidingMenu.events
|
||||
toggleSlidingMenu()
|
||||
$('.collapseButton').blur()
|
||||
|
||||
"click .leaveAudioButton": (event) ->
|
||||
exitVoiceCall event
|
||||
toggleSlidingMenu()
|
||||
|
||||
Template.main.helpers
|
||||
setTitle: ->
|
||||
document.title = "BigBlueButton #{window.getMeetingName() ? 'HTML5'}"
|
||||
@ -243,7 +254,7 @@ Template.main.rendered = ->
|
||||
toggleSlidingMenu()
|
||||
|
||||
if Meteor.config.app.autoJoinAudio
|
||||
displayAudioSelectionMenu(isMobile:isMobile())
|
||||
onAudioJoinHelper()
|
||||
|
||||
Template.makeButton.rendered = ->
|
||||
$('button[rel=tooltip]').tooltip()
|
||||
|
@ -36,9 +36,9 @@
|
||||
|
||||
<!-- display/hide whiteboard toggle -->
|
||||
{{#if getInSession "display_whiteboard"}}
|
||||
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
|
||||
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Hide Whiteboard"}}
|
||||
{{else}}
|
||||
{{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
|
||||
{{> makeButton btn_class="whiteboardIcon navbarButton collapseSectionButton" i_class="ion-easel" rel="tooltip" data_placement="bottom" title="Show Whiteboard"}}
|
||||
{{/if}}
|
||||
|
||||
<!-- display/hide chat bar toggle -->
|
||||
@ -135,6 +135,7 @@
|
||||
<div id="browser-icon-container"></div>
|
||||
<p id="notification-text"></p>
|
||||
</div>
|
||||
|
||||
<div id="main" class="mainContainer row-fluid">
|
||||
{{#if isDisconnected}}
|
||||
{{>status}}
|
||||
@ -144,7 +145,6 @@
|
||||
{{> chatbar id="chat" title="Chat" name="chatbar"}}
|
||||
{{> usersList id="users" name="usersList"}}
|
||||
<audio id="remote-media" autoplay="autoplay"></audio>
|
||||
<video style="display:none"></video>
|
||||
{{> footer}}
|
||||
{{/if}}
|
||||
<div id='shield'></div>
|
||||
@ -178,9 +178,9 @@
|
||||
{{/if}}
|
||||
|
||||
{{#if getInSession "display_whiteboard"}}
|
||||
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Hide Whiteboard"}}
|
||||
{{> makeButton btn_class="navbarIconToggleActive whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Hide Whiteboard"}}
|
||||
{{else}}
|
||||
{{> makeButton btn_class="whiteboardIcon slideButton" i_class="glyphicon glyphicon-pencil" rel="tooltip" data_placement="right" title="Show Whiteboard"}}
|
||||
{{> makeButton btn_class="whiteboardIcon slideButton" i_class="ion-easel" rel="tooltip" data_placement="right" title="Show Whiteboard"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if getInSession "display_chatbar"}}
|
||||
@ -190,31 +190,9 @@
|
||||
{{/if}}
|
||||
|
||||
{{#if amIInAudio}}
|
||||
<!-- This button is for leaving audio -->
|
||||
<div class='hiddenNavbarSection'>
|
||||
<!-- display the button for leaving audio -->
|
||||
{{> makeButton btn_class="navbarIconToggleActive audioFeedIcon navbarButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
|
||||
</div>
|
||||
{{#unless amIListenOnlyAudio}}
|
||||
{{#if isCurrentUserMuted}}
|
||||
<!-- if you are muted the button representing your status will show volume off -->
|
||||
{{> makeButton btn_class="muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-off" sharingAudio=true rel="tooltip" data_placement="bottom" title="Unmute"}}
|
||||
{{else}}
|
||||
{{#if isCurrentUserTalking}}
|
||||
<!-- you are talking. Display a high volume/volume up representing voice activity -->
|
||||
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-up" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
|
||||
{{else}}
|
||||
<!-- you are not talking. Display low volume/volume down representing no voice activity -->
|
||||
{{> makeButton btn_class="navbarIconToggleActive muteIcon navbarButton audioButton" i_class="glyphicon glyphicon-volume-down" sharingAudio=true rel="tooltip" data_placement="bottom" title="Mute"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{/unless}}
|
||||
{{> makeButton btn_class="navbarIconToggleActive audioFeedIcon slideButton audioButton leaveAudioButton" i_class="ion-volume-mute" sharingAudio=true rel="tooltip" data_placement="bottom" title="Leave Audio Call"}}
|
||||
{{else}}
|
||||
<div class='hiddenNavbarSection'>
|
||||
<div id="shareMicrophonePanel">
|
||||
{{> makeButton btn_class="audioFeedIcon navbarButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
|
||||
</div>
|
||||
</div>
|
||||
{{> makeButton btn_class="audioFeedIcon slideButton audioButton joinAudioButton" i_class="glyphicon glyphicon-headphones" sharingAudio=false rel="tooltip" data_placement="bottom" title="Join Audio Call"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if isCurrentUserRaisingHand}}
|
||||
|
@ -1,9 +1,9 @@
|
||||
@import "variables";
|
||||
|
||||
.active {
|
||||
border: .2vh solid extract(@azure, 2) !important;
|
||||
border: .2vh solid !important;
|
||||
@media @mobile-portrait-with-keyboard, @mobile-portrait {
|
||||
border-left: .1vh solid extract(@azure, 2) !important;
|
||||
border-left: .1vh solid !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,18 @@
|
||||
.chatNameSelectorPrivate {
|
||||
.chatNameSelector;
|
||||
width:90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@media @landscape {
|
||||
height: 20px;
|
||||
}
|
||||
@media @desktop-portrait {
|
||||
height: 25px;
|
||||
}
|
||||
@media @mobile-portrait, @mobile-portrait-with-keyboard {
|
||||
font-size: 4vw;
|
||||
}
|
||||
}
|
||||
|
||||
.chatNameSelectorPublic {
|
||||
@ -107,6 +119,12 @@
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
.disabledChat {
|
||||
background-color: grey;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
float: left;
|
||||
@media @desktop-portrait, @mobile-portrait, @mobile-portrait-with-keyboard {
|
||||
@ -274,7 +292,7 @@
|
||||
|
||||
&:hover {
|
||||
background-color: #ddd;
|
||||
border: 1px solid extract(@azure, 2);
|
||||
border: 1px solid;
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
@ -41,13 +41,8 @@ body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.listenOnlyIcon {
|
||||
color: white;
|
||||
font-size: 20px;
|
||||
padding-top: 10px;
|
||||
&:hover {
|
||||
color: white !important;
|
||||
}
|
||||
.heading {
|
||||
margin-left:5px
|
||||
}
|
||||
|
||||
.mainContainer {
|
||||
@ -59,6 +54,7 @@ body {
|
||||
color: black;
|
||||
padding-top: 13px;
|
||||
text-align: center;
|
||||
background-color: #EEEEEE;
|
||||
@media @landscape {
|
||||
position:fixed;
|
||||
bottom:0;
|
||||
@ -92,8 +88,6 @@ body {
|
||||
}
|
||||
.btn {
|
||||
.linear-gradient(rgb(72,76,85), rgb(65,68,77));
|
||||
border-left: 1px solid extract(@darkGrey, 2);
|
||||
border-right: 1px solid extract(@darkGrey, 4);
|
||||
&.navbarIconToggleActive {
|
||||
background: extract(@darkGrey, 3);
|
||||
border-bottom: 4px solid extract(@azure, 1);
|
||||
@ -223,7 +217,7 @@ body {
|
||||
display: block;
|
||||
float: left;
|
||||
&:hover {
|
||||
background: extract(@darkGrey, 3);
|
||||
background: extract(@darkGrey, 4);
|
||||
}
|
||||
}
|
||||
@media @landscape {
|
||||
@ -232,7 +226,7 @@ body {
|
||||
}
|
||||
|
||||
.navbarSettingsButtons .btn:hover {
|
||||
background: extract(@darkGrey, 3);
|
||||
background: extract(@darkGrey, 4);
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
@ -384,7 +378,7 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.glyphicon, .ion-android-hand {
|
||||
.glyphicon, .ion-android-hand, .ion-easel {
|
||||
@media @mobile-portrait-with-keyboard, @mobile-portrait {
|
||||
font-size: 35px;
|
||||
}
|
||||
@ -472,8 +466,6 @@ body {
|
||||
}
|
||||
.btn {
|
||||
.linear-gradient(rgb(72,76,85), rgb(65,68,77));
|
||||
border-left: 1px solid extract(@darkGrey, 2);
|
||||
border-right: 1px solid extract(@darkGrey, 4);
|
||||
&.navbarIconToggleActive {
|
||||
background: extract(@darkGrey, 3);
|
||||
border-bottom: 4px solid extract(@azure, 1);
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#content {
|
||||
margin-top: 10px;
|
||||
&:first-child {
|
||||
margin-top: 0px;
|
||||
}
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
@media @mobile-portrait, @mobile-portrait-with-keyboard {
|
||||
|
@ -65,6 +65,24 @@ Handlebars.registerHelper "grabChatTabs", ->
|
||||
setInSession 'chatTabs', initTabs
|
||||
getInSession('chatTabs')[0..3]
|
||||
|
||||
# true if the lock settings limit public chat and the current user is locked
|
||||
Handlebars.registerHelper "publicChatDisabled", ->
|
||||
userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked
|
||||
publicChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePubChat
|
||||
presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter
|
||||
return userIsLocked and publicChatIsDisabled and !presenter
|
||||
|
||||
# true if the lock settings limit private chat and the current user is locked
|
||||
Handlebars.registerHelper "privateChatDisabled", ->
|
||||
userIsLocked = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.locked
|
||||
privateChatIsDisabled = Meteor.Meetings.findOne({})?.roomLockSettings.disablePrivChat
|
||||
presenter = Meteor.Users.findOne({userId:getInSession 'userId'})?.user.presenter
|
||||
return userIsLocked and privateChatIsDisabled and !presenter
|
||||
|
||||
# return whether the user's chat pane is open in Private chat (vs Public chat or Options)
|
||||
Handlebars.registerHelper "inPrivateChat", ->
|
||||
return !((getInSession 'inChatWith') in ['PUBLIC_CHAT', 'OPTIONS'])
|
||||
|
||||
@sendMessage = ->
|
||||
message = linkify $('#newMessageInput').val() # get the message from the input box
|
||||
unless (message?.length > 0 and (/\S/.test(message))) # check the message has content and it is not whitespace
|
||||
|
@ -1,6 +1,9 @@
|
||||
<template name="chatbar">
|
||||
<div id="{{id}}" {{visibility name}} class="component">
|
||||
<h3 class="title gradientBar"><span class="glyphicon glyphicon-comment"></span>{{title}}{{> extraConversations}}</h3>
|
||||
<h3 class="title gradientBar">
|
||||
<span class="glyphicon glyphicon-comment heading"></span>
|
||||
{{> extraConversations}}
|
||||
</h3>
|
||||
{{>tabButtons}} <!-- Display public/options tabs, and private chat tabs -->
|
||||
{{#if getInSession "display_chatPane"}}
|
||||
<div id="chatbody">
|
||||
@ -24,10 +27,25 @@
|
||||
|
||||
<template name="chatInput">
|
||||
<div id="chatInput" class="chat-input-wrapper">
|
||||
<textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
|
||||
<button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top" title="Click to send your message">
|
||||
Send
|
||||
</button>
|
||||
{{#if inPrivateChat}}
|
||||
{{#if privateChatDisabled}}
|
||||
<textarea id="newMessageInput" class="disabledChat" placeholder="Private chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Private chat is temporarily locked" disabled></textarea>
|
||||
{{else}}
|
||||
<textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
|
||||
<button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top">
|
||||
Send
|
||||
</button>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if publicChatDisabled}}
|
||||
<textarea id="newMessageInput" class="disabledChat" placeholder="Public chat is temporarily locked (disabled)" rel="tooltip" data-placement="top" title="Public chat is temporarily locked" disabled></textarea>
|
||||
{{else}}
|
||||
<textarea id="newMessageInput" placeholder="Write a message..." rel="tooltip" data-placement="top" title="Write a new message"></textarea>
|
||||
<button type="submit" id="sendMessageButton" class="btn" rel="tooltip" data-placement="top">
|
||||
Send
|
||||
</button>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -9,3 +9,16 @@ Template.displayUserIcons.events
|
||||
# the userId of the person who is lowering the hand
|
||||
console.log "lower hand- client click handler"
|
||||
Meteor.call('userLowerHand', getInSession("meetingId"), @userId, getInSession("userId"), getInSession("authToken"))
|
||||
|
||||
Template.displayUserIcons.helpers
|
||||
userLockedIconApplicable: (userId) ->
|
||||
# the lock settings affect the user (and requiire a lock icon) if
|
||||
# the user is set to be locked and there is a relevant lock in place
|
||||
locked = BBB.getUser(userId)?.user.locked
|
||||
settings = Meteor.Meetings.findOne()?.roomLockSettings
|
||||
lockInAction = settings.disablePrivChat or
|
||||
settings.disableCam or
|
||||
settings.disableMic or
|
||||
settings.lockedLayout or
|
||||
settings.disablePubChat
|
||||
return locked and lockInAction
|
||||
|
@ -32,6 +32,10 @@
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{#if userLockedIconApplicable userId}}
|
||||
<span class="userListSettingIcon glyphicon ion-locked" rel="tooltip" data-placement="bottom" title="The viewer is locked"></span>
|
||||
{{/if}}
|
||||
|
||||
{{#if user.presenter}}
|
||||
<span class="userListSettingIcon glyphicon glyphicon-picture" rel="tooltip" data-placement="bottom" title="{{user.name}} is the presenter"></span>
|
||||
{{else}}
|
||||
|
@ -1,3 +1,6 @@
|
||||
Template.usersList.helpers
|
||||
getMeetingSize: -> # Retreieve the number of users in the chat, or "error" string
|
||||
return Meteor.Users.find().count()
|
||||
getInfoNumberOfUsers: ->
|
||||
numberUsers = Meteor.Users.find().count()
|
||||
if numberUsers > 8
|
||||
return "Users: #{numberUsers}"
|
||||
# do not display the label if there are just a few users
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template name="usersList">
|
||||
<div id="{{id}}" {{visibility name}} class="component">
|
||||
<h3 class="title gradientBar"><span class="glyphicon glyphicon-user"></span> Participants: {{getMeetingSize}} User(s)</h3>
|
||||
<h3 class="title gradientBar"><span class="glyphicon glyphicon-user heading"></span> {{getInfoNumberOfUsers}} </h3>
|
||||
|
||||
<div id="user-contents">
|
||||
<div class="userlist ScrollableWindowY">
|
||||
|
@ -4,7 +4,7 @@
|
||||
{{#if isMobileChromeOrFirefox}}
|
||||
{{> makeButton btn_class="fullscreenWhiteboardButton" i_class="glyphicon glyphicon-fullscreen"}}
|
||||
{{/if}}
|
||||
<span class="glyphicon glyphicon-pencil"></span>
|
||||
<span class="ion-easel heading"></span>
|
||||
{{title}}
|
||||
</h3>
|
||||
{{#each getCurrentSlide}}
|
||||
|
@ -14,6 +14,8 @@ config.defaultWelcomeMessageFooter = "This server is running a build of <a href=
|
||||
config.maxUsernameLength = 30
|
||||
config.maxChatLength = 140
|
||||
|
||||
config.lockOnJoin = true
|
||||
|
||||
## Application configurations
|
||||
config.app = {}
|
||||
|
||||
|
BIN
bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf
Normal file → Executable file
BIN
bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.ttf
Normal file → Executable file
Binary file not shown.
BIN
bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff
Normal file → Executable file
BIN
bigbluebutton-html5/app/public/packages/ionicons/fonts/ionicons.woff
Normal file → Executable file
Binary file not shown.
@ -2,17 +2,27 @@
|
||||
# Private methods on server
|
||||
# --------------------------------------------------------------------------------------------
|
||||
@addMeetingToCollection = (meetingId, name, intendedForRecording, voiceConf, duration) ->
|
||||
#check if the meeting is already in the collection
|
||||
unless Meteor.Meetings.findOne({meetingId: meetingId})?
|
||||
currentlyBeingRecorded = false # defaut value
|
||||
id = Meteor.Meetings.insert(
|
||||
meetingId: meetingId,
|
||||
meetingName: name,
|
||||
intendedForRecording: intendedForRecording,
|
||||
currentlyBeingRecorded: currentlyBeingRecorded,
|
||||
voiceConf: voiceConf,
|
||||
duration: duration)
|
||||
Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]."
|
||||
#check if the meeting is already in the collection
|
||||
unless Meteor.Meetings.findOne({meetingId: meetingId})?
|
||||
entry =
|
||||
meetingId: meetingId
|
||||
meetingName: name
|
||||
intendedForRecording: intendedForRecording
|
||||
currentlyBeingRecorded: false # defaut value
|
||||
voiceConf: voiceConf
|
||||
duration: duration
|
||||
roomLockSettings:
|
||||
# by default the lock settings will be disabled on meeting create
|
||||
disablePrivChat: false
|
||||
disableCam: false
|
||||
disableMic: false
|
||||
lockOnJoin: Meteor.config.lockOnJoin
|
||||
lockedLayout: false
|
||||
disablePubChat: false
|
||||
|
||||
id = Meteor.Meetings.insert(entry)
|
||||
Meteor.log.info "added meeting _id=[#{id}]:meetingId=[#{meetingId}]:name=[#{name}]:duration=[#{duration}]:voiceConf=[#{voiceConf}]
|
||||
roomLockSettings:[#{JSON.stringify entry.roomLockSettings}]."
|
||||
|
||||
|
||||
@clearMeetingsCollection = (meetingId) ->
|
||||
@ -22,6 +32,7 @@
|
||||
Meteor.Meetings.remove({}, Meteor.log.info "cleared Meetings Collection (all meetings)!")
|
||||
|
||||
|
||||
#clean up upon a meeting's end
|
||||
@removeMeetingFromCollection = (meetingId) ->
|
||||
if Meteor.Meetings.findOne({meetingId: meetingId})?
|
||||
Meteor.log.info "end of meeting #{meetingId}. Clear the meeting data from all collections"
|
||||
|
@ -19,7 +19,7 @@ Meteor.methods
|
||||
payload:
|
||||
userid: userId
|
||||
meeting_id: meetingId
|
||||
voiceConf: voiceConf
|
||||
voice_conf: voiceConf
|
||||
name: username
|
||||
header:
|
||||
timestamp: new Date().getTime()
|
||||
@ -28,7 +28,7 @@ Meteor.methods
|
||||
|
||||
Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}"
|
||||
|
||||
publish Meteor.config.redis.channels.toBBBApps.voice, message
|
||||
publish Meteor.config.redis.channels.toBBBApps.meeting, message
|
||||
|
||||
else
|
||||
if isAllowedTo('leaveListenOnly', meetingId, userId, authToken)
|
||||
@ -36,7 +36,7 @@ Meteor.methods
|
||||
payload:
|
||||
userid: userId
|
||||
meeting_id: meetingId
|
||||
voiceConf: voiceConf
|
||||
voice_conf: voiceConf
|
||||
name: username
|
||||
header:
|
||||
timestamp: new Date().getTime()
|
||||
@ -45,7 +45,7 @@ Meteor.methods
|
||||
|
||||
Meteor.log.info "publishing a user listenOnly toggleRequest #{isJoining} request for #{userId}"
|
||||
|
||||
publish Meteor.config.redis.channels.toBBBApps.voice, message
|
||||
publish Meteor.config.redis.channels.toBBBApps.meeting, message
|
||||
|
||||
return
|
||||
|
||||
@ -204,7 +204,7 @@ Meteor.methods
|
||||
# the collection already contains an entry for this user because
|
||||
# we added a dummy user on register_user_message (to save authToken)
|
||||
if u?
|
||||
Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}"
|
||||
Meteor.log.info "UPDATING USER #{user.userid}, authToken=#{u.authToken}, locked=#{user.locked}"
|
||||
Meteor.Users.update({userId:user.userid, meetingId: meetingId}, {$set:{
|
||||
user:
|
||||
userid: user.userid
|
||||
@ -308,6 +308,36 @@ Meteor.methods
|
||||
Meteor.log.info "added user dummy html5 user with: userid=[#{userId}], id=[#{id}]
|
||||
Users.size is now #{Meteor.Users.find({meetingId: meetingId}).count()}"
|
||||
|
||||
|
||||
# when new lock settings including disableMic are set,
|
||||
# all viewers that are in the audio bridge with a mic should be muted and locked
|
||||
@handleLockingMic = (meetingId, newSettings) ->
|
||||
# send mute requests for the viewer users joined with mic
|
||||
for u in Meteor.Users.find({
|
||||
meetingId:meetingId
|
||||
'user.role':'VIEWER'
|
||||
'user.listenOnly':false
|
||||
'user.locked':true
|
||||
'user.voiceUser.joined':true
|
||||
'user.voiceUser.muted':false})?.fetch()
|
||||
Meteor.log.error u.user.name #
|
||||
Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted
|
||||
|
||||
# change the locked status of a user (lock settings)
|
||||
@setUserLockedStatus = (meetingId, userId, isLocked) ->
|
||||
if Meteor.Users.findOne({userId:userId, meetingId: meetingId})?
|
||||
Meteor.Users.update({userId:userId, meetingId: meetingId}, {$set:{'user.locked': isLocked}})
|
||||
|
||||
# if the user is sharing audio, he should be muted upon locking involving disableMic
|
||||
u = Meteor.Users.findOne({meetingId:meetingId, userId:userId})
|
||||
if u.user.role is 'VIEWER' and !u.user.listenOnly and u.user.voiceUser.joined and !u.user.voiceUser.muted and isLocked
|
||||
Meteor.call('muteUser', meetingId, u.userId, u.userId, u.authToken, true) #true for muted
|
||||
|
||||
Meteor.log.info "setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}"
|
||||
else
|
||||
Meteor.log.error "(unsuccessful-no such user) setting user locked status for userid:[#{userId}] from [#{meetingId}] locked=#{isLocked}"
|
||||
|
||||
|
||||
# called on server start and on meeting end
|
||||
@clearUsersCollection = (meetingId) ->
|
||||
if meetingId?
|
||||
|
@ -1,8 +1,4 @@
|
||||
Meteor.methods
|
||||
#
|
||||
# I dont know if this is okay to be server side. We need to call it from the router, but I don't know if any harm can be caused
|
||||
# by the client calling this
|
||||
#
|
||||
|
||||
# Construct and send a message to bbb-web to validate the user
|
||||
validateAuthToken: (meetingId, userId, authToken) ->
|
||||
@ -60,15 +56,25 @@ class Meteor.RedisPubSub
|
||||
correlationId = message.payload?.reply_to or message.header?.reply_to
|
||||
meetingId = message.payload?.meeting_id
|
||||
|
||||
ignoredEventTypes = [
|
||||
# just because it's common. we handle it anyway
|
||||
notLoggedEventTypes = [
|
||||
"keep_alive_reply"
|
||||
"page_resized_message"
|
||||
"presentation_page_resized_message"
|
||||
"presentation_cursor_updated_message" # just because it's common. we handle it anyway
|
||||
"presentation_cursor_updated_message"
|
||||
"get_presentation_info_reply"
|
||||
# "get_users_reply"
|
||||
"get_chat_history_reply"
|
||||
"get_all_meetings_reply"
|
||||
"presentation_shared_message"
|
||||
"presentation_conversion_done_message"
|
||||
"presentation_conversion_progress_message"
|
||||
"presentation_page_generated_message"
|
||||
"presentation_page_changed_message"
|
||||
]
|
||||
|
||||
if message?.header? and message?.payload?
|
||||
unless message.header.name in ignoredEventTypes
|
||||
unless message.header.name in notLoggedEventTypes
|
||||
Meteor.log.info "eventType= #{message.header.name} ",
|
||||
message: jsonMsg
|
||||
|
||||
@ -281,6 +287,37 @@ class Meteor.RedisPubSub
|
||||
Meteor.Meetings.update({meetingId: meetingId, intendedForRecording: intendedForRecording}, {$set: {currentlyBeingRecorded: currentlyBeingRecorded}})
|
||||
return
|
||||
|
||||
# --------------------------------------------------
|
||||
# lock settings ------------------------------------
|
||||
if message.header.name is "eject_voice_user_message"
|
||||
console.log "\n111111111"
|
||||
return
|
||||
|
||||
if message.header.name is "new_permission_settings"
|
||||
oldSettings = Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings
|
||||
newSettings = message.payload
|
||||
|
||||
# if the disableMic setting was turned on
|
||||
if !oldSettings?.disableMic and newSettings.disableMic
|
||||
handleLockingMic(meetingId, newSettings)
|
||||
|
||||
# substitute with the new lock settings
|
||||
Meteor.Meetings.update({meetingId: meetingId}, {$set: {
|
||||
'roomLockSettings.disablePrivChat': message.payload.disablePrivChat
|
||||
'roomLockSettings.disableCam': message.payload.disableCam
|
||||
'roomLockSettings.disableMic': message.payload.disableMic
|
||||
'roomLockSettings.lockOnJoin': message.payload.lockOnJoin
|
||||
'roomLockSettings.lockedLayout': message.payload.lockedLayout
|
||||
'roomLockSettings.disablePubChat': message.payload.disablePubChat
|
||||
}})
|
||||
return
|
||||
|
||||
if message.header.name is "user_locked_message" or message.header.name is "user_unlocked_message"
|
||||
userId = message.payload.userid
|
||||
isLocked = message.payload.locked
|
||||
setUserLockedStatus(meetingId, userId, isLocked)
|
||||
return
|
||||
|
||||
if message.header.name in ["meeting_ended_message", "meeting_destroyed_event",
|
||||
"end_and_kick_all_message", "disconnect_all_users_message"]
|
||||
if Meteor.Meetings.findOne({meetingId: meetingId})?
|
||||
@ -298,9 +335,9 @@ class Meteor.RedisPubSub
|
||||
|
||||
# message should be an object
|
||||
@publish = (channel, message) ->
|
||||
Meteor.log.info "Publishing",
|
||||
channel: channel
|
||||
message: message
|
||||
# Meteor.log.info "Publishing",
|
||||
# channel: channel
|
||||
# message: message
|
||||
|
||||
if Meteor.redisPubSub?
|
||||
Meteor.redisPubSub.pubClient.publish channel, JSON.stringify(message), (err, res) ->
|
||||
|
@ -1,8 +1,16 @@
|
||||
|
||||
presenter = null
|
||||
|
||||
#for the time being moderators have the same permissions that viewers do
|
||||
# holds the values for whether the moderator user is allowed to perform an action (true)
|
||||
# or false if not allowed. Some actions have dynamic values depending on the current lock settings
|
||||
moderator =
|
||||
# audio listen only
|
||||
joinListenOnly: true
|
||||
leaveListenOnly: true
|
||||
|
||||
# join audio with mic cannot be controlled on the server side as it is
|
||||
# a client side only functionality
|
||||
|
||||
# raising/lowering hand
|
||||
raiseOwnHand : true
|
||||
lowerOwnHand : true
|
||||
@ -18,21 +26,29 @@ moderator =
|
||||
subscribeChat: true
|
||||
|
||||
#chat
|
||||
chatPublic: true #should make this dynamically modifiable later on
|
||||
chatPrivate: true #should make this dynamically modifiable later on
|
||||
chatPublic: true
|
||||
chatPrivate: true
|
||||
|
||||
|
||||
# holds the values for whether the viewer user is allowed to perform an action (true)
|
||||
# or false if not allowed. Some actions have dynamic values depending on the current lock settings
|
||||
viewer = (meetingId, userId) ->
|
||||
|
||||
# listen only
|
||||
joinListenOnly: true #should make this dynamically modifiable later on
|
||||
leaveListenOnly: true #should make this dynamically modifiable later on
|
||||
joinListenOnly: true
|
||||
leaveListenOnly: true
|
||||
|
||||
# join audio with mic cannot be controlled on the server side as it is
|
||||
# a client side only functionality
|
||||
|
||||
viewer =
|
||||
# raising/lowering hand
|
||||
raiseOwnHand : true
|
||||
lowerOwnHand : true
|
||||
|
||||
# muting
|
||||
muteSelf : true
|
||||
unmuteSelf : true
|
||||
unmuteSelf : !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disableMic) or
|
||||
!(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked)
|
||||
|
||||
logoutSelf : true
|
||||
|
||||
@ -41,15 +57,18 @@ viewer =
|
||||
subscribeChat: true
|
||||
|
||||
#chat
|
||||
chatPublic: true #should make this dynamically modifiable later on
|
||||
chatPrivate: true #should make this dynamically modifiable later on
|
||||
chatPublic: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePubChat) or
|
||||
!(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or
|
||||
Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter
|
||||
chatPrivate: !(Meteor.Meetings.findOne({meetingId:meetingId})?.roomLockSettings.disablePrivChat) or
|
||||
!(Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.locked) or
|
||||
Meteor.Users.findOne({meetingId:meetingId, userId:userId})?.user.presenter
|
||||
|
||||
# listen only
|
||||
joinListenOnly: true #should make this dynamically modifiable later on
|
||||
leaveListenOnly: true #should make this dynamically modifiable later on
|
||||
|
||||
|
||||
# carries out the decision making for actions affecting users. For the list of
|
||||
# actions and the default value - see 'viewer' and 'moderator' in the beginning of the file
|
||||
@isAllowedTo = (action, meetingId, userId, authToken) ->
|
||||
# Disclaimer:the current version of the HTML5 client represents only VIEWER users
|
||||
|
||||
validated = Meteor.Users.findOne({meetingId:meetingId, userId: userId})?.validated
|
||||
Meteor.log.info "in isAllowedTo: action-#{action}, userId=#{userId}, authToken=#{authToken} validated:#{validated}"
|
||||
@ -59,7 +78,7 @@ viewer =
|
||||
if user? and authToken is user.authToken # check if the user is who he claims to be
|
||||
if user.validated and user.clientType is "HTML5"
|
||||
if user.user?.role is 'VIEWER' or user.user?.role is 'MODERATOR' or user.user?.role is undefined
|
||||
return viewer[action] or false
|
||||
return viewer(meetingId, userId)[action] or false
|
||||
else
|
||||
Meteor.log.warn "UNSUCCESSFULL ATTEMPT FROM userid=#{userId} to perform:#{action}"
|
||||
return false
|
||||
|
Loading…
Reference in New Issue
Block a user