Merge remote-tracking branch 'perroned/prototype-metor-client' into meteor-rebuild-server

This commit is contained in:
Anton Georgiev 2014-06-11 19:45:02 +00:00
commit c9f8683e0b
19 changed files with 479 additions and 54 deletions

2
client/bbb-html5-client/assets/css/navbar.less Normal file → Executable file
View File

@ -69,7 +69,7 @@
}
.navbar-btn-group-right {
dispaly:block;
display:block;
float:right;
}
}

View File

@ -22,26 +22,30 @@ define [
_registerEvents: ->
globals.events.on "connection:user_list_change", (users) =>
globals.events.trigger("users:user_list_change", users)
globals.events.on "connection:load_users", (users) =>
#alert "load users"
for userBlock in users
@add [
id : userBlock.id
userid: userBlock.id
username: userBlock.name
new UserModel {id: userBlock.id, userid: userBlock.id, username: userBlock.name}
]
globals.events.trigger("users:load_users", users)
globals.events.on "connection:user_join", (userid, username) =>
unless @get(userid)? #check if the user is already present
#globals.events.on "getUsers", =>
#users = @toJSON()
#globals.events.trigger("receiveUsers", users)
globals.events.on "connection:user_join", (newUserid, newUsername) =>
unless @get(newUserid)? #check if the user is already present
#newUser = new UserModel {id: newUserid, userid: newUserid, username: newUsername}
newUser = new UserModel()
newUser.id = newUserid
newUser.userid = newUserid
newUser.username = newUsername
@add [
id : userid
userid: userid
username: username
newUser
]
globals.events.trigger("users:user_join", userid, username)
globals.events.trigger("user:add_new_user", newUser)
globals.events.on "connection:user_left", (userid) =>
toDel = @get(userid)
@ -52,4 +56,7 @@ define [
globals.events.on "connection:setPresenter", (userid) =>
globals.events.trigger("users:setPresenter", userid)
render: ->
alert "user collection rendering"
UsersCollection

View File

@ -17,6 +17,7 @@ define [
@userId = @getUrlVars()["user_id"]
@meetingId = @getUrlVars()["meeting_id"]
@username = @getUrlVars()["username"]
globals.meetingName = decodeURI(@getUrlVars()["meetingName"])
disconnect: ->
alert( " i go through disconnect") # not used right now

20
client/bbb-html5-client/public/js/models/user.coffee Normal file → Executable file
View File

@ -2,10 +2,26 @@ define [
'underscore',
'backbone',
'globals'
], (_, Backbone, globals) ->
'text!templates/user.html'
], (_, Backbone, globals, userTemplate) ->
UserModel = Backbone.Model.extend
initialize: ->
defaults:
id : null
userid: null
username: null
initialize: ->
#alert("iiiiiinitialize"+newUserid+" "+newUsername)
console.log "creation"
isValid: ->
console.log "inside is valid- id: #{@id} userid: #{@userid} username: #{@username}"
value = @id? and @userid? and @username?
render: ->
_.template(userTemplate, {userID: @userid, username: @username})
UserModel

View File

@ -8,10 +8,11 @@ define [
'cs!views/session_navbar_hidden',
'cs!views/session_chat',
'cs!views/session_users',
'cs!views/SingleUserView',
'cs!views/session_video'
'cs!views/session_whiteboard'
], ($, _, Backbone, globals, sessionTemplate, SessionNavbarView, SessionNavbarHiddenView,
SessionChatView, SessionUsersView, SessionVideoView, SessionWhiteboardView) ->
SessionChatView, SessionUsersView, SingleUserView, SessionVideoView, SessionWhiteboardView) ->
SessionView = Backbone.View.extend
tagName: 'section'
@ -23,6 +24,7 @@ define [
@navbarHiddenView = new SessionNavbarHiddenView()
@navbarHiddenView.$parentEl = @$el
@chatView = new SessionChatView()
@singleUserView = new SingleUserView()
@usersView = new SessionUsersView()
@videoView = new SessionVideoView()
@whiteboardView = new SessionWhiteboardView()

View File

@ -202,7 +202,7 @@ define [
# Adds a default welcome message to the chat
_addWelcomeMessage: ->
msg = "You are now connected to the meeting '#{globals.currentAuth?.get('meetingID')}'"
msg = "You are now connected to the meeting '#{globals.meetingName}'"
@_addChatMessage("System", msg)
SessionChatView

View File

@ -22,6 +22,7 @@ define [
initialize: ->
@$parentEl = null
@usersShown = true # Whether the user's pane is displayed, it is displayed be default
render: ->
compiledTemplate = _.template(sessionNavbarTemplate)
@ -41,9 +42,15 @@ define [
@$parentEl.toggleClass('chat-on')
@_setToggleButtonsStatus()
# Toggle the visibility of the users panel
# Toggle the visibility of the user's pane
_toggleUsers: ->
@$parentEl.toggleClass('users-on')
if @usersShown # If the user's pane is displayed, hide it and mark flag as hidden
$("#users").hide()
@usersShown=false
else # Display the pane
$("#users").show()
@usersShown=true
#@$parentEl.toggleClass('users-on')
@_setToggleButtonsStatus()
_toggleVideo: ->
@ -65,6 +72,7 @@ define [
_scheduleResize: (id) ->
attempts = 0
before = $(id).is(':visible')
console.log "isvisible: "+before
interval = setInterval( ->
if $(id).is(':visible') != before or attempts > 20
attempts += 1

View File

@ -19,8 +19,9 @@ define [
"click .user": "_userClicked"
initialize: ->
@userListID = "#user-list"
userListID = "#user-list"
@model.start()
@users = null
# Bind to the event triggered when the client connects to the server
if globals.connection.isConnected()
@ -30,6 +31,7 @@ define [
@_registerEvents()
render: ->
# this renders to unordered list where users will be appended to
compiledTemplate = _.template(sessionUsersTemplate)
@$el.html compiledTemplate
@ -40,16 +42,22 @@ define [
globals.events.on "users:user_list_change", (users) =>
@_removeAllUsers()
for userBlock in users
alert("on user_list_change; adding user:" + JSON.stringify userBlock)
console.log("on user_list_change; adding user:" + JSON.stringify userBlock)
@_addUser(userBlock.id, userBlock.name)
#globals.events.on "receiveUsers", (data) =>
#@users = data
globals.events.on "users:load_users", (users) =>
@_removeAllUsers()
for userBlock in users
@_addUser(userBlock.userid, userBlock.name)
#@_addUser(userBlock.userid, userBlock.name)
globals.events.trigger "user:add_new_user", {id: userBlock.userid, userid: userBlock.userid, username: userBlock.name}
globals.events.on "users:user_join", (userid, username) =>
@_addUser(userid, username)
#@_addUser(userid, username)
console.log "fffffffffffffff"
globals.events.trigger "user:add_new_user", {id: userid, userid: userid, username: username}
globals.events.on "users:user_left", (userid) =>
@_removeUserByID(userid)
@ -65,20 +73,6 @@ define [
_removeUserByID: (userID)->
@$("#user-"+userID).remove()
# Add a user to the screen.
_addUser: (userID, username) ->
if userID? and username?
data =
username: username
userID: userID
compiledTemplate = _.template(userTemplate, data)
# TODO!!!! only add the new element if it doesn't exist yet
# this will resolve the problem of users displayed multiple times in the userlist
@$el.children("ul").append compiledTemplate
# Marks a user as selected when clicked.
_userClicked: (e) ->
@$('.user.selected').removeClass('selected')

View File

@ -40,7 +40,7 @@ login = (req, resp) ->
"\nauth_token = " + auth_token
url = "#{configJson.settings.IP}:3000/html5.client?meeting_id=" + meeting_id + "&user_id=" +
user_id + "&auth_token=" + auth_token + "&username=" + joinParams.fullName
user_id + "&auth_token=" + auth_token + "&username=" + joinParams.fullName + "&meetingName=" + joinParams.meetingID
json =
resp.json({

8
labs/meteor-client/client/stylesheets/style.css Normal file → Executable file
View File

@ -92,3 +92,11 @@ margin-bottom: 10px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
}
.raiseHand {
}
.lowerHand{
}
.kickUser{
}
.signin{}

90
labs/meteor-client/client/views/users/user_item.html Normal file → Executable file
View File

@ -1,7 +1,89 @@
<template name="userItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
<li class="user-wrapper">
<div class="row">
<div class="user-role col-md-1" id="user-{{user.externUserId}}"><i class="icon fa fa-user"></i></div>
<div class="user-name col-md-5">{{user.name}}</div>
<!--<div class="user-video col-md-1"><i class="icon fa fa-video-camera"></i></div>
<div class="user-audio col-md-1"><i class="icon fa fa-microphone"></i></div>
<div class="user-kick col-md-1"><i class="icon fa fa-sign-out"></i></div>-->
<div ><i class="icon fa fa-video-camera"></i></div>
<div ><i class="icon fa fa-microphone"></i></div>
<div ><i class="icon fa fa-sign-out"></i></div>
<!-- some user info -->
{{#if user.presenter}}
<span><strong>{{user.name}} is the Presenter</strong></span>
{{/if}}
{{#if user.sharingAudio}}
<span>{{user.name}} is sharing Audio</span>
{{else}}
<span>{{user.name}} is <strong>NOT</strong> sharing Audio</span>
{{/if}}
<span>-</span>
{{#if user.sharingVideo}}
<span>{{user.name}} is sharing Video</span>
{{else}}
<span>{{user.name}} is <strong>NOT</strong> sharing Video</span>
{{/if}}
<br/>
<!-- controls user has access to -->
{{#with getCurrentUser}} <!--We need a helper to get the current user, because the current context (this) is the user being displayed-->
{{#if compareUserIds this.user.userId ../user.userId}}
<p>The current user</p>
<span>User Controls:</span>
<input type="button" class="raiseHand" id="{{user.externUserId}}" value="Raise hand" />
{{#if user.handRaised}}
<span>{{user.name}}&#39;s hand is raised</span>
{{/if}}
<!-- toggles for own user's mic and cam-->
{{#if user.sharingAudio}}
<input type="button" class="disableMic" id="{{user.externUserId}}" value="Mute"/>
{{else}}
<input type="button" class="enableMic" id="{{user.externUserId}}" value="Unmute"/>
{{/if}}
{{#if user.sharingVideo}}
<input type="button" class="disableCam" id="{{user.externUserId}}" value="Hide Webcam"/>
{{else}}
<input type="button" class="enableCam" id="{{user.externUserId}}" value="Share Webcam"/>
{{/if}}
{{/if}}
{{/with}}
<!-- If a hand is raised teacher can 'answer' which just turns off the raised hand flag
can only be done if hand is raised -->
<p>Teacher controls:
{{#if user.handRaised}}
<input type="button" class="lowerHand" id="{{user.externUserId}}" value="Answer Question"/>
{{else}}
<input type="button" class="lowerHand" id="{{user.externUserId}}" value="Answer Question" disabled/>
{{/if}}
{{#with getCurrentUser}}
{{#if user.permissions.disableCam}}
<input type="button" class="disableCam" id="{{user.externUserId}}" value="Disable webcam"/>
{{/if}}
{{#if user.permissions.disableMic}}
<input type="button" class="disableMic" id="{{user.externUserId}}" value="Disable mic"/>
{{/if}}
{{/with}}
{{#if user.presenter}}
<input type="button" class="setPresenter" id="{{user.externUserId}}" value="Set this user as the presenter" disabled/>
{{else}}
<input type="button" class="setPresenter" id="{{user.externUserId}}" value="Set this user as the presenter"/>
{{/if}}
<input type="button" class="kickUser" id="{{user.externUserId}}" value="Kick from Call" />
</p>
</div>
</div>
</li>
<hr/>
</template>

81
labs/meteor-client/client/views/users/user_item.js Normal file → Executable file
View File

@ -3,5 +3,84 @@ Template.userItem.helpers({
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
},
// for now just assume user is the first person we find
getCurrentUser: function(){
id = Session.get("userId") || "a1a1a1a1a1a1";
var u = Users.findOne({"user.userId":id});
return u;
},
// using handlebars' {{equals}} wasn't working for these some reason, so a simple JS function to do it
compareUserIds: function(u1, u2){
return u1 === u2;
},
});
Template.userItem.events({
'click input.raiseHand': function(event){
Users.update({_id:this._id}, {$set: {"user.handRaised": true}});
},
'click input.disableCam': function(event){
Users.update({_id:this._id},{$set: {"user.sharingVideo": false}});
},
'click input.disableMic': function(event){
Users.update({_id:this._id}, {$set: {"user.sharingAudio": false}});
},
'click input.enableMic': function(event){
Users.update({_id:this._id},{$set: {"user.sharingAudio": true}});
},
'click input.enableCam': function(event){
Users.update({_id:this._id},{$set: {"user.sharingVideo": true}});
},
'click input.lowerHand': function(event){
Users.update({_id:this._id}, {$set: {"user.handRaised": false}});
},
'click input.setPresenter': function(event){
/*
* Not the best way to go about doing this
* The meeting should probably know about the presenter instead of the individual user
*/
// only perform operation is user is not already presenter, prevent extra DB work
if(!this.user.presenter){
// from new user, find meeting
var m = Meetings.findOne({meetingName: this.meetingId});
// unset old user as presenter
if(m){
var u = Users.findOne({meetingId:m.meetingName, 'user.presenter':true})
Users.update({_id:u._id}, {$set: {'user.presenter': false}});
}
// set newly selected user as presenter
Users.update({_id:this._id}, {$set: {"user.presenter": true}});
}
},
'click input.kickUser': function(event){
/*
* Add:
* When user is blown away, if they were presenter remove that from meeting (if kicking the presenter is even possible?)
*/
var user = this;
var meeting = Meetings.findOne({meetingName:this.meetingId});
if(user !== null && meeting !== null) {
// find users index. I couldn't get indexOf() working because the array is of objects
var index = -1;
for(var i = 0; i < meeting.users.length; i++){
if(meeting.users[i].userId == user.user.externUserId){
index = i;
break;
}
}
if(index >= 0) {
meeting.users.splice(index, 1);// remove user from meeting
Meetings.update({_id:meeting._id}, {$set:{users: meeting.users}});// update meeting
// remove meeting from user
Users.update({_id:this._id}, {$set: {"meetingId": null}});
}
}
}
});

20
labs/meteor-client/client/views/users/users_list.html Normal file → Executable file
View File

@ -1,7 +1,21 @@
<template name="usersList">
<div class="posts">
{{#each users}}
{{> userItem}}
<div>
{{#each getMeetings}}
<p>Meeting Name: {{meetingName}}</p>
<p>Users in meeting:</p>
<!-- Retrieve all users in the meeting -->
<h3>User List</h3>
<ul id="user-list">
{{#each getUsersInMeeting meetingName}}
{{> userItem}}
{{/each}}
</ul>
{{/each}}
</div>
<div>
<input type="button" class="signin" id="a1a1a1a1a1a1" value="Signin as RED" />
<input type="button" class="signin" id="b2b2b2b2b2b2" value="Signin as BLUE" />
<input type="button" class="signin" id="c3c3c3c3c3c3" value="Signin as Joe" />
</div>
</template>

23
labs/meteor-client/client/views/users/users_list.js Normal file → Executable file
View File

@ -17,5 +17,26 @@ var postsData = [
];
Template.usersList.helpers({
users: postsData
users: function() {
console.log (Users);
//console.log
return Users.find();
},
getMeetings: function(){
return Meetings.find();
},
/* should be changed to find all users listed in the meeting and retrieve them,
instead of here where we retrieve every user pointing to the meeting */
getUsersInMeeting: function(meetingName){
return Users.find({meetingId: meetingName});
}
});
Template.usersList.events({
'click input.signin': function(event){
Session.set("userId", event.target.id);
}
});

1
labs/meteor-client/collections/users.js Normal file → Executable file
View File

@ -1,4 +1,5 @@
Users = new Meteor.Collection('bbb_users');
Meetings = new Meteor.Collection('meetings');
Meteor.methods({
authenticate: function(auth) {

View File

@ -0,0 +1,25 @@
SetCollectionPermissions = function() {
/*Users.allow({
'insert': function(userId, doc){
return userId;
},
'update': function(userId, doc, fields, modifier){
return userId;
},
});*/
/*Meetings.users.allow({
'insert': function(userId, doc){
return Roles.userIsInRole(Meteor.user(), ["admin"]);
},
'update': function (userId, doc, fields, modifier) {
return Roles.userIsInRole(Meteor.user(), ["admin"]) && doc.username !== "Admin";
},
remove: function(userId, doc) {
return Roles.userIsInRole(userId, ["admin"]) && doc.username !== "Admin";
}
});*/
return 0;
}

View File

@ -0,0 +1,126 @@
CreateSeedData = function() {
////////////////////////////////////////////////////////////////////
// Create Seed Data
//
if(Meetings.find().count() === 0) {
console.log("recreating meeting");
Meetings.insert({
meetingName: "Classroom1",
users: [
{userId: "a1a1a1a1a1a1"},
{userId: "b2b2b2b2b2b2"},
{userId: "c3c3c3c3c3c3"}
]
});
}
if (Users.find().count() === 0) {
Users.insert({
meetingId: "Classroom1",
user: {
handRaised: false,
phoneUser: false,
presenter: true,
sharingAudio: true,
sharingVideo: true,
externUserId: "a1a1a1a1a1a1",
webcamStream: "",
userId: "a1a1a1a1a1a1",
name: "RED",
permissions: {
disablePrivChat: false,
disableCam: true,
disableMic: true,
lockedLayout: false,
disablePubChat: false
},
hasStream: false,
role: "MODERATOR",
locked: false,
voiceUser: {
talking: false,
webUserId: "a1a1a1a1a1a1",
joined: false,
muted: false,
userId: "a1a1a1a1a1a1",
callerNum: "RED",
callerName: "RED",
locked: false
},
listenOnly: false
}
});
Users.insert({
meetingId: "Classroom1",
user: {
handRaised: false,
phoneUser: false,
presenter: false,
sharingAudio: true,
sharingVideo: false,
externUserId: "b2b2b2b2b2b2",
webcamStream: "",
userId: "b2b2b2b2b2b2",
name: "BLUE",
permissions: {
disablePrivChat: false,
disableCam: false,
disableMic: false,
lockedLayout: false,
disablePubChat: false
},
hasStream: false,
role: "USER",
locked: false,
voiceUser: {
talking: false,
webUserId: "b2b2b2b2b2b2",
joined: false,
muted: false,
userId: "b2b2b2b2b2b2",
callerNum: "BLUE",
callerName: "BLUE",
locked: false
},
listenOnly: false
}
});
Users.insert({
meetingId: "Classroom1",
user: {
handRaised: false,
phoneUser: false,
presenter: false,
sharingAudio: true,
sharingVideo: false,
externUserId: "c3c3c3c3c3c3",
webcamStream: "",
userId: "c3c3c3c3c3c3",
name: "Joe",
permissions: {
disablePrivChat: false,
disableCam: false,
disableMic: false,
lockedLayout: false,
disablePubChat: false
},
hasStream: false,
role: "USER",
locked: false,
voiceUser: {
talking: false,
webUserId: "c3c3c3c3c3c3",
joined: false,
muted: false,
userId: "c3c3c3c3c3c3",
callerNum: "Joe",
callerName: "Joe",
locked: false
},
listenOnly: false
}
});
}
}

View File

@ -0,0 +1,16 @@
PublishCollections = function() {
////////////////////////////////////////////////////////////////////
// Publish
//
/*
// publish Users
Meteor.publish("Users", function () {
return Orders.find();
});
// publish Meetings
Meteor.publish("Meetings", function () {
return Orders.find();
});*/
}

View File

@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////////////
// Startup
//
Meteor.startup(function () {
console.log('server start');
// cleanup collections
remove_all_data = false;
if(remove_all_data){
Meteor.users.remove({});
Users.remove({});
Meetings.remove({});
}
// Add seed data if first time server starting
CreateSeedData();
// Publish data collections
PublishCollections();
// Set collection permissions
SetCollectionPermissions();
});