mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-05 18:01:01 +00:00
Merge pull request #1194 from sharelatex/ew-collabratec-link-project-apis
collabratec link/unlink apis, auth refactor GitOrigin-RevId: dc901494197334e87d3e6702c789654ccef5e56a
This commit is contained in:
parent
f02e3e604b
commit
28c934e8ff
4 changed files with 209 additions and 31 deletions
|
@ -25,9 +25,10 @@ module.exports = AuthorizationManager =
|
|||
# * privilegeLevel: "owner", "readAndWrite", of "readOnly" if the user has
|
||||
# access. false if the user does not have access
|
||||
# * becausePublic: true if the access level is only because the project is public.
|
||||
# * becauseSiteAdmin: true if access level is only because user is admin
|
||||
getPrivilegeLevelForProject: (
|
||||
user_id, project_id, token,
|
||||
callback = (error, privilegeLevel, becausePublic) ->
|
||||
callback = (error, privilegeLevel, becausePublic, becauseSiteAdmin) ->
|
||||
) ->
|
||||
if !user_id?
|
||||
# User is Anonymous, Try Token-based access
|
||||
|
@ -41,48 +42,48 @@ module.exports = AuthorizationManager =
|
|||
return callback(err) if err?
|
||||
if isValidReadOnly
|
||||
# Grant anonymous user read-only access
|
||||
callback null, PrivilegeLevels.READ_ONLY, false
|
||||
callback null, PrivilegeLevels.READ_ONLY, false, false
|
||||
else if (
|
||||
isValidReadAndWrite and
|
||||
TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED
|
||||
)
|
||||
# Grant anonymous user read-and-write access
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, false
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, false, false
|
||||
else
|
||||
# Deny anonymous access
|
||||
callback null, PrivilegeLevels.NONE, false
|
||||
callback null, PrivilegeLevels.NONE, false, false
|
||||
else if publicAccessLevel == PublicAccessLevels.READ_ONLY
|
||||
# Legacy public read-only access for anonymous user
|
||||
callback null, PrivilegeLevels.READ_ONLY, true
|
||||
callback null, PrivilegeLevels.READ_ONLY, true, false
|
||||
else if publicAccessLevel == PublicAccessLevels.READ_AND_WRITE
|
||||
# Legacy public read-write access for anonymous user
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, true
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, true, false
|
||||
else
|
||||
# Deny anonymous user access
|
||||
callback null, PrivilegeLevels.NONE, false
|
||||
callback null, PrivilegeLevels.NONE, false, false
|
||||
else
|
||||
# User is present, get their privilege level from database
|
||||
CollaboratorsHandler.getMemberIdPrivilegeLevel user_id, project_id, (error, privilegeLevel) ->
|
||||
return callback(error) if error?
|
||||
if privilegeLevel? and privilegeLevel != PrivilegeLevels.NONE
|
||||
# The user has direct access
|
||||
callback null, privilegeLevel, false
|
||||
callback null, privilegeLevel, false, false
|
||||
else
|
||||
AuthorizationManager.isUserSiteAdmin user_id, (error, isAdmin) ->
|
||||
return callback(error) if error?
|
||||
if isAdmin
|
||||
callback null, PrivilegeLevels.OWNER, false
|
||||
callback null, PrivilegeLevels.OWNER, false, true
|
||||
else
|
||||
# Legacy public-access system
|
||||
# User is present (not anonymous), but does not have direct access
|
||||
AuthorizationManager.getPublicAccessLevel project_id, (err, publicAccessLevel) ->
|
||||
return callback(err) if err?
|
||||
if publicAccessLevel == PublicAccessLevels.READ_ONLY
|
||||
callback null, PrivilegeLevels.READ_ONLY, true
|
||||
callback null, PrivilegeLevels.READ_ONLY, true, false
|
||||
else if publicAccessLevel == PublicAccessLevels.READ_AND_WRITE
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, true
|
||||
callback null, PrivilegeLevels.READ_AND_WRITE, true, false
|
||||
else
|
||||
callback null, PrivilegeLevels.NONE, false
|
||||
callback null, PrivilegeLevels.NONE, false, false
|
||||
|
||||
canUserReadProject: (user_id, project_id, token, callback = (error, canRead) ->) ->
|
||||
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel) ->
|
||||
|
@ -104,10 +105,10 @@ module.exports = AuthorizationManager =
|
|||
else
|
||||
return callback null, false
|
||||
|
||||
canUserAdminProject: (user_id, project_id, token, callback = (error, canAdmin) ->) ->
|
||||
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel) ->
|
||||
canUserAdminProject: (user_id, project_id, token, callback = (error, canAdmin, becauseSiteAdmin) ->) ->
|
||||
AuthorizationManager.getPrivilegeLevelForProject user_id, project_id, token, (error, privilegeLevel, becausePublic, becauseSiteAdmin) ->
|
||||
return callback(error) if error?
|
||||
return callback null, (privilegeLevel == PrivilegeLevels.OWNER)
|
||||
return callback null, (privilegeLevel == PrivilegeLevels.OWNER), becauseSiteAdmin
|
||||
|
||||
isUserSiteAdmin: (user_id, callback = (error, isAdmin) ->) ->
|
||||
if !user_id?
|
||||
|
|
|
@ -1,6 +1,54 @@
|
|||
ObjectId = require("mongojs").ObjectId
|
||||
Project = require("../../models/Project").Project
|
||||
|
||||
module.exports = ProjectCollabratecDetailsHandler =
|
||||
initializeCollabratecProject: (project_id, name, user_id, collabratec_document_id, collabratec_privategroup_id, callback=(err)->) ->
|
||||
update = $set: { name, collabratecUsers: [ { user_id, collabratec_document_id, collabratec_privategroup_id } ] }
|
||||
initializeCollabratecProject: (project_id, user_id, collabratec_document_id, collabratec_privategroup_id, callback=(err)->) ->
|
||||
try
|
||||
project_id = ObjectId(project_id)
|
||||
user_id = ObjectId(user_id)
|
||||
catch err
|
||||
return callback err
|
||||
update = $set: { collabratecUsers: [ { user_id, collabratec_document_id, collabratec_privategroup_id } ] }
|
||||
Project.update { _id: project_id }, update, callback
|
||||
|
||||
isLinkedCollabratecUserProject: (project_id, user_id, callback=(err, isLinked)->) ->
|
||||
try
|
||||
project_id = ObjectId(project_id)
|
||||
user_id = ObjectId(user_id)
|
||||
catch err
|
||||
return callback err
|
||||
query =
|
||||
_id: project_id
|
||||
collabratecUsers: $elemMatch:
|
||||
user_id: user_id
|
||||
Project.findOne query, {_id: 1}, (err, project) ->
|
||||
callback err if err?
|
||||
callback null, project?
|
||||
|
||||
linkCollabratecUserProject: (project_id, user_id, collabratec_document_id, callback=(err)->) ->
|
||||
try
|
||||
project_id = ObjectId(project_id)
|
||||
user_id = ObjectId(user_id)
|
||||
catch err
|
||||
return callback err
|
||||
query =
|
||||
_id: project_id
|
||||
collabratecUsers: $not: $elemMatch:
|
||||
collabratec_document_id: collabratec_document_id
|
||||
user_id: user_id
|
||||
update = $push: collabratecUsers:
|
||||
collabratec_document_id: collabratec_document_id
|
||||
user_id: user_id
|
||||
Project.update query, update, callback
|
||||
|
||||
unlinkCollabratecUserProject: (project_id, user_id, callback=(err)->) ->
|
||||
try
|
||||
project_id = ObjectId(project_id)
|
||||
user_id = ObjectId(user_id)
|
||||
catch err
|
||||
return callback err
|
||||
query =
|
||||
_id: project_id
|
||||
update = $pull: collabratecUsers:
|
||||
user_id: user_id
|
||||
Project.update query, update, callback
|
||||
|
|
|
@ -42,7 +42,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return the user's privilege level", ->
|
||||
@callback.calledWith(null, "readOnly", false).should.equal true
|
||||
@callback.calledWith(null, "readOnly", false, false).should.equal true
|
||||
|
||||
describe "with a user_id with no privilege level", ->
|
||||
beforeEach ->
|
||||
|
@ -53,7 +53,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return false", ->
|
||||
@callback.calledWith(null, false, false).should.equal true
|
||||
@callback.calledWith(null, false, false, false).should.equal true
|
||||
|
||||
describe "with a user_id who is an admin", ->
|
||||
beforeEach ->
|
||||
|
@ -64,7 +64,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return the user as an owner", ->
|
||||
@callback.calledWith(null, "owner", false).should.equal true
|
||||
@callback.calledWith(null, "owner", false, true).should.equal true
|
||||
|
||||
describe "with no user (anonymous)", ->
|
||||
|
||||
|
@ -86,7 +86,7 @@ describe "AuthorizationManager", ->
|
|||
@TokenAccessHandler.isValidToken.calledWith(@project_id, @token).should.equal true
|
||||
|
||||
it "should return false", ->
|
||||
@callback.calledWith(null, false, false).should.equal true
|
||||
@callback.calledWith(null, false, false, false).should.equal true
|
||||
|
||||
describe 'when the token is valid for read-and-write', ->
|
||||
|
||||
|
@ -108,7 +108,7 @@ describe "AuthorizationManager", ->
|
|||
@TokenAccessHandler.isValidToken.calledWith(@project_id, @token).should.equal true
|
||||
|
||||
it "should deny access", ->
|
||||
@callback.calledWith(null, false, false).should.equal true
|
||||
@callback.calledWith(null, false, false, false).should.equal true
|
||||
|
||||
describe 'when read-write-sharing is enabled', ->
|
||||
beforeEach ->
|
||||
|
@ -165,7 +165,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return the user's privilege level", ->
|
||||
@callback.calledWith(null, "readOnly", false).should.equal true
|
||||
@callback.calledWith(null, "readOnly", false, false).should.equal true
|
||||
|
||||
describe "with a user_id with no privilege level", ->
|
||||
beforeEach ->
|
||||
|
@ -176,7 +176,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return false", ->
|
||||
@callback.calledWith(null, false, false).should.equal true
|
||||
@callback.calledWith(null, false, false, false).should.equal true
|
||||
|
||||
describe "with a user_id who is an admin", ->
|
||||
beforeEach ->
|
||||
|
@ -187,7 +187,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.getPrivilegeLevelForProject @user_id, @project_id, @token, @callback
|
||||
|
||||
it "should return the user as an owner", ->
|
||||
@callback.calledWith(null, "owner", false).should.equal true
|
||||
@callback.calledWith(null, "owner", false, true).should.equal true
|
||||
|
||||
describe "with no user (anonymous)", ->
|
||||
beforeEach ->
|
||||
|
@ -200,7 +200,7 @@ describe "AuthorizationManager", ->
|
|||
@AuthorizationManager.isUserSiteAdmin.called.should.equal false
|
||||
|
||||
it "should return false", ->
|
||||
@callback.calledWith(null, false, false).should.equal true
|
||||
@callback.calledWith(null, false, false, false).should.equal true
|
||||
|
||||
describe "with a public project", ->
|
||||
beforeEach ->
|
||||
|
|
|
@ -13,6 +13,8 @@ modulePath = Path.join __dirname, "../../../../app/js/Features/Project/ProjectCo
|
|||
|
||||
describe "ProjectCollabratecDetailsHandler", ->
|
||||
beforeEach ->
|
||||
@projectId = ObjectId("5bea8747c7bba6012fcaceb3")
|
||||
@userId = ObjectId("5be316a9c7f6aa03802ea8fb")
|
||||
@ProjectModel = {}
|
||||
@ProjectCollabratecDetailsHandler = SandboxedModule.require modulePath, requires:
|
||||
"../../models/Project": { Project: @ProjectModel }
|
||||
|
@ -23,23 +25,150 @@ describe "ProjectCollabratecDetailsHandler", ->
|
|||
describe "when update succeeds", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields()
|
||||
@ProjectCollabratecDetailsHandler.initializeCollabratecProject "project-id", "name", "user-id", "collabratec-document-id", "collabratec-private-group-id", @callback
|
||||
@ProjectCollabratecDetailsHandler.initializeCollabratecProject @projectId, @userId, "collabratec-document-id", "collabratec-private-group-id", @callback
|
||||
|
||||
it "should update project model", ->
|
||||
update = $set: {
|
||||
name: "name",
|
||||
collabratecUsers: [ {
|
||||
user_id: "user-id",
|
||||
user_id: @userId,
|
||||
collabratec_document_id: "collabratec-document-id",
|
||||
collabratec_privategroup_id: "collabratec-private-group-id"
|
||||
} ]
|
||||
}
|
||||
expect(@ProjectModel.update).to.have.been.calledWith { _id: "project-id" }, update, @callback
|
||||
expect(@ProjectModel.update).to.have.been.calledWith { _id: @projectId }, update, @callback
|
||||
|
||||
describe "when update has error", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields("error")
|
||||
@ProjectCollabratecDetailsHandler.initializeCollabratecProject "project-id", "name", "user-id", "collabratec-document-id", "collabratec-private-group-id", @callback
|
||||
@ProjectCollabratecDetailsHandler.initializeCollabratecProject @projectId, @userId, "collabratec-document-id", "collabratec-private-group-id", @callback
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback).to.have.been.calledWith("error")
|
||||
|
||||
describe "with invalid args", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub()
|
||||
@ProjectCollabratecDetailsHandler.initializeCollabratecProject "bad-project-id", "bad-user-id", "collabratec-document-id", "collabratec-private-group-id", @callback
|
||||
|
||||
it "should not update", ->
|
||||
expect(@ProjectModel.update).not.to.have.beenCalled
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback.firstCall.args[0]).to.be.instanceOf Error
|
||||
|
||||
describe "isLinkedCollabratecUserProject", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.findOne = sinon.stub().yields()
|
||||
|
||||
describe "when find succeeds", ->
|
||||
describe "when user project found", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.findOne = sinon.stub().yields(null, "project")
|
||||
@ProjectCollabratecDetailsHandler.isLinkedCollabratecUserProject @projectId, @userId, @callback
|
||||
|
||||
it "should call find with project and user id", ->
|
||||
expect(@ProjectModel.findOne).to.have.been.calledWithMatch {
|
||||
_id: ObjectId(@projectId)
|
||||
collabratecUsers: $elemMatch:
|
||||
user_id: ObjectId(@userId)
|
||||
}
|
||||
|
||||
it "should callback with true", ->
|
||||
expect(@callback).to.have.been.calledWith null, true
|
||||
|
||||
describe "when user project found", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.findOne = sinon.stub().yields(null, null)
|
||||
@ProjectCollabratecDetailsHandler.isLinkedCollabratecUserProject @projectId, @userId, @callback
|
||||
|
||||
it "should callback with false", ->
|
||||
expect(@callback).to.have.been.calledWith null, false
|
||||
|
||||
describe "when find has error", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.findOne = sinon.stub().yields("error")
|
||||
@ProjectCollabratecDetailsHandler.isLinkedCollabratecUserProject @projectId, @userId, @callback
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback).to.have.been.calledWith "error"
|
||||
|
||||
describe "with invalid args", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.findOne = sinon.stub()
|
||||
@ProjectCollabratecDetailsHandler.isLinkedCollabratecUserProject "bad-project-id", "bad-user-id", @callback
|
||||
|
||||
it "should not update", ->
|
||||
expect(@ProjectModel.findOne).not.to.have.beenCalled
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback.firstCall.args[0]).to.be.instanceOf Error
|
||||
|
||||
describe "linkCollabratecUserProject", ->
|
||||
|
||||
describe "when update succeeds", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields()
|
||||
@ProjectCollabratecDetailsHandler.linkCollabratecUserProject @projectId, @userId, "collabratec-document-id", @callback
|
||||
|
||||
it "should update project model", ->
|
||||
query =
|
||||
_id: @projectId
|
||||
collabratecUsers: $not: $elemMatch:
|
||||
collabratec_document_id: "collabratec-document-id"
|
||||
user_id: @userId
|
||||
update = $push: collabratecUsers:
|
||||
collabratec_document_id: "collabratec-document-id"
|
||||
user_id: @userId
|
||||
expect(@ProjectModel.update).to.have.been.calledWith query, update, @callback
|
||||
|
||||
describe "when update has error", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields("error")
|
||||
@ProjectCollabratecDetailsHandler.linkCollabratecUserProject @projectId, @userId, "collabratec-document-id", @callback
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback).to.have.been.calledWith("error")
|
||||
|
||||
describe "with invalid args", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub()
|
||||
@ProjectCollabratecDetailsHandler.linkCollabratecUserProject "bad-project-id", "bad-user-id", "collabratec-document-id", @callback
|
||||
|
||||
it "should not update", ->
|
||||
expect(@ProjectModel.update).not.to.have.beenCalled
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback.firstCall.args[0]).to.be.instanceOf Error
|
||||
|
||||
describe "unlinkCollabratecUserProject", ->
|
||||
|
||||
describe "when update succeeds", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields()
|
||||
@ProjectCollabratecDetailsHandler.unlinkCollabratecUserProject @projectId, @userId, @callback
|
||||
|
||||
it "should update project model", ->
|
||||
query =
|
||||
_id: @projectId
|
||||
update = $pull: collabratecUsers:
|
||||
user_id: @userId
|
||||
expect(@ProjectModel.update).to.have.been.calledWith query, update, @callback
|
||||
|
||||
describe "when update has error", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub().yields("error")
|
||||
@ProjectCollabratecDetailsHandler.unlinkCollabratecUserProject @projectId, @userId, @callback
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback).to.have.been.calledWith("error")
|
||||
|
||||
describe "with invalid args", ->
|
||||
beforeEach ->
|
||||
@ProjectModel.update = sinon.stub()
|
||||
@ProjectCollabratecDetailsHandler.unlinkCollabratecUserProject "bad-project-id", "bad-user-id", @callback
|
||||
|
||||
it "should not update", ->
|
||||
expect(@ProjectModel.update).not.to.have.beenCalled
|
||||
|
||||
it "should callback with error", ->
|
||||
expect(@callback.firstCall.args[0]).to.be.instanceOf Error
|
||||
|
|
Loading…
Reference in a new issue