mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add an endpoint to access project members
This commit is contained in:
parent
092c036406
commit
8f7603c324
9 changed files with 224 additions and 51 deletions
|
@ -5,6 +5,7 @@ EditorRealTimeController = require "../Editor/EditorRealTimeController"
|
|||
LimitationsManager = require "../Subscription/LimitationsManager"
|
||||
UserGetter = require "../User/UserGetter"
|
||||
EmailHelper = require "../Helpers/EmailHelper"
|
||||
logger = require 'logger-sharelatex'
|
||||
|
||||
|
||||
module.exports = CollaboratorsController =
|
||||
|
@ -50,3 +51,12 @@ module.exports = CollaboratorsController =
|
|||
return callback(error) if error?
|
||||
EditorRealTimeController.emitToRoom(project_id, 'userRemovedFromProject', user_id)
|
||||
callback()
|
||||
|
||||
getAllMembers: (req, res, next) ->
|
||||
projectId = req.params.Project_id
|
||||
logger.log {projectId}, "getting all active members for project"
|
||||
CollaboratorsHandler.getAllMembers projectId, (err, members) ->
|
||||
if err?
|
||||
logger.err {projectId}, "error getting members for project"
|
||||
return next(err)
|
||||
res.json({members: members})
|
||||
|
|
|
@ -8,6 +8,7 @@ async = require "async"
|
|||
PrivilegeLevels = require "../Authorization/PrivilegeLevels"
|
||||
Errors = require "../Errors/Errors"
|
||||
EmailHelper = require "../Helpers/EmailHelper"
|
||||
ProjectEditorHandler = require "../Project/ProjectEditorHandler"
|
||||
|
||||
|
||||
module.exports = CollaboratorsHandler =
|
||||
|
@ -144,3 +145,12 @@ module.exports = CollaboratorsHandler =
|
|||
if error?
|
||||
logger.error {err: error, project_id, user_id}, "error flushing to TPDS after adding collaborator"
|
||||
callback()
|
||||
|
||||
getAllMembers: (projectId, callback=(err, members)->) ->
|
||||
logger.log {projectId}, "fetching all members"
|
||||
CollaboratorsHandler.getMembersWithPrivilegeLevels projectId, (error, rawMembers) ->
|
||||
if error?
|
||||
logger.err {projectId, error}, "error getting members for project"
|
||||
return callback(error)
|
||||
{owner, members} = ProjectEditorHandler.buildOwnerAndMembersViews(rawMembers)
|
||||
callback(null, members)
|
||||
|
|
|
@ -11,6 +11,13 @@ module.exports =
|
|||
webRouter.post '/project/:Project_id/users', AuthorizationMiddlewear.ensureUserCanAdminProject, CollaboratorsController.addUserToProject
|
||||
webRouter.delete '/project/:Project_id/users/:user_id', AuthorizationMiddlewear.ensureUserCanAdminProject, CollaboratorsController.removeUserFromProject
|
||||
|
||||
webRouter.get(
|
||||
'/project/:Project_id/members',
|
||||
AuthenticationController.requireLogin(),
|
||||
AuthorizationMiddlewear.ensureUserCanAdminProject,
|
||||
CollaboratorsController.getAllMembers
|
||||
)
|
||||
|
||||
# invites
|
||||
webRouter.post(
|
||||
'/project/:Project_id/invite',
|
||||
|
@ -26,7 +33,7 @@ module.exports =
|
|||
)
|
||||
|
||||
webRouter.get(
|
||||
'/project/:Project_id/invite',
|
||||
'/project/:Project_id/invites',
|
||||
AuthenticationController.requireLogin(),
|
||||
AuthorizationMiddlewear.ensureUserCanAdminProject,
|
||||
CollaboratorsInviteController.getAllInvites
|
||||
|
|
|
@ -17,16 +17,11 @@ module.exports = ProjectEditorHandler =
|
|||
members: []
|
||||
invites: invites || []
|
||||
|
||||
owner = null
|
||||
for member in members
|
||||
if member.privilegeLevel == "owner"
|
||||
owner = member.user
|
||||
else
|
||||
result.members.push @buildUserModelView member.user, member.privilegeLevel
|
||||
if owner?
|
||||
result.owner = @buildUserModelView owner, "owner"
|
||||
{owner, ownerFeatures, members} = @buildOwnerAndMembersViews(members)
|
||||
result.owner = owner
|
||||
result.members = members
|
||||
|
||||
result.features = _.defaults(owner?.features or {}, {
|
||||
result.features = _.defaults(ownerFeatures or {}, {
|
||||
collaborators: -1 # Infinite
|
||||
versioning: false
|
||||
dropbox:false
|
||||
|
@ -38,6 +33,18 @@ module.exports = ProjectEditorHandler =
|
|||
|
||||
return result
|
||||
|
||||
buildOwnerAndMembersViews: (members) ->
|
||||
owner = null
|
||||
ownerFeatures = null
|
||||
filteredMembers = []
|
||||
for member in members
|
||||
if member.privilegeLevel == "owner"
|
||||
ownerFeatures = member.user.features
|
||||
owner = @buildUserModelView member.user, "owner"
|
||||
else
|
||||
filteredMembers.push @buildUserModelView member.user, member.privilegeLevel
|
||||
{owner: owner, ownerFeatures: ownerFeatures, members: filteredMembers}
|
||||
|
||||
buildUserModelView: (user, privileges) ->
|
||||
_id : user._id
|
||||
first_name : user.first_name
|
||||
|
|
|
@ -25,7 +25,7 @@ define [
|
|||
})
|
||||
|
||||
getInvites: () ->
|
||||
$http.get("/project/#{ide.project_id}/invite", {
|
||||
$http.get("/project/#{ide.project_id}/invites", {
|
||||
json: true
|
||||
headers:
|
||||
"X-Csrf-Token": window.csrfToken
|
||||
|
|
|
@ -17,5 +17,13 @@ define [
|
|||
privileges: privileges
|
||||
_csrf: window.csrfToken
|
||||
})
|
||||
|
||||
getMembers: () ->
|
||||
$http.get("/project/#{ide.project_id}/members", {
|
||||
json: true
|
||||
headers:
|
||||
"X-Csrf-Token": window.csrfToken
|
||||
})
|
||||
|
||||
}
|
||||
]
|
||||
|
|
|
@ -18,6 +18,7 @@ describe "CollaboratorsController", ->
|
|||
'../Subscription/LimitationsManager' : @LimitationsManager = {}
|
||||
'../Project/ProjectEditorHandler' : @ProjectEditorHandler = {}
|
||||
'../User/UserGetter': @UserGetter = {}
|
||||
'logger-sharelatex': @logger = {err: sinon.stub(), erro: sinon.stub(), log: sinon.stub()}
|
||||
@res = new MockResponse()
|
||||
@req = new MockRequest()
|
||||
|
||||
|
@ -150,3 +151,37 @@ describe "CollaboratorsController", ->
|
|||
it "should return a success code", ->
|
||||
@res.sendStatus.calledWith(204).should.equal true
|
||||
|
||||
describe 'getAllMembers', ->
|
||||
beforeEach ->
|
||||
@req.session =
|
||||
user: _id: @user_id = "user-id-123"
|
||||
@req.params = Project_id: @project_id
|
||||
@res.json = sinon.stub()
|
||||
@next = sinon.stub()
|
||||
@members = [{a: 1}]
|
||||
@CollaboratorsHandler.getAllMembers = sinon.stub().callsArgWith(1, null, @members)
|
||||
@CollaboratorsController.getAllMembers(@req, @res, @next)
|
||||
|
||||
it 'should not produce an error', ->
|
||||
@next.callCount.should.equal 0
|
||||
|
||||
it 'should produce a json response', ->
|
||||
@res.json.callCount.should.equal 1
|
||||
@res.json.calledWith({members: @members}).should.equal true
|
||||
|
||||
it 'should call CollaboratorsHandler.getAllMembers', ->
|
||||
@CollaboratorsHandler.getAllMembers.callCount.should.equal 1
|
||||
|
||||
describe 'when CollaboratorsHandler.getAllMembers produces an error', ->
|
||||
beforeEach ->
|
||||
@res.json = sinon.stub()
|
||||
@next = sinon.stub()
|
||||
@CollaboratorsHandler.getAllMembers = sinon.stub().callsArgWith(1, new Error('woops'))
|
||||
@CollaboratorsController.getAllMembers(@req, @res, @next)
|
||||
|
||||
it 'should produce an error', ->
|
||||
@next.callCount.should.equal 1
|
||||
@next.firstCall.args[0].should.be.instanceof Error
|
||||
|
||||
it 'should not produce a json response', ->
|
||||
@res.json.callCount.should.equal 0
|
||||
|
|
|
@ -18,6 +18,7 @@ describe "CollaboratorsHandler", ->
|
|||
"../Project/ProjectEntityHandler": @ProjectEntityHandler = {}
|
||||
"./CollaboratorsEmailHandler": @CollaboratorsEmailHandler = {}
|
||||
"../Errors/Errors": Errors
|
||||
"../Project/ProjectEditorHandler": @ProjectEditorHandler = {}
|
||||
|
||||
@project_id = "mock-project-id"
|
||||
@user_id = "mock-user-id"
|
||||
|
@ -292,3 +293,61 @@ describe "CollaboratorsHandler", ->
|
|||
@CollaboratorHandler.removeUserFromProject
|
||||
.calledWith(project_id, @user_id)
|
||||
.should.equal true
|
||||
|
||||
describe 'getAllMembers', ->
|
||||
|
||||
beforeEach ->
|
||||
@owning_user = {_id: 'owner-id', email: 'owner@example.com', features: {a: 1}}
|
||||
@readwrite_user = {_id: 'readwrite-id', email: 'readwrite@example.com'}
|
||||
@members = [
|
||||
{user: @owning_user, privilegeLevel: "owner"},
|
||||
{user: @readwrite_user, privilegeLevel: "readAndWrite"}
|
||||
]
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels = sinon.stub().callsArgWith(1, null, @members)
|
||||
@ProjectEditorHandler.buildOwnerAndMembersViews = sinon.stub().returns(@views = {
|
||||
owner: @owning_user,
|
||||
ownerFeatures: @owning_user.features,
|
||||
members: [ {_id: @readwrite_user._id, email: @readwrite_user.email} ]
|
||||
})
|
||||
@callback = sinon.stub()
|
||||
@CollaboratorHandler.getAllMembers @project_id, @callback
|
||||
|
||||
it 'should not produce an error', ->
|
||||
@callback.callCount.should.equal 1
|
||||
expect(@callback.firstCall.args[0]).to.equal null
|
||||
|
||||
it 'should produce a list of members', ->
|
||||
@callback.callCount.should.equal 1
|
||||
expect(@callback.firstCall.args[1]).to.deep.equal @views.members
|
||||
|
||||
it 'should call getMembersWithPrivileges', ->
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels.callCount.should.equal 1
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels.firstCall.args[0].should.equal @project_id
|
||||
|
||||
it 'should call ProjectEditorHandler.buildOwnerAndMembersViews', ->
|
||||
@ProjectEditorHandler.buildOwnerAndMembersViews.callCount.should.equal 1
|
||||
@ProjectEditorHandler.buildOwnerAndMembersViews.firstCall.args[0].should.equal @members
|
||||
|
||||
describe 'when getMembersWithPrivileges produces an error', ->
|
||||
|
||||
beforeEach ->
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels = sinon.stub().callsArgWith(1, new Error('woops'))
|
||||
@ProjectEditorHandler.buildOwnerAndMembersViews = sinon.stub().returns(@views = {
|
||||
owner: @owning_user,
|
||||
ownerFeatures: @owning_user.features,
|
||||
members: [ {_id: @readwrite_user._id, email: @readwrite_user.email} ]
|
||||
})
|
||||
@callback = sinon.stub()
|
||||
@CollaboratorHandler.getAllMembers @project_id, @callback
|
||||
|
||||
it 'should produce an error', ->
|
||||
@callback.callCount.should.equal 1
|
||||
expect(@callback.firstCall.args[0]).to.not.equal null
|
||||
expect(@callback.firstCall.args[0]).to.be.instanceof Error
|
||||
|
||||
it 'should call getMembersWithPrivileges', ->
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels.callCount.should.equal 1
|
||||
@CollaboratorHandler.getMembersWithPrivilegeLevels.firstCall.args[0].should.equal @project_id
|
||||
|
||||
it 'should not call ProjectEditorHandler.buildOwnerAndMembersViews', ->
|
||||
@ProjectEditorHandler.buildOwnerAndMembersViews.callCount.should.equal 0
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
chai = require('chai')
|
||||
expect = chai.expect
|
||||
should = chai.should()
|
||||
|
||||
modulePath = "../../../../app/js/Features/Project/ProjectEditorHandler"
|
||||
|
@ -183,3 +184,39 @@ describe "ProjectEditorHandler", ->
|
|||
@result.features.compileGroup.should.equal @owner.features.compileGroup
|
||||
@result.features.compileTimeout.should.equal @owner.features.compileTimeout
|
||||
|
||||
describe 'buildOwnerAndMembersViews', ->
|
||||
beforeEach ->
|
||||
@owner.features =
|
||||
versioning: true
|
||||
collaborators: 3
|
||||
compileGroup:"priority"
|
||||
compileTimeout: 22
|
||||
@result = @handler.buildOwnerAndMembersViews @members
|
||||
|
||||
it 'should produce an object with owner, ownerFeatures and members keys', ->
|
||||
expect(@result).to.have.all.keys ['owner', 'ownerFeatures', 'members']
|
||||
|
||||
it 'should separate the owner from the members', ->
|
||||
@result.members.length.should.equal(@members.length-1)
|
||||
expect(@result.owner._id).to.equal @owner._id
|
||||
expect(@result.owner.email).to.equal @owner.email
|
||||
expect(@result.members.filter((m) => m._id == @owner._id).length).to.equal 0
|
||||
|
||||
it 'should extract the ownerFeatures from the owner object', ->
|
||||
expect(@result.ownerFeatures).to.deep.equal @owner.features
|
||||
|
||||
describe 'when there is no owner', ->
|
||||
beforeEach ->
|
||||
# remove the owner from members list
|
||||
@membersWithoutOwner = @members.filter((m) => m.user._id != @owner._id)
|
||||
@result = @handler.buildOwnerAndMembersViews @membersWithoutOwner
|
||||
|
||||
it 'should produce an object with owner, ownerFeatures and members keys', ->
|
||||
expect(@result).to.have.all.keys ['owner', 'ownerFeatures', 'members']
|
||||
|
||||
it 'should not separate out an owner', ->
|
||||
@result.members.length.should.equal @membersWithoutOwner.length
|
||||
expect(@result.owner).to.equal null
|
||||
|
||||
it 'should not extract the ownerFeatures from the owner object', ->
|
||||
expect(@result.ownerFeatures).to.equal null
|
||||
|
|
Loading…
Reference in a new issue