mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-05 09:00:07 +00:00
Merge pull request #1192 from sharelatex/ta-publisher-create
Add Interface to Create Publishers GitOrigin-RevId: 50af2d1c05821d20b1ec33e8f68a05d824e55c46
This commit is contained in:
parent
0097564754
commit
f3a10ac221
9 changed files with 165 additions and 14 deletions
|
@ -67,20 +67,33 @@ requireAccessToEntity = (entityName, entityId, req, res, next) ->
|
|||
unless loggedInUser
|
||||
return AuthorizationMiddlewear.redirectToRestricted req, res, next
|
||||
|
||||
getEntity entityName, entityId, loggedInUser, (error, entity, entityConfig) ->
|
||||
getEntity entityName, entityId, loggedInUser, (error, entity, entityConfig, entityExists) ->
|
||||
return next(error) if error?
|
||||
unless entity?
|
||||
|
||||
if entity?
|
||||
req.entity = entity
|
||||
req.entityConfig = entityConfig
|
||||
return next()
|
||||
|
||||
if entityExists # user doesn't have access to entity
|
||||
return AuthorizationMiddlewear.redirectToRestricted(req, res, next)
|
||||
|
||||
req.entity = entity
|
||||
req.entityConfig = entityConfig
|
||||
next()
|
||||
if loggedInUser.isAdmin and entityConfig.canCreate
|
||||
# entity doesn't exists, admin can create it
|
||||
return res.redirect "/entities/#{entityName}/create/#{entityId}"
|
||||
|
||||
getEntity = (entityName, entityId, userId, callback = (error, entity, entityConfig)->) ->
|
||||
next(new Errors.NotFoundError())
|
||||
|
||||
getEntity = (entityName, entityId, user, callback = (error, entity, entityConfig, entityExists)->) ->
|
||||
entityConfig = EntityConfigs[entityName]
|
||||
unless entityConfig
|
||||
return callback(new Errors.NotFoundError("No such entity: #{entityName}"))
|
||||
|
||||
UserMembershipHandler.getEntity entityId, entityConfig, userId, (error, entity)->
|
||||
UserMembershipHandler.getEntity entityId, entityConfig, user, (error, entity)->
|
||||
return callback(error) if error?
|
||||
callback(null, entity, entityConfig)
|
||||
return callback(null, entity, entityConfig, true) if entity?
|
||||
|
||||
# no access to entity. Check if entity exists
|
||||
UserMembershipHandler.getEntityWithoutAuthorizationCheck entityId, entityConfig, (error, entity)->
|
||||
return callback(error) if error?
|
||||
callback(null, null, entityConfig, entity?)
|
||||
|
|
|
@ -80,3 +80,21 @@ module.exports =
|
|||
)
|
||||
res.contentType('text/csv')
|
||||
res.send(csvOutput)
|
||||
|
||||
new: (req, res, next)->
|
||||
res.render "user_membership/new",
|
||||
entityName: req.params.name
|
||||
entityId: req.params.id
|
||||
|
||||
create: (req, res, next)->
|
||||
entityName = req.params.name
|
||||
entityId = req.params.id
|
||||
entityConfig = EntityConfigs[entityName]
|
||||
unless entityConfig
|
||||
return next(new Errors.NotFoundError("No such entity: #{entityName}"))
|
||||
unless entityConfig.canCreate
|
||||
return next(new Errors.NotFoundError("Cannot create new #{entityName}"))
|
||||
|
||||
UserMembershipHandler.createEntity entityId, entityConfig, (error, entity) ->
|
||||
return next(error) if error?
|
||||
res.redirect entityConfig.pathsFor(entityId).index
|
||||
|
|
|
@ -49,6 +49,7 @@ module.exports =
|
|||
|
||||
institution:
|
||||
modelName: 'Institution'
|
||||
canCreate: true
|
||||
fields:
|
||||
primaryKey: 'v1Id'
|
||||
read: ['managerIds']
|
||||
|
@ -60,11 +61,13 @@ module.exports =
|
|||
subtitle: 'managers_management'
|
||||
remove: 'remove_manager'
|
||||
pathsFor: (id) ->
|
||||
index: "/manage/institutions/#{id}/managers"
|
||||
addMember: "/manage/institutions/#{id}/managers"
|
||||
removeMember: "/manage/institutions/#{id}/managers"
|
||||
|
||||
publisher:
|
||||
modelName: 'Publisher'
|
||||
canCreate: true
|
||||
fields:
|
||||
primaryKey: 'slug'
|
||||
read: ['managerIds']
|
||||
|
@ -76,5 +79,6 @@ module.exports =
|
|||
subtitle: 'managers_management'
|
||||
remove: 'remove_manager'
|
||||
pathsFor: (id) ->
|
||||
index: "/manage/publishers/#{id}/managers"
|
||||
addMember: "/manage/publishers/#{id}/managers"
|
||||
removeMember: "/manage/publishers/#{id}/managers"
|
||||
|
|
|
@ -12,13 +12,19 @@ UserMembershipEntityConfigs = require "./UserMembershipEntityConfigs"
|
|||
|
||||
module.exports =
|
||||
getEntity: (entityId, entityConfig, loggedInUser, callback = (error, entity) ->) ->
|
||||
entityId = ObjectId(entityId) if ObjectId.isValid(entityId.toString())
|
||||
query = Object.assign({}, entityConfig.baseQuery)
|
||||
query[entityConfig.fields.primaryKey] = entityId
|
||||
query = buildEntityQuery(entityId, entityConfig)
|
||||
unless loggedInUser.isAdmin
|
||||
query[entityConfig.fields.access] = ObjectId(loggedInUser._id)
|
||||
EntityModels[entityConfig.modelName].findOne query, callback
|
||||
|
||||
getEntityWithoutAuthorizationCheck: (entityId, entityConfig, callback = (error, entity) ->) ->
|
||||
query = buildEntityQuery(entityId, entityConfig)
|
||||
EntityModels[entityConfig.modelName].findOne query, callback
|
||||
|
||||
createEntity: (entityId, entityConfig, callback = (error, entity) ->) ->
|
||||
data = buildEntityQuery(entityId, entityConfig)
|
||||
EntityModels[entityConfig.modelName].create data, callback
|
||||
|
||||
getUsers: (entity, entityConfig, callback = (error, users) ->) ->
|
||||
attributes = entityConfig.fields.read
|
||||
getPopulatedListOfMembers(entity, attributes, callback)
|
||||
|
@ -72,3 +78,9 @@ removeUserFromEntity = (entity, attribute, userId, callback = (error)->) ->
|
|||
fieldUpdate = {}
|
||||
fieldUpdate[attribute] = userId
|
||||
entity.update { $pull: fieldUpdate }, callback
|
||||
|
||||
buildEntityQuery = (entityId, entityConfig, loggedInUser) ->
|
||||
entityId = ObjectId(entityId) if ObjectId.isValid(entityId.toString())
|
||||
query = Object.assign({}, entityConfig.baseQuery)
|
||||
query[entityConfig.fields.primaryKey] = entityId
|
||||
query
|
||||
|
|
|
@ -2,6 +2,7 @@ UserMembershipAuthorization = require './UserMembershipAuthorization'
|
|||
UserMembershipController = require './UserMembershipController'
|
||||
SubscriptionGroupController = require '../Subscription/SubscriptionGroupController'
|
||||
TeamInvitesController = require '../Subscription/TeamInvitesController'
|
||||
AuthorizationMiddlewear = require('../Authorization/AuthorizationMiddlewear')
|
||||
|
||||
module.exports =
|
||||
apply: (webRouter) ->
|
||||
|
@ -54,3 +55,11 @@ module.exports =
|
|||
webRouter.delete "/manage/publishers/:id/managers/:userId",
|
||||
UserMembershipAuthorization.requirePublisherAccess,
|
||||
UserMembershipController.remove
|
||||
|
||||
# create new entitites
|
||||
webRouter.get "/entities/:name/create/:id",
|
||||
AuthorizationMiddlewear.ensureUserIsSiteAdmin,
|
||||
UserMembershipController.new
|
||||
webRouter.post "/entities/:name/create/:id",
|
||||
AuthorizationMiddlewear.ensureUserIsSiteAdmin,
|
||||
UserMembershipController.create
|
||||
|
|
15
services/web/app/views/user_membership/new.pug
Normal file
15
services/web/app/views/user_membership/new.pug
Normal file
|
@ -0,0 +1,15 @@
|
|||
extends ../layout
|
||||
|
||||
block content
|
||||
.content.content-alt
|
||||
.container
|
||||
.row
|
||||
.col-md-10.col-md-offset-1
|
||||
h3 #{entityName} "#{entityId}" does not exists in v2
|
||||
form(
|
||||
enctype='multipart/form-data',
|
||||
method='post',
|
||||
action=''
|
||||
)
|
||||
input(name="_csrf", type="hidden", value=csrfToken)
|
||||
button.btn.btn-primary.text-capitalize(type="submit") Create #{entityName} in v2
|
|
@ -18,6 +18,7 @@ describe "UserMembershipAuthorization", ->
|
|||
getSessionUser: sinon.stub().returns(@user)
|
||||
@UserMembershipHandler =
|
||||
getEntity: sinon.stub().yields(null, @subscription)
|
||||
getEntityWithoutAuthorizationCheck: sinon.stub().yields(null, @subscription)
|
||||
@AuthorizationMiddlewear =
|
||||
redirectToRestricted: sinon.stub().yields()
|
||||
@UserMembershipAuthorization = SandboxedModule.require modulePath, requires:
|
||||
|
@ -45,15 +46,42 @@ describe "UserMembershipAuthorization", ->
|
|||
expect(@req.entityConfig).to.exist
|
||||
done()
|
||||
|
||||
it 'handle entity not found', (done) ->
|
||||
it 'handle entity not found as non-admin', (done) ->
|
||||
@UserMembershipHandler.getEntity.yields(null, null)
|
||||
@UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(null, null)
|
||||
@UserMembershipAuthorization.requireGroupAccess @req, null, (error) =>
|
||||
expect(error).to.extist
|
||||
sinon.assert.called(@AuthorizationMiddlewear.redirectToRestricted)
|
||||
expect(error).to.be.instanceof(Error)
|
||||
expect(error.constructor.name).to.equal('NotFoundError')
|
||||
sinon.assert.called(@UserMembershipHandler.getEntity)
|
||||
expect(@req.entity).to.not.exist
|
||||
done()
|
||||
|
||||
it 'handle entity not found an admin can create', (done) ->
|
||||
@user.isAdmin = true
|
||||
@UserMembershipHandler.getEntity.yields(null, null)
|
||||
@UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(null, null)
|
||||
@UserMembershipAuthorization.requirePublisherAccess @req, redirect: (path) =>
|
||||
expect(path).to.extist
|
||||
expect(path).to.match /create/
|
||||
done()
|
||||
|
||||
it 'handle entity not found an admin cannot create', (done) ->
|
||||
@user.isAdmin = true
|
||||
@UserMembershipHandler.getEntity.yields(null, null)
|
||||
@UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(null, null)
|
||||
@UserMembershipAuthorization.requireGroupAccess @req, null, (error) =>
|
||||
expect(error).to.extist
|
||||
expect(error).to.be.instanceof(Error)
|
||||
expect(error.constructor.name).to.equal('NotFoundError')
|
||||
done()
|
||||
|
||||
it 'handle entity no access', (done) ->
|
||||
@UserMembershipHandler.getEntity.yields(null, null)
|
||||
@UserMembershipAuthorization.requireGroupAccess @req, null, (error) =>
|
||||
sinon.assert.called(@AuthorizationMiddlewear.redirectToRestricted)
|
||||
done()
|
||||
|
||||
it 'handle anonymous user', (done) ->
|
||||
@AuthenticationController.getSessionUser.returns(null)
|
||||
@UserMembershipAuthorization.requireGroupAccess @req, null, (error) =>
|
||||
|
|
|
@ -38,6 +38,7 @@ describe "UserMembershipController", ->
|
|||
getLoggedInUserId: sinon.stub().returns(@user._id)
|
||||
@UserMembershipHandler =
|
||||
getEntity: sinon.stub().yields(null, @subscription)
|
||||
createEntity: sinon.stub().yields(null, @institution)
|
||||
getUsers: sinon.stub().yields(null, @users)
|
||||
addUser: sinon.stub().yields(null, @newUser)
|
||||
removeUser: sinon.stub().yields(null)
|
||||
|
@ -204,3 +205,37 @@ describe "UserMembershipController", ->
|
|||
|
||||
it "should export the correct csv", ->
|
||||
assertCalledWith(@res.send, "mock-email-1@foo.com\nmock-email-2@foo.com\n")
|
||||
|
||||
describe 'new', ->
|
||||
beforeEach ->
|
||||
@req.params.name = 'publisher'
|
||||
@req.params.id = 'abc'
|
||||
|
||||
it 'renders view', (done) ->
|
||||
@UserMembershipController.new @req, render: (viewPath, data) =>
|
||||
expect(data.entityName).to.eq 'publisher'
|
||||
expect(data.entityId).to.eq 'abc'
|
||||
done()
|
||||
|
||||
describe 'create', ->
|
||||
beforeEach ->
|
||||
@req.params.name = 'institution'
|
||||
@req.params.id = 123
|
||||
|
||||
it 'creates institution', (done) ->
|
||||
@UserMembershipController.create @req, redirect: (path) =>
|
||||
expect(path).to.eq EntityConfigs['institution'].pathsFor(123).index
|
||||
sinon.assert.calledWithMatch(
|
||||
@UserMembershipHandler.createEntity,
|
||||
123,
|
||||
modelName: 'Institution',
|
||||
)
|
||||
done()
|
||||
|
||||
it 'checks canCreate', (done) ->
|
||||
@req.params.name = 'group'
|
||||
@UserMembershipController.create @req, null, (error) =>
|
||||
expect(error).to.extist
|
||||
expect(error).to.be.an.instanceof(Errors.NotFoundError)
|
||||
sinon.assert.notCalled(@UserMembershipHandler.createEntity)
|
||||
done()
|
||||
|
|
|
@ -46,6 +46,7 @@ describe 'UserMembershipHandler', ->
|
|||
findOne: sinon.stub().yields(null, @subscription)
|
||||
@Publisher =
|
||||
findOne: sinon.stub().yields(null, @publisher)
|
||||
create: sinon.stub().yields(null, @publisher)
|
||||
@UserMembershipHandler = SandboxedModule.require modulePath, requires:
|
||||
'./UserMembershipViewModel': @UserMembershipViewModel
|
||||
'../User/UserGetter': @UserGetter
|
||||
|
@ -57,7 +58,7 @@ describe 'UserMembershipHandler', ->
|
|||
log: ->
|
||||
err: ->
|
||||
|
||||
describe 'getEntty', ->
|
||||
describe 'getEntity', ->
|
||||
describe 'group subscriptions', ->
|
||||
it 'get subscription', (done) ->
|
||||
@UserMembershipHandler.getEntity @fakeEntityId, EntityConfigs.group, @user, (error, subscription) =>
|
||||
|
@ -86,6 +87,15 @@ describe 'UserMembershipHandler', ->
|
|||
should.exist(error)
|
||||
done()
|
||||
|
||||
describe 'getEntityWithoutAuthorizationCheck', ->
|
||||
it 'get publisher', (done) ->
|
||||
@UserMembershipHandler.getEntityWithoutAuthorizationCheck @fakeEntityId, EntityConfigs.publisher, (error, subscription) =>
|
||||
should.not.exist(error)
|
||||
expectedQuery = slug: @fakeEntityId
|
||||
assertCalledWith(@Publisher.findOne, expectedQuery)
|
||||
expect(subscription).to.equal @publisher
|
||||
done()
|
||||
|
||||
describe 'institutions', ->
|
||||
it 'get institution', (done) ->
|
||||
@UserMembershipHandler.getEntity @institution.v1Id, EntityConfigs.institution, @user, (error, institution) =>
|
||||
|
@ -136,6 +146,13 @@ describe 'UserMembershipHandler', ->
|
|||
expect(@UserMembershipViewModel.buildAsync.callCount).to.equal expectedCallcount
|
||||
done()
|
||||
|
||||
describe 'createEntity', ->
|
||||
it 'creates publisher', (done) ->
|
||||
@UserMembershipHandler.createEntity @fakeEntityId, EntityConfigs.publisher, (error, publisher) =>
|
||||
should.not.exist(error)
|
||||
assertCalledWith(@Publisher.create, slug: @fakeEntityId)
|
||||
done()
|
||||
|
||||
describe 'addUser', ->
|
||||
beforeEach ->
|
||||
@email = @newUser.email
|
||||
|
|
Loading…
Reference in a new issue