Add in clientTracking.updatePosition end point

This commit is contained in:
James Allen 2014-11-13 15:27:18 +00:00
parent 84778b5961
commit e769819521
6 changed files with 188 additions and 20 deletions

View file

@ -5,6 +5,16 @@ HttpController = require "./HttpController"
Utils = require "./Utils"
module.exports = Router =
_handleError: (callback, error, client, method, extraAttrs = {}) ->
Utils.getClientAttributes client, ["project_id", "doc_id", "user_id"], (_, attrs) ->
for key, value of extraAttrs
attrs[key] = value
attrs.client_id = client.id
attrs.err = error
logger.error attrs, "server side error in #{method}"
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
configure: (app, io, session) ->
app.set("io", io)
app.get "/clients", HttpController.getConnectedClients
@ -29,9 +39,7 @@ module.exports = Router =
client.on "joinProject", (data = {}, callback) ->
WebsocketController.joinProject client, user, data.project_id, (err, args...) ->
if err?
logger.error {err, user_id: user?.id, project_id: data.project_id}, "server side error in joinProject"
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
Router._handleError callback, err, client, "joinProject", {project_id: data.project_id, user_id: user?.id}
else
callback(null, args...)
@ -44,30 +52,27 @@ module.exports = Router =
WebsocketController.joinDoc client, doc_id, fromVersion, (err, args...) ->
if err?
Utils.getClientAttributes client, ["project_id", "user_id"], (_, {project_id, user_id}) ->
logger.error {err, client_id: client.id, user_id, project_id, doc_id, fromVersion}, "server side error in joinDoc"
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
Router._handleError callback, err, client, "joinDoc", {doc_id, fromVersion}
else
callback(null, args...)
client.on "leaveDoc", (doc_id, callback) ->
WebsocketController.leaveDoc client, doc_id, (err, args...) ->
if err?
Utils.getClientAttributes client, ["project_id", "user_id"], (_, {project_id, user_id}) ->
logger.error {err, client_id: client.id, user_id, project_id, doc_id}, "server side error in leaveDoc"
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
Router._handleError callback, err, client, "leaveDoc"
else
callback(null, args...)
client.on "getConnectedUsers", (callback = (error, users) ->) ->
client.on "clientTracking.getConnectedUsers", (callback = (error, users) ->) ->
WebsocketController.getConnectedUsers client, (err, users) ->
if err?
Utils.getClientAttributes client, ["project_id", "user_id", "doc_id"], (_, {project_id, user_id, doc_id}) ->
logger.error {err, client_id: client.id, user_id, project_id, doc_id}, "server side error in getConnectedUsers"
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
Router._handleError callback, err, client, "clientTracking.getConnectedUsers"
else
callback(null, users)
client.on "clientTracking.updatePosition", (cursorData, callback = (error) ->) ->
WebsocketController.updateClientPosition client, cursorData, (err) ->
if err?
Router._handleError callback, err, client, "clientTracking.updatePosition"
else
callback()

View file

@ -70,7 +70,37 @@ module.exports = WebsocketController =
client.leave doc_id
callback()
updateClientPosition: (client, cursorData, callback = (error) ->) ->
Utils.getClientAttributes client, [
"project_id", "first_name", "last_name", "email", "user_id"
], (error, {project_id, first_name, last_name, email, user_id}) ->
return callback(error) if error?
logger.log {user_id, project_id, client_id: client.id, cursorData: cursorData}, "updating client position"
cursorData.id = client.id
cursorData.user_id = user_id if user_id?
cursorData.email = email if email?
if first_name? and last_name?
cursorData.name = first_name + " " + last_name
ConnectedUsersManager.updateUserPosition(project_id, client.id, {
first_name: first_name,
last_name: last_name,
email: email,
user_id: user_id
}, {
row: cursorData.row,
column: cursorData.column,
doc_id: cursorData.doc_id
}, callback)
else
cursorData.name = "Anonymous"
callback()
#EditorRealTimeController.emitToRoom(project_id, "clientTracking.clientUpdated", cursorData)
#callback()
getConnectedUsers: (client, callback = (error, users) ->) ->
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
logger.log {user_id, project_id, client_id: client.id}, "getting connected users"
AuthorizationManager.assertClientCanViewProject client, (error) ->
return callback(error) if error?
client.get "project_id", (error, project_id) ->

View file

@ -0,0 +1,61 @@
chai = require("chai")
expect = chai.expect
chai.should()
RealTimeClient = require "./helpers/RealTimeClient"
MockWebServer = require "./helpers/MockWebServer"
FixturesManager = require "./helpers/FixturesManager"
describe "clientTracking", ->
before (done) ->
FixturesManager.setUpProject {
privilegeLevel: "owner"
project: {
name: "Test Project"
}
}, (error, data) =>
throw error if error?
{@user_id, @project_id} = data
@clientA = RealTimeClient.connect()
@clientB = RealTimeClient.connect()
@clientA.emit "joinProject", {
project_id: @project_id
}, (error) =>
throw error if error?
@clientB.emit "joinProject", {
project_id: @project_id
}, (error) =>
throw error if error?
done()
describe "when a client updates its cursor location", ->
before (done) ->
@updates = []
@clientB.on "clientTracking.clientUpdated", (data) ->
@updates.push data
@clientA.emit "clientTracking.updatePosition", {
row: @row = 42
column: @column = 36
doc_id: @doc_id = "mock-doc-id"
}, (error) ->
throw error if error?
done()
it "should tell other clients about the update"
it "should record the update in getConnectedUsers", (done) ->
@clientB.emit "clientTracking.getConnectedUsers", (error, users) =>
for user in users
if user.client_id == @clientA.socket.sessionid
expect(user.cursorData).to.deep.equal({
row: @row
column: @column
doc_id: @doc_id
})
return done()
throw new Error("user was never found")
describe "anonymous users", ->
it "should test something..."

View file

@ -47,7 +47,7 @@ describe "joinProject", ->
done()
it "should have marked the user as connected", (done) ->
@client.emit "getConnectedUsers", (error, users) =>
@client.emit "clientTracking.getConnectedUsers", (error, users) =>
connected = false
for user in users
if user.client_id == @client.socket.sessionid and user.user_id == @user_id

View file

@ -16,7 +16,11 @@ module.exports = FixturesManager =
MockWebServer.run (error) =>
throw error if error?
RealTimeClient.setSession {
user: { _id: user_id }
user: {
_id: user_id
first_name: "Joe"
last_name: "Bloggs"
}
}, (error) =>
throw error if error?
callback null, {project_id, user_id, privilegeLevel, project}

View file

@ -217,4 +217,72 @@ describe 'WebsocketController', ->
it "should return an error", ->
@callback.calledWith(@err).should.equal true
describe "updateClientPosition", ->
beforeEach ->
#@EditorRealTimeController.emitToRoom = sinon.stub()
@ConnectedUsersManager.updateUserPosition = sinon.stub().callsArgWith(4)
@update = {
doc_id: @doc_id = "doc-id-123"
row: @row = 42
column: @column = 37
}
describe "with a logged in user", ->
beforeEach ->
@clientParams = {
project_id: @project_id
first_name: @first_name = "Douglas"
last_name: @last_name = "Adams"
email: @email = "joe@example.com"
user_id: @user_id = "user-id-123"
}
@client.get = (param, callback) => callback null, @clientParams[param]
@WebsocketController.updateClientPosition @client, @update
@populatedCursorData =
doc_id: @doc_id,
id: @client.id
name: "#{@first_name} #{@last_name}"
row: @row
column: @column
email: @email
user_id: @user_id
# it "should send the update to the project room with the user's name", ->
# @EditorRealTimeController.emitToRoom.calledWith(@project_id, "clientTracking.clientUpdated", @populatedCursorData).should.equal true
it "should send the cursor data to the connected user manager", (done)->
@ConnectedUsersManager.updateUserPosition.calledWith(@project_id, @client.id, {
user_id: @user_id,
email: @email,
first_name: @first_name,
last_name: @last_name
}, {
row: @row
column: @column
doc_id: @doc_id
}).should.equal true
done()
describe "with an anonymous user", ->
beforeEach ->
@clientParams = {
project_id: @project_id
}
@client.get = (param, callback) => callback null, @clientParams[param]
@WebsocketController.updateClientPosition @client, @update
# it "should send the update to the project room with an anonymous name", ->
# @EditorRealTimeController.emitToRoom
# .calledWith(@project_id, "clientTracking.clientUpdated", {
# doc_id: @doc_id,
# id: @client.id
# name: "Anonymous"
# row: @row
# column: @column
# })
# .should.equal true
it "should not send cursor data to the connected user manager", (done)->
@ConnectedUsersManager.updateUserPosition.called.should.equal false
done()