mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 07:45:26 -05:00
Show who is online
This commit is contained in:
parent
3995de3cfc
commit
37a12e88c1
9 changed files with 168 additions and 71 deletions
|
@ -13,62 +13,64 @@ FOUR_DAYS_IN_S = ONE_DAY_IN_S * 4
|
||||||
|
|
||||||
USER_TIMEOUT_IN_S = ONE_HOUR_IN_S
|
USER_TIMEOUT_IN_S = ONE_HOUR_IN_S
|
||||||
|
|
||||||
buildProjectSetKey = (project_id)-> return "users_in_project:#{project_id}"
|
buildProjectSetKey = (project_id)-> return "clients_in_project:#{project_id}"
|
||||||
buildUserKey = (project_id, user_id)-> return "connected_user:#{project_id}:#{user_id}"
|
buildUserKey = (project_id, client_id)-> return "connected_user:#{project_id}:#{client_id}"
|
||||||
|
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
|
|
||||||
markUserAsConnected: (project_id, user_id, callback = (err)->)->
|
markUserAsConnected: (project_id, client_id, user, callback = (err)->)->
|
||||||
logger.log project_id:project_id, user_id:user_id, "marking user as connected"
|
logger.log project_id:project_id, client_id:client_id, "marking user as connected"
|
||||||
|
|
||||||
multi = rclient.multi()
|
multi = rclient.multi()
|
||||||
multi.sadd buildProjectSetKey(project_id), user_id
|
multi.sadd buildProjectSetKey(project_id), client_id
|
||||||
multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
|
multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
|
||||||
multi.hset buildUserKey(project_id, user_id), "connected_at", new Date()
|
multi.hset buildUserKey(project_id, client_id), "connected_at", Date.now()
|
||||||
multi.expire buildUserKey(project_id, user_id), USER_TIMEOUT_IN_S
|
multi.hset buildUserKey(project_id, client_id), "user_id", user._id
|
||||||
|
multi.hset buildUserKey(project_id, client_id), "first_name", user.first_name
|
||||||
|
multi.hset buildUserKey(project_id, client_id), "last_name", user.last_name
|
||||||
|
multi.hset buildUserKey(project_id, client_id), "email", user.email
|
||||||
|
multi.expire buildUserKey(project_id, client_id), USER_TIMEOUT_IN_S
|
||||||
multi.exec (err)->
|
multi.exec (err)->
|
||||||
if err?
|
if err?
|
||||||
logger.err err:err, project_id:project_id, user_id:user_id, "problem marking user as connected"
|
logger.err err:err, project_id:project_id, client_id:client_id, "problem marking user as connected"
|
||||||
callback(err)
|
callback(err)
|
||||||
|
|
||||||
markUserAsDisconnected: (project_id, user_id, callback)->
|
markUserAsDisconnected: (project_id, client_id, callback)->
|
||||||
logger.log project_id:project_id, user_id:user_id, "marking user as disconnected"
|
logger.log project_id:project_id, client_id:client_id, "marking user as disconnected"
|
||||||
multi = rclient.multi()
|
multi = rclient.multi()
|
||||||
multi.srem buildProjectSetKey(project_id), user_id
|
multi.srem buildProjectSetKey(project_id), client_id
|
||||||
multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
|
multi.expire buildProjectSetKey(project_id), FOUR_DAYS_IN_S
|
||||||
multi.del buildUserKey(project_id, user_id)
|
multi.del buildUserKey(project_id, client_id)
|
||||||
multi.exec callback
|
multi.exec callback
|
||||||
|
|
||||||
|
|
||||||
_getConnectedUser: (project_id, user_id, callback)->
|
_getConnectedUser: (project_id, client_id, callback)->
|
||||||
rclient.hgetall buildUserKey(project_id, user_id), (err, result)->
|
rclient.hgetall buildUserKey(project_id, client_id), (err, result)->
|
||||||
if !result?
|
if !result?
|
||||||
result =
|
result =
|
||||||
connected : false
|
connected : false
|
||||||
user_id:user_id
|
client_id:client_id
|
||||||
else
|
else
|
||||||
result.connected = true
|
result.connected = true
|
||||||
result.user_id = user_id
|
result.client_id = client_id
|
||||||
if result.cursorData?
|
if result.cursorData?
|
||||||
result.cursorData = JSON.parse(result.cursorData)
|
result.cursorData = JSON.parse(result.cursorData)
|
||||||
result.email = result.cursorData.email
|
|
||||||
result.name = result.cursorData.name
|
|
||||||
callback err, result
|
callback err, result
|
||||||
|
|
||||||
setUserCursorPosition: (project_id, user_id, cursorData, callback)->
|
setUserCursorPosition: (project_id, client_id, cursorData, callback)->
|
||||||
multi = rclient.multi()
|
multi = rclient.multi()
|
||||||
multi.hset buildUserKey(project_id, user_id), "cursorData", JSON.stringify(cursorData)
|
multi.hset buildUserKey(project_id, client_id), "cursorData", JSON.stringify(cursorData)
|
||||||
multi.expire buildUserKey(project_id, user_id), USER_TIMEOUT_IN_S
|
multi.expire buildUserKey(project_id, client_id), USER_TIMEOUT_IN_S
|
||||||
multi.exec callback
|
multi.exec callback
|
||||||
|
|
||||||
|
|
||||||
getConnectedUsers: (project_id, callback)->
|
getConnectedUsers: (project_id, callback)->
|
||||||
self = @
|
self = @
|
||||||
rclient.smembers buildProjectSetKey(project_id), (err, results)->
|
rclient.smembers buildProjectSetKey(project_id), (err, results)->
|
||||||
jobs = results.map (user_id)->
|
jobs = results.map (client_id)->
|
||||||
(cb)->
|
(cb)->
|
||||||
self._getConnectedUser(project_id, user_id, cb)
|
self._getConnectedUser(project_id, client_id, cb)
|
||||||
async.series jobs, (err, users)->
|
async.series jobs, (err, users)->
|
||||||
users = _.filter users, (user)->
|
users = _.filter users, (user)->
|
||||||
user.connected
|
user.connected
|
||||||
|
|
|
@ -59,16 +59,14 @@ module.exports = EditorController =
|
||||||
callback null, ProjectEditorHandler.buildProjectModelView(project), privilegeLevel, EditorController.protocolVersion
|
callback null, ProjectEditorHandler.buildProjectModelView(project), privilegeLevel, EditorController.protocolVersion
|
||||||
|
|
||||||
# can be done affter the connection has happened
|
# can be done affter the connection has happened
|
||||||
EditorRealTimeController.emitToRoom(project_id, "ConnectedUsers.userConnected", user)
|
ConnectedUsersManager.markUserAsConnected project_id, client.id, user, ->
|
||||||
ConnectedUsersManager.markUserAsConnected project_id, user._id, ->
|
|
||||||
|
|
||||||
leaveProject: (client, user) ->
|
leaveProject: (client, user) ->
|
||||||
self = @
|
self = @
|
||||||
client.get "project_id", (error, project_id) ->
|
client.get "project_id", (error, project_id) ->
|
||||||
return if error? or !project_id?
|
return if error? or !project_id?
|
||||||
EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientDisconnected", client.id)
|
EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientDisconnected", client.id)
|
||||||
EditorRealTimeController.emitToRoom(project_id, "ConnectedUsers.userDissconected", user)
|
ConnectedUsersManager.markUserAsDisconnected project_id, client.id, ->
|
||||||
ConnectedUsersManager.markUserAsDisconnected project_id, user._id, ->
|
|
||||||
logger.log user_id:user._id, project_id:project_id, "user leaving project"
|
logger.log user_id:user._id, project_id:project_id, "user leaving project"
|
||||||
self.flushProjectIfEmpty(project_id)
|
self.flushProjectIfEmpty(project_id)
|
||||||
|
|
||||||
|
@ -126,7 +124,11 @@ module.exports = EditorController =
|
||||||
cursorData.email = email if email?
|
cursorData.email = email if email?
|
||||||
if first_name? and last_name?
|
if first_name? and last_name?
|
||||||
cursorData.name = first_name + " " + last_name
|
cursorData.name = first_name + " " + last_name
|
||||||
ConnectedUsersManager.setUserCursorPosition(project_id, user_id, cursorData, ->)
|
ConnectedUsersManager.setUserCursorPosition(project_id, client.id, {
|
||||||
|
row: cursorData.row,
|
||||||
|
column: cursorData.column,
|
||||||
|
doc_id: cursorData.doc_id
|
||||||
|
}, ->)
|
||||||
else
|
else
|
||||||
cursorData.name = "Anonymous"
|
cursorData.name = "Anonymous"
|
||||||
EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientUpdated", cursorData)
|
EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientUpdated", cursorData)
|
||||||
|
|
|
@ -39,6 +39,20 @@ header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading")
|
||||||
i.fa.fa-pencil
|
i.fa.fa-pencil
|
||||||
|
|
||||||
.toolbar-right
|
.toolbar-right
|
||||||
|
span.online-users(
|
||||||
|
ng-show="onlineUsersArray.length > 0"
|
||||||
|
ng-controller="OnlineUsersController"
|
||||||
|
)
|
||||||
|
span.online-user(
|
||||||
|
ng-repeat="user in onlineUsersArray",
|
||||||
|
ng-style="{ 'background-color': 'hsl({{ getHueForUserId(user.user_id) }}, 100%, 50%)' }",
|
||||||
|
popover="{{ user.name }}"
|
||||||
|
popover-placement="bottom"
|
||||||
|
popover-append-to-body="true"
|
||||||
|
popover-trigger="mouseenter"
|
||||||
|
ng-click="gotoUser(user)"
|
||||||
|
) {{ user.name.slice(0,1) }}
|
||||||
|
|
||||||
a.btn.btn-full-height(
|
a.btn.btn-full-height(
|
||||||
href,
|
href,
|
||||||
ng-if="permissions.admin",
|
ng-if="permissions.admin",
|
||||||
|
|
|
@ -1,30 +1,63 @@
|
||||||
define [
|
define [
|
||||||
"libs/md5"
|
"libs/md5"
|
||||||
|
"ide/online-users/controllers/OnlineUsersController"
|
||||||
], () ->
|
], () ->
|
||||||
class OnlineUsersManager
|
class OnlineUsersManager
|
||||||
constructor: (@ide, @$scope) ->
|
constructor: (@ide, @$scope) ->
|
||||||
@$scope.onlineUsers = {}
|
@$scope.onlineUsers = {}
|
||||||
@$scope.onlineUserCursorHighlights = {}
|
@$scope.onlineUserCursorHighlights = {}
|
||||||
|
@$scope.onlineUsersArray = []
|
||||||
|
|
||||||
@$scope.$on "cursor:editor:update", (event, position) =>
|
@$scope.$on "cursor:editor:update", (event, position) =>
|
||||||
@sendCursorPositionUpdate(position)
|
@sendCursorPositionUpdate(position)
|
||||||
|
|
||||||
|
@$scope.$on "project:joined", () =>
|
||||||
|
ide.$http
|
||||||
|
.get "/project/#{@ide.$scope.project._id}/connected_users"
|
||||||
|
.success (connectedUsers) =>
|
||||||
|
@$scope.onlineUsers = {}
|
||||||
|
for user in connectedUsers or []
|
||||||
|
if user.client_id == @ide.socket.socket.sessionid
|
||||||
|
# Don't store myself
|
||||||
|
continue
|
||||||
|
# Store data in the same format returned by clientTracking.clientUpdated
|
||||||
|
@$scope.onlineUsers[user.client_id] = {
|
||||||
|
id: user.client_id
|
||||||
|
user_id: user.user_id
|
||||||
|
email: user.email
|
||||||
|
name: "#{user.first_name} #{user.last_name}"
|
||||||
|
doc_id: user.cursorData?.doc_id
|
||||||
|
row: user.cursorData?.row
|
||||||
|
column: user.cursorData?.column
|
||||||
|
}
|
||||||
|
@refreshOnlineUsers()
|
||||||
|
|
||||||
@ide.socket.on "clientTracking.clientUpdated", (client) =>
|
@ide.socket.on "clientTracking.clientUpdated", (client) =>
|
||||||
if client.id != @ide.socket.socket.sessionid # Check it's not me!
|
if client.id != @ide.socket.socket.sessionid # Check it's not me!
|
||||||
@$scope.$apply () =>
|
@$scope.$apply () =>
|
||||||
@$scope.onlineUsers[client.id] = client
|
@$scope.onlineUsers[client.id] = client
|
||||||
@updateCursorHighlights()
|
@refreshOnlineUsers()
|
||||||
|
|
||||||
@ide.socket.on "clientTracking.clientDisconnected", (client_id) =>
|
@ide.socket.on "clientTracking.clientDisconnected", (client_id) =>
|
||||||
@$scope.$apply () =>
|
@$scope.$apply () =>
|
||||||
delete @$scope.onlineUsers[client_id]
|
delete @$scope.onlineUsers[client_id]
|
||||||
@updateCursorHighlights()
|
@refreshOnlineUsers()
|
||||||
|
|
||||||
|
@$scope.getHueForUserId = (user_id) =>
|
||||||
|
@getHueForUserId(user_id)
|
||||||
|
|
||||||
|
refreshOnlineUsers: () ->
|
||||||
|
@$scope.onlineUsersArray = []
|
||||||
|
|
||||||
|
for client_id, user of @$scope.onlineUsers
|
||||||
|
if user.doc_id?
|
||||||
|
user.doc = @ide.fileTreeManager.findEntityById(user.doc_id)
|
||||||
|
@$scope.onlineUsersArray.push user
|
||||||
|
|
||||||
updateCursorHighlights: () ->
|
|
||||||
@$scope.onlineUserCursorHighlights = {}
|
@$scope.onlineUserCursorHighlights = {}
|
||||||
for client_id, client of @$scope.onlineUsers
|
for client_id, client of @$scope.onlineUsers
|
||||||
doc_id = client.doc_id
|
doc_id = client.doc_id
|
||||||
continue if !doc_id?
|
continue if !doc_id? or !client.row? or !client.column?
|
||||||
@$scope.onlineUserCursorHighlights[doc_id] ||= []
|
@$scope.onlineUserCursorHighlights[doc_id] ||= []
|
||||||
@$scope.onlineUserCursorHighlights[doc_id].push {
|
@$scope.onlineUserCursorHighlights[doc_id].push {
|
||||||
label: client.name
|
label: client.name
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
define [
|
||||||
|
"base"
|
||||||
|
], (App) ->
|
||||||
|
App.controller "OnlineUsersController", ($scope, ide) ->
|
||||||
|
$scope.gotoUser = (user) ->
|
||||||
|
if user.doc? and user.row?
|
||||||
|
ide.editorManager.openDoc(user.doc, gotoLine: user.row + 1)
|
|
@ -8,6 +8,7 @@
|
||||||
@import "./editor/binary-file.less";
|
@import "./editor/binary-file.less";
|
||||||
@import "./editor/search.less";
|
@import "./editor/search.less";
|
||||||
@import "./editor/publish-template.less";
|
@import "./editor/publish-template.less";
|
||||||
|
@import "./editor/online-users.less";
|
||||||
|
|
||||||
.full-size {
|
.full-size {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
14
services/web/public/stylesheets/app/editor/online-users.less
Normal file
14
services/web/public/stylesheets/app/editor/online-users.less
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.online-users {
|
||||||
|
.online-user {
|
||||||
|
background-color: rgb(0, 170, 255);
|
||||||
|
width: 24px;
|
||||||
|
display: inline-block;
|
||||||
|
height: 24px;
|
||||||
|
margin-right: 8px;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
text-transform: uppercase;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,8 +36,14 @@ describe "ConnectedUsersManager", ->
|
||||||
"logger-sharelatex": log:->
|
"logger-sharelatex": log:->
|
||||||
"redis": createClient:=>
|
"redis": createClient:=>
|
||||||
return @rClient
|
return @rClient
|
||||||
@user_id = "32132132"
|
@client_id = "32132132"
|
||||||
@project_id = "dskjh2u21321"
|
@project_id = "dskjh2u21321"
|
||||||
|
@user = {
|
||||||
|
_id: "user-id-123"
|
||||||
|
first_name: "Joe"
|
||||||
|
last_name: "Bloggs"
|
||||||
|
email: "joe@example.com"
|
||||||
|
}
|
||||||
|
|
||||||
afterEach ->
|
afterEach ->
|
||||||
tk.reset()
|
tk.reset()
|
||||||
|
@ -47,23 +53,43 @@ describe "ConnectedUsersManager", ->
|
||||||
@rClient.exec.callsArgWith(0)
|
@rClient.exec.callsArgWith(0)
|
||||||
|
|
||||||
it "should set a key with the date and give it a ttl", (done)->
|
it "should set a key with the date and give it a ttl", (done)->
|
||||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@user_id}", "connected_at", new Date()).should.equal true
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "connected_at", Date.now()).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should push the user_id on to the project list", (done)->
|
it "should set a key with the user_id", (done)->
|
||||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
@rClient.sadd.calledWith("users_in_project:#{@project_id}", @user_id).should.equal true
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "user_id", @user._id).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should set a key with the first_name", (done)->
|
||||||
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "first_name", @user.first_name).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should set a key with the last_name", (done)->
|
||||||
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "last_name", @user.last_name).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should set a key with the email", (done)->
|
||||||
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "email", @user.email).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it "should push the client_id on to the project list", (done)->
|
||||||
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
|
@rClient.sadd.calledWith("clients_in_project:#{@project_id}", @client_id).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should add a ttl to the connected user set so it stays clean", (done)->
|
it "should add a ttl to the connected user set so it stays clean", (done)->
|
||||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
@rClient.expire.calledWith("users_in_project:#{@project_id}", 24 * 4 * 60 * 60).should.equal true
|
@rClient.expire.calledWith("clients_in_project:#{@project_id}", 24 * 4 * 60 * 60).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should add a ttl to the connected user so it stays clean", (done)->
|
it "should add a ttl to the connected user so it stays clean", (done)->
|
||||||
@ConnectedUsersManager.markUserAsConnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsConnected @project_id, @client_id, @user, (err)=>
|
||||||
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@user_id}", 60 * 60).should.equal true
|
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@client_id}", 60 * 60).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "markUserAsDisconnected", ->
|
describe "markUserAsDisconnected", ->
|
||||||
|
@ -71,18 +97,18 @@ describe "ConnectedUsersManager", ->
|
||||||
@rClient.exec.callsArgWith(0)
|
@rClient.exec.callsArgWith(0)
|
||||||
|
|
||||||
it "should remove the user from the set", (done)->
|
it "should remove the user from the set", (done)->
|
||||||
@ConnectedUsersManager.markUserAsDisconnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsDisconnected @project_id, @client_id, (err)=>
|
||||||
@rClient.srem.calledWith("users_in_project:#{@project_id}", @user_id).should.equal true
|
@rClient.srem.calledWith("clients_in_project:#{@project_id}", @client_id).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should delete the connected_user string", (done)->
|
it "should delete the connected_user string", (done)->
|
||||||
@ConnectedUsersManager.markUserAsDisconnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsDisconnected @project_id, @client_id, (err)=>
|
||||||
@rClient.del.calledWith("connected_user:#{@project_id}:#{@user_id}").should.equal true
|
@rClient.del.calledWith("connected_user:#{@project_id}:#{@client_id}").should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should add a ttl to the connected user set so it stays clean", (done)->
|
it "should add a ttl to the connected user set so it stays clean", (done)->
|
||||||
@ConnectedUsersManager.markUserAsDisconnected @project_id, @user_id, (err)=>
|
@ConnectedUsersManager.markUserAsDisconnected @project_id, @client_id, (err)=>
|
||||||
@rClient.expire.calledWith("users_in_project:#{@project_id}", 24 * 4 * 60 * 60).should.equal true
|
@rClient.expire.calledWith("clients_in_project:#{@project_id}", 24 * 4 * 60 * 60).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "_getConnectedUser", ->
|
describe "_getConnectedUser", ->
|
||||||
|
@ -90,16 +116,16 @@ describe "ConnectedUsersManager", ->
|
||||||
it "should get the user returning connected if there is a value", (done)->
|
it "should get the user returning connected if there is a value", (done)->
|
||||||
cursorData = JSON.stringify(cursorData:{row:1})
|
cursorData = JSON.stringify(cursorData:{row:1})
|
||||||
@rClient.hgetall.callsArgWith(1, null, {connected_at:new Date(), cursorData})
|
@rClient.hgetall.callsArgWith(1, null, {connected_at:new Date(), cursorData})
|
||||||
@ConnectedUsersManager._getConnectedUser @project_id, @user_id, (err, result)=>
|
@ConnectedUsersManager._getConnectedUser @project_id, @client_id, (err, result)=>
|
||||||
result.connected.should.equal true
|
result.connected.should.equal true
|
||||||
result.user_id.should.equal @user_id
|
result.client_id.should.equal @client_id
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it "should get the user returning connected if there is a value", (done)->
|
it "should get the user returning connected if there is a value", (done)->
|
||||||
@rClient.hgetall.callsArgWith(1)
|
@rClient.hgetall.callsArgWith(1)
|
||||||
@ConnectedUsersManager._getConnectedUser @project_id, @user_id, (err, result)=>
|
@ConnectedUsersManager._getConnectedUser @project_id, @client_id, (err, result)=>
|
||||||
result.connected.should.equal false
|
result.connected.should.equal false
|
||||||
result.user_id.should.equal @user_id
|
result.client_id.should.equal @client_id
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "getConnectedUsers", ->
|
describe "getConnectedUsers", ->
|
||||||
|
@ -108,16 +134,16 @@ describe "ConnectedUsersManager", ->
|
||||||
@users = ["1234", "5678", "9123"]
|
@users = ["1234", "5678", "9123"]
|
||||||
@rClient.smembers.callsArgWith(1, null, @users)
|
@rClient.smembers.callsArgWith(1, null, @users)
|
||||||
@ConnectedUsersManager._getConnectedUser = sinon.stub()
|
@ConnectedUsersManager._getConnectedUser = sinon.stub()
|
||||||
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[0]).callsArgWith(2, null, {connected:true, user_id:@users[0]})
|
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[0]).callsArgWith(2, null, {connected:true, client_id:@users[0]})
|
||||||
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[1]).callsArgWith(2, null, {connected:false, user_id:@users[1]})
|
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[1]).callsArgWith(2, null, {connected:false, client_id:@users[1]})
|
||||||
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[2]).callsArgWith(2, null, {connected:true, user_id:@users[2]})
|
@ConnectedUsersManager._getConnectedUser.withArgs(@project_id, @users[2]).callsArgWith(2, null, {connected:true, client_id:@users[2]})
|
||||||
|
|
||||||
|
|
||||||
it "should only return the users in the list which are still in redis", (done)->
|
it "should only return the users in the list which are still in redis", (done)->
|
||||||
@ConnectedUsersManager.getConnectedUsers @project_id, (err, users)=>
|
@ConnectedUsersManager.getConnectedUsers @project_id, (err, users)=>
|
||||||
users.length.should.equal 2
|
users.length.should.equal 2
|
||||||
users[0].should.deep.equal {user_id:@users[0], connected:true}
|
users[0].should.deep.equal {client_id:@users[0], connected:true}
|
||||||
users[1].should.deep.equal {user_id:@users[2], connected:true}
|
users[1].should.deep.equal {client_id:@users[2], connected:true}
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "setUserCursorPosition", ->
|
describe "setUserCursorPosition", ->
|
||||||
|
@ -127,13 +153,13 @@ describe "ConnectedUsersManager", ->
|
||||||
@rClient.exec.callsArgWith(0)
|
@rClient.exec.callsArgWith(0)
|
||||||
|
|
||||||
it "should add the cursor data to the users hash", (done)->
|
it "should add the cursor data to the users hash", (done)->
|
||||||
@ConnectedUsersManager.setUserCursorPosition @project_id, @user_id, @cursorData, (err)=>
|
@ConnectedUsersManager.setUserCursorPosition @project_id, @client_id, @cursorData, (err)=>
|
||||||
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@user_id}", "cursorData", JSON.stringify(@cursorData)).should.equal true
|
@rClient.hset.calledWith("connected_user:#{@project_id}:#{@client_id}", "cursorData", JSON.stringify(@cursorData)).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
||||||
it "should add the ttl on", (done)->
|
it "should add the ttl on", (done)->
|
||||||
@ConnectedUsersManager.setUserCursorPosition @project_id, @user_id, @cursorData, (err)=>
|
@ConnectedUsersManager.setUserCursorPosition @project_id, @client_id, @cursorData, (err)=>
|
||||||
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@user_id}", 60 * 60).should.equal true
|
@rClient.expire.calledWith("connected_user:#{@project_id}:#{@client_id}", 60 * 60).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ describe "EditorController", ->
|
||||||
@ProjectGetter.populateProjectWithUsers = sinon.stub().callsArgWith(1, null, @project)
|
@ProjectGetter.populateProjectWithUsers = sinon.stub().callsArgWith(1, null, @project)
|
||||||
@AuthorizationManager.setPrivilegeLevelOnClient = sinon.stub()
|
@AuthorizationManager.setPrivilegeLevelOnClient = sinon.stub()
|
||||||
@EditorRealTimeController.emitToRoom = sinon.stub()
|
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||||
@ConnectedUsersManager.markUserAsConnected.callsArgWith(2)
|
@ConnectedUsersManager.markUserAsConnected.callsArgWith(3)
|
||||||
|
|
||||||
describe "when authorized", ->
|
describe "when authorized", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@ -123,11 +123,8 @@ describe "EditorController", ->
|
||||||
it "should return the project model view, privilege level and protocol version", ->
|
it "should return the project model view, privilege level and protocol version", ->
|
||||||
@callback.calledWith(null, @projectModelView, "owner", @EditorController.protocolVersion).should.equal true
|
@callback.calledWith(null, @projectModelView, "owner", @EditorController.protocolVersion).should.equal true
|
||||||
|
|
||||||
it "should emit the to the room that the user has connected", ->
|
|
||||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, "ConnectedUsers.userConnected", @user).should.equal true
|
|
||||||
|
|
||||||
it "should mark the user as connected with the ConnectedUsersManager", ->
|
it "should mark the user as connected with the ConnectedUsersManager", ->
|
||||||
@ConnectedUsersManager.markUserAsConnected.calledWith(@project_id, @user_id).should.equal true
|
@ConnectedUsersManager.markUserAsConnected.calledWith(@project_id, @client.id, @user).should.equal true
|
||||||
|
|
||||||
|
|
||||||
describe "when not authorized", ->
|
describe "when not authorized", ->
|
||||||
|
@ -169,11 +166,8 @@ describe "EditorController", ->
|
||||||
.calledWith(@project_id, "clientTracking.clientDisconnected", @client.id)
|
.calledWith(@project_id, "clientTracking.clientDisconnected", @client.id)
|
||||||
.should.equal true
|
.should.equal true
|
||||||
|
|
||||||
it "should emit the to the room that the user has connected", ->
|
|
||||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, "ConnectedUsers.userDissconected", @user).should.equal true
|
|
||||||
|
|
||||||
it "should mark the user as connected with the ConnectedUsersManager", ->
|
it "should mark the user as connected with the ConnectedUsersManager", ->
|
||||||
@ConnectedUsersManager.markUserAsDisconnected.calledWith(@project_id, @user_id).should.equal true
|
@ConnectedUsersManager.markUserAsDisconnected.calledWith(@project_id, @client.id).should.equal true
|
||||||
|
|
||||||
|
|
||||||
describe "joinDoc", ->
|
describe "joinDoc", ->
|
||||||
|
@ -296,7 +290,11 @@ describe "EditorController", ->
|
||||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, "clientTracking.clientUpdated", @populatedCursorData).should.equal true
|
@EditorRealTimeController.emitToRoom.calledWith(@project_id, "clientTracking.clientUpdated", @populatedCursorData).should.equal true
|
||||||
|
|
||||||
it "should send the cursor data to the connected user manager", (done)->
|
it "should send the cursor data to the connected user manager", (done)->
|
||||||
@ConnectedUsersManager.setUserCursorPosition.calledWith(@project_id, @user_id, @populatedCursorData).should.equal true
|
@ConnectedUsersManager.setUserCursorPosition.calledWith(@project_id, @client.id, {
|
||||||
|
row: @row
|
||||||
|
column: @column
|
||||||
|
doc_id: @doc_id
|
||||||
|
}).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe "with an anonymous user", ->
|
describe "with an anonymous user", ->
|
||||||
|
|
Loading…
Reference in a new issue