mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
Add appltOtUpdate end point (sans acceptance tests for now)
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
module.exports = AuthorizationManager =
|
||||
assertClientCanViewProject: (client, callback = (error) ->) ->
|
||||
AuthorizationManager._assertClientHasPrivilegeLevel client, ["readOnly", "readAndWrite", "owner"], callback
|
||||
|
||||
|
||||
assertClientCanEditProject: (client, callback = (error) ->) ->
|
||||
AuthorizationManager._assertClientHasPrivilegeLevel client, ["readAndWrite", "owner"], callback
|
||||
|
||||
_assertClientHasPrivilegeLevel: (client, allowedLevels, callback = (error) ->) ->
|
||||
client.get "privilege_level", (error, privilegeLevel) ->
|
||||
return callback(error) if error?
|
||||
|
||||
@@ -2,6 +2,9 @@ request = require "request"
|
||||
logger = require "logger-sharelatex"
|
||||
settings = require "settings-sharelatex"
|
||||
|
||||
redis = require("redis-sharelatex")
|
||||
rclient = redis.createClient(settings.redis.web)
|
||||
|
||||
module.exports = DocumentUpdaterManager =
|
||||
getDocument: (project_id, doc_id, fromVersion, callback = (error, exists, doclines, version) ->) ->
|
||||
#timer = new metrics.Timer("get-document")
|
||||
@@ -23,4 +26,15 @@ module.exports = DocumentUpdaterManager =
|
||||
err = new Error("doc updater returned a non-success status code: #{res.statusCode}")
|
||||
err.statusCode = res.statusCode
|
||||
logger.error {err, project_id, doc_id, url}, "doc updater returned a non-success status code: #{res.statusCode}"
|
||||
callback err
|
||||
callback err
|
||||
|
||||
queueChange: (project_id, doc_id, change, callback = ()->)->
|
||||
jsonChange = JSON.stringify change
|
||||
doc_key = "#{project_id}:#{doc_id}"
|
||||
multi = rclient.multi()
|
||||
multi.rpush "PendingUpdates:#{doc_id}", jsonChange
|
||||
multi.sadd "DocsWithPendingUpdates", doc_key
|
||||
multi.rpush "pending-updates-list", doc_key
|
||||
multi.exec (error) ->
|
||||
return callback(error) if error?
|
||||
callback()
|
||||
@@ -109,3 +109,27 @@ module.exports = WebsocketController =
|
||||
ConnectedUsersManager.getConnectedUsers project_id, (error, users) ->
|
||||
return callback(error) if error?
|
||||
callback null, users
|
||||
|
||||
applyOtUpdate: (client, project_id, doc_id, update, callback = (error) ->) ->
|
||||
AuthorizationManager.assertClientCanEditProject client, (error) ->
|
||||
if error?
|
||||
logger.error {err: error, project_id, doc_id, client_id: client.id, version: update.v}, "client is not authorized to make update"
|
||||
client.disconnect()
|
||||
return callback(error)
|
||||
|
||||
Utils.getClientAttributes client, ["user_id"], (error, {user_id}) ->
|
||||
return callback(error) if error?
|
||||
update.meta ||= {}
|
||||
update.meta.source = client.id
|
||||
update.meta.user_id = user_id
|
||||
# metrics.inc "editor.doc-update", 0.3
|
||||
# metrics.set "editor.active-projects", project_id, 0.3
|
||||
# metrics.set "editor.active-users", user_id, 0.3
|
||||
|
||||
logger.log {user_id, doc_id, project_id, client_id: client.id, version: update.v}, "sending update to doc updater"
|
||||
|
||||
DocumentUpdaterManager.queueChange project_id, doc_id, update, (error) ->
|
||||
if error?
|
||||
logger.error {err: error, project_id, doc_id, client_id: client.id, version: update.v}, "document was not available for update"
|
||||
client.disconnect()
|
||||
callback(error)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
describe "applyOtUpdate", ->
|
||||
describe "when authorized", ->
|
||||
it "should publish a message on redis"
|
||||
|
||||
it "should add the doc to the pending updates set in redis"
|
||||
|
||||
it "should push the update into redis"
|
||||
|
||||
describe "when not authorized", ->
|
||||
it "should return an error"
|
||||
|
||||
it "should disconnect the client"
|
||||
@@ -35,5 +35,30 @@ describe 'AuthorizationManager', ->
|
||||
it "should return an error with any other privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "unknown"
|
||||
@AuthorizationManager.assertClientCanViewProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
|
||||
describe "assertClientCanEditProject", ->
|
||||
it "should not allow the readOnly privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readOnly"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
|
||||
it "should allow the readAndWrite privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readAndWrite"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should allow the owner privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "owner"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should return an error with any other privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "unknown"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
@@ -12,11 +12,14 @@ describe 'DocumentUpdaterManager', ->
|
||||
@version = 42
|
||||
@settings =
|
||||
apis: documentupdater: url: "http://doc-updater.example.com"
|
||||
redis: web: {}
|
||||
@rclient = {auth:->}
|
||||
|
||||
@DocumentUpdaterManager = SandboxedModule.require modulePath, requires:
|
||||
'settings-sharelatex':@settings
|
||||
'logger-sharelatex': @logger = {log: sinon.stub(), error: sinon.stub()}
|
||||
'request': @request = {}
|
||||
'redis-sharelatex' : createClient: () => @rclient
|
||||
|
||||
describe "getDocument", ->
|
||||
beforeEach ->
|
||||
@@ -58,3 +61,43 @@ describe 'DocumentUpdaterManager', ->
|
||||
@callback
|
||||
.calledWith(err)
|
||||
.should.equal true
|
||||
|
||||
describe 'queueChange', ->
|
||||
beforeEach ->
|
||||
@change = {
|
||||
"action":"removeText",
|
||||
"range":{"start":{"row":2,"column":2},"end":{"row":2,"column":3}},
|
||||
"text":"e"
|
||||
}
|
||||
@rclient.multi = sinon.stub().returns @rclient
|
||||
@rclient.exec = sinon.stub().callsArg(0)
|
||||
@rclient.rpush = sinon.stub()
|
||||
@rclient.sadd = sinon.stub()
|
||||
@callback = sinon.stub()
|
||||
|
||||
describe "successfully", ->
|
||||
beforeEach ->
|
||||
@DocumentUpdaterManager.queueChange(@project_id, @doc_id, @change, @callback)
|
||||
|
||||
it "should push the change", ->
|
||||
@rclient.rpush
|
||||
.calledWith("PendingUpdates:#{@doc_id}", JSON.stringify(@change))
|
||||
.should.equal true
|
||||
|
||||
it "should notify the doc updater of the change via the pending-updates-list queue", ->
|
||||
@rclient.rpush
|
||||
.calledWith("pending-updates-list", "#{@project_id}:#{@doc_id}")
|
||||
.should.equal true
|
||||
|
||||
it "should push the doc id into the pending updates set", ->
|
||||
@rclient.sadd
|
||||
.calledWith("DocsWithPendingUpdates", "#{@project_id}:#{@doc_id}")
|
||||
.should.equal true
|
||||
|
||||
describe "with error connecting to redis during exec", ->
|
||||
beforeEach ->
|
||||
@rclient.exec = sinon.stub().callsArgWith(0, new Error("something went wrong"))
|
||||
@DocumentUpdaterManager.queueChange(@project_id, @doc_id, @change, @callback)
|
||||
|
||||
it "should return an error", ->
|
||||
@callback.calledWithExactly(sinon.match(Error)).should.equal true
|
||||
|
||||
@@ -10,7 +10,7 @@ describe 'WebsocketController', ->
|
||||
tk.freeze(new Date())
|
||||
@project_id = "project-id-123"
|
||||
@user = {
|
||||
_id: "user-id-123"
|
||||
_id: @user_id = "user-id-123"
|
||||
first_name: "James"
|
||||
last_name: "Allen"
|
||||
email: "james@example.com"
|
||||
@@ -19,6 +19,7 @@ describe 'WebsocketController', ->
|
||||
}
|
||||
@callback = sinon.stub()
|
||||
@client =
|
||||
id: @client_id = "mock-client-id-123"
|
||||
params: {}
|
||||
set: sinon.stub()
|
||||
get: (param, cb) -> cb null, @params[param]
|
||||
@@ -286,4 +287,69 @@ describe 'WebsocketController', ->
|
||||
|
||||
it "should not send cursor data to the connected user manager", (done)->
|
||||
@ConnectedUsersManager.updateUserPosition.called.should.equal false
|
||||
done()
|
||||
done()
|
||||
|
||||
describe "applyOtUpdate", ->
|
||||
beforeEach ->
|
||||
@update = {op: {p: 12, t: "foo"}}
|
||||
@client.params.user_id = @user_id
|
||||
@AuthorizationManager.assertClientCanEditProject = sinon.stub().callsArg(1)
|
||||
@DocumentUpdaterManager.queueChange = sinon.stub().callsArg(3)
|
||||
|
||||
describe "succesfully", ->
|
||||
beforeEach ->
|
||||
@WebsocketController.applyOtUpdate @client, @project_id, @doc_id, @update, @callback
|
||||
|
||||
it "should set the source of the update to the client id", ->
|
||||
@update.meta.source.should.equal @client.id
|
||||
|
||||
it "should set the user_id of the update to the user id", ->
|
||||
@update.meta.user_id.should.equal @user_id
|
||||
|
||||
it "should queue the update", ->
|
||||
@DocumentUpdaterManager.queueChange
|
||||
.calledWith(@project_id, @doc_id, @update)
|
||||
.should.equal true
|
||||
|
||||
it "should call the callback", ->
|
||||
@callback.called.should.equal true
|
||||
|
||||
# it "should update the active users metric", ->
|
||||
# @metrics.set.calledWith("editor.active-users", @user_id).should.equal true
|
||||
#
|
||||
# it "should update the active projects metric", ->
|
||||
# @metrics.set.calledWith("editor.active-projects", @project_id).should.equal true
|
||||
#
|
||||
# it "should increment the doc updates", ->
|
||||
# @metrics.inc.calledWith("editor.doc-update").should.equal true
|
||||
|
||||
describe "unsuccessfully", ->
|
||||
beforeEach ->
|
||||
@client.disconnect = sinon.stub()
|
||||
@DocumentUpdaterManager.queueChange = sinon.stub().callsArgWith(3, @error = new Error("Something went wrong"))
|
||||
@WebsocketController.applyOtUpdate @client, @project_id, @doc_id, @update, @callback
|
||||
|
||||
it "should disconnect the client", ->
|
||||
@client.disconnect.called.should.equal true
|
||||
|
||||
it "should log an error", ->
|
||||
@logger.error.called.should.equal true
|
||||
|
||||
it "should call the callback with the error", ->
|
||||
@callback.calledWith(@error).should.equal true
|
||||
|
||||
describe "when not authorized", ->
|
||||
beforeEach ->
|
||||
@client.disconnect = sinon.stub()
|
||||
@AuthorizationManager.assertClientCanEditProject = sinon.stub().callsArgWith(1, @error = new Error("not authorized"))
|
||||
@WebsocketController.applyOtUpdate @client, @project_id, @doc_id, @update, @callback
|
||||
|
||||
it "should disconnect the client", ->
|
||||
@client.disconnect.called.should.equal true
|
||||
|
||||
it "should log an error", ->
|
||||
@logger.error.called.should.equal true
|
||||
|
||||
it "should call the callback with the error", ->
|
||||
@callback.calledWith(@error).should.equal true
|
||||
|
||||
Reference in New Issue
Block a user