Merge pull request #2105 from overleaf/ta-user-membership-refactor
UserMembershipAuthorization Refactor GitOrigin-RevId: 7711cda4a134823cbacee42731319fbb8aa648d0
This commit is contained in:
committed by
sharelatex
parent
44d3b8b92e
commit
a23ecc9bf8
@@ -1,339 +0,0 @@
|
||||
/* eslint-disable
|
||||
handle-callback-err,
|
||||
max-len,
|
||||
no-return-assign,
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
const sinon = require('sinon')
|
||||
const chai = require('chai')
|
||||
const { expect } = require('chai')
|
||||
const modulePath =
|
||||
'../../../../app/src/Features/UserMembership/UserMembershipAuthorization.js'
|
||||
const SandboxedModule = require('sandboxed-module')
|
||||
const MockRequest = require('../helpers/MockRequest')
|
||||
const EntityConfigs = require('../../../../app/src/Features/UserMembership/UserMembershipEntityConfigs')
|
||||
const Errors = require('../../../../app/src/Features/Errors/Errors')
|
||||
|
||||
describe('UserMembershipAuthorization', function() {
|
||||
beforeEach(function() {
|
||||
this.req = new MockRequest()
|
||||
this.req.params.id = 'mock-entity-id'
|
||||
this.user = { _id: 'mock-user-id' }
|
||||
this.subscription = { _id: 'mock-subscription-id' }
|
||||
|
||||
this.AuthenticationController = {
|
||||
getSessionUser: sinon.stub().returns(this.user)
|
||||
}
|
||||
this.UserMembershipHandler = {
|
||||
getEntity: sinon.stub().yields(null, this.subscription),
|
||||
getEntityWithoutAuthorizationCheck: sinon
|
||||
.stub()
|
||||
.yields(null, this.subscription)
|
||||
}
|
||||
this.AuthorizationMiddleware = {
|
||||
redirectToRestricted: sinon.stub().yields(),
|
||||
ensureUserIsSiteAdmin: sinon.stub().yields()
|
||||
}
|
||||
return (this.UserMembershipAuthorization = SandboxedModule.require(
|
||||
modulePath,
|
||||
{
|
||||
globals: {
|
||||
console: console
|
||||
},
|
||||
requires: {
|
||||
'../Authentication/AuthenticationController': this
|
||||
.AuthenticationController,
|
||||
'../Authorization/AuthorizationMiddleware': this
|
||||
.AuthorizationMiddleware,
|
||||
'./UserMembershipHandler': this.UserMembershipHandler,
|
||||
'./EntityConfigs': EntityConfigs,
|
||||
'../Errors/Errors': Errors,
|
||||
request: (this.request = sinon.stub().yields(null, null, {})),
|
||||
'logger-sharelatex': {
|
||||
log() {},
|
||||
warn() {},
|
||||
err() {}
|
||||
}
|
||||
}
|
||||
}
|
||||
))
|
||||
})
|
||||
|
||||
describe('requireAccessToEntity', function() {
|
||||
it('get entity', function(done) {
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.params.id,
|
||||
{ modelName: 'Subscription' },
|
||||
this.user
|
||||
)
|
||||
expect(this.req.entity).to.equal(this.subscription)
|
||||
expect(this.req.entityConfig).to.exist
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle entity not found as non-admin', function(done) {
|
||||
this.UserMembershipHandler.getEntity.yields(null, null)
|
||||
this.UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(
|
||||
null,
|
||||
null
|
||||
)
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.exist
|
||||
expect(error).to.be.instanceof(Error)
|
||||
expect(error.constructor.name).to.equal('NotFoundError')
|
||||
sinon.assert.called(this.UserMembershipHandler.getEntity)
|
||||
expect(this.req.entity).to.not.exist
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle entity not found an admin can create', function(done) {
|
||||
this.user.isAdmin = true
|
||||
this.UserMembershipHandler.getEntity.yields(null, null)
|
||||
this.UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(
|
||||
null,
|
||||
null
|
||||
)
|
||||
return this.UserMembershipAuthorization.requirePublisherMetricsAccess(
|
||||
this.req,
|
||||
{
|
||||
redirect: path => {
|
||||
expect(path).to.exist
|
||||
expect(path).to.match(/create/)
|
||||
return done()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle entity not found a non-admin can create', function(done) {
|
||||
this.user.staffAccess = { institutionManagement: true }
|
||||
this.UserMembershipHandler.getEntity.yields(null, null)
|
||||
this.UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(
|
||||
null,
|
||||
null
|
||||
)
|
||||
return this.UserMembershipAuthorization.requirePublisherMetricsAccess(
|
||||
this.req,
|
||||
{
|
||||
redirect: path => {
|
||||
expect(path).to.exist
|
||||
expect(path).to.match(/create/)
|
||||
return done()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle entity not found an admin cannot create', function(done) {
|
||||
this.user.isAdmin = true
|
||||
this.UserMembershipHandler.getEntity.yields(null, null)
|
||||
this.UserMembershipHandler.getEntityWithoutAuthorizationCheck.yields(
|
||||
null,
|
||||
null
|
||||
)
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.exist
|
||||
expect(error).to.be.instanceof(Error)
|
||||
expect(error.constructor.name).to.equal('NotFoundError')
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle entity no access', function(done) {
|
||||
this.UserMembershipHandler.getEntity.yields(null, null)
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
sinon.assert.called(this.AuthorizationMiddleware.redirectToRestricted)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle anonymous user', function(done) {
|
||||
this.AuthenticationController.getSessionUser.returns(null)
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.called(this.AuthorizationMiddleware.redirectToRestricted)
|
||||
sinon.assert.notCalled(this.UserMembershipHandler.getEntity)
|
||||
expect(this.req.entity).to.not.exist
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('checks user is staff if required', function(done) {
|
||||
return this.UserMembershipAuthorization.requireInstitutionManagementStaffAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.called(this.AuthorizationMiddleware.redirectToRestricted)
|
||||
sinon.assert.notCalled(this.UserMembershipHandler.getEntity)
|
||||
expect(this.req.entity).to.not.exist
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('requireEntityAccess', function() {
|
||||
it('handle team access', function(done) {
|
||||
return this.UserMembershipAuthorization.requireTeamMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.params.id,
|
||||
{ fields: { primaryKey: 'overleaf.id' } }
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle group access', function(done) {
|
||||
return this.UserMembershipAuthorization.requireGroupMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.params.id,
|
||||
{ translations: { title: 'group_account' } }
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle group managers access', function(done) {
|
||||
return this.UserMembershipAuthorization.requireGroupManagersManagementAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.params.id,
|
||||
{ translations: { subtitle: 'managers_management' } }
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle institution access', function(done) {
|
||||
return this.UserMembershipAuthorization.requireInstitutionMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.params.id,
|
||||
{ modelName: 'Institution' }
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle template with brand access', function(done) {
|
||||
const templateData = {
|
||||
id: 123,
|
||||
title: 'Template Title',
|
||||
brand: { slug: 'brand-slug' }
|
||||
}
|
||||
this.request.yields(
|
||||
null,
|
||||
{ statusCode: 200 },
|
||||
JSON.stringify(templateData)
|
||||
)
|
||||
return this.UserMembershipAuthorization.requireTemplateMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
'brand-slug',
|
||||
{ modelName: 'Publisher' }
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle template without brand access', function(done) {
|
||||
const templateData = {
|
||||
id: 123,
|
||||
title: 'Template Title',
|
||||
brand: null
|
||||
}
|
||||
this.request.yields(
|
||||
null,
|
||||
{ statusCode: 200 },
|
||||
JSON.stringify(templateData)
|
||||
)
|
||||
return this.UserMembershipAuthorization.requireTemplateMetricsAccess(
|
||||
this.req,
|
||||
null,
|
||||
error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.notCalled(this.UserMembershipHandler.getEntity)
|
||||
sinon.assert.calledOnce(
|
||||
this.AuthorizationMiddleware.ensureUserIsSiteAdmin
|
||||
)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle graph access', function(done) {
|
||||
this.req.query.resource_id = 'mock-resource-id'
|
||||
this.req.query.resource_type = 'institution'
|
||||
const middleware = this.UserMembershipAuthorization.requireGraphAccess
|
||||
return middleware(this.req, null, error => {
|
||||
expect(error).to.not.exist
|
||||
sinon.assert.calledWithMatch(
|
||||
this.UserMembershipHandler.getEntity,
|
||||
this.req.query.resource_id,
|
||||
{ modelName: 'Institution' }
|
||||
)
|
||||
return done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -336,6 +336,7 @@ describe('UserMembershipController', function() {
|
||||
describe('create', function() {
|
||||
beforeEach(function() {
|
||||
this.req.params.name = 'institution'
|
||||
this.req.entityConfig = EntityConfigs['institution']
|
||||
return (this.req.params.id = 123)
|
||||
})
|
||||
|
||||
@@ -352,15 +353,5 @@ describe('UserMembershipController', function() {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('checks canCreate', function(done) {
|
||||
this.req.params.name = 'group'
|
||||
return this.UserMembershipController.create(this.req, null, error => {
|
||||
expect(error).to.extist
|
||||
expect(error).to.be.an.instanceof(Errors.NotFoundError)
|
||||
sinon.assert.notCalled(this.UserMembershipHandler.createEntity)
|
||||
return done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -92,81 +92,6 @@ describe('UserMembershipHandler', function() {
|
||||
}))
|
||||
})
|
||||
|
||||
describe('getEntity', function() {
|
||||
describe('group subscriptions', function() {
|
||||
it('get subscription', function(done) {
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.fakeEntityId,
|
||||
EntityConfigs.group,
|
||||
this.user,
|
||||
null,
|
||||
(error, subscription) => {
|
||||
should.not.exist(error)
|
||||
const expectedQuery = {
|
||||
groupPlan: true,
|
||||
_id: this.fakeEntityId,
|
||||
manager_ids: ObjectId(this.user._id)
|
||||
}
|
||||
assertCalledWith(this.Subscription.findOne, expectedQuery)
|
||||
expect(subscription).to.equal(this.subscription)
|
||||
expect(subscription.membersLimit).to.equal(10)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('get for admin', function(done) {
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.fakeEntityId,
|
||||
EntityConfigs.group,
|
||||
{ isAdmin: true },
|
||||
null,
|
||||
(error, subscription) => {
|
||||
should.not.exist(error)
|
||||
const expectedQuery = {
|
||||
groupPlan: true,
|
||||
_id: this.fakeEntityId
|
||||
}
|
||||
assertCalledWith(this.Subscription.findOne, expectedQuery)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('get with staffAccess field', function(done) {
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.fakeEntityId,
|
||||
EntityConfigs.group,
|
||||
{ staffAccess: { institutionMetrics: true } },
|
||||
'institutionMetrics',
|
||||
(error, subscription) => {
|
||||
should.not.exist(error)
|
||||
const expectedQuery = {
|
||||
groupPlan: true,
|
||||
_id: this.fakeEntityId
|
||||
}
|
||||
assertCalledWith(this.Subscription.findOne, expectedQuery)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle error', function(done) {
|
||||
this.Subscription.findOne.yields(new Error('some error'))
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.fakeEntityId,
|
||||
EntityConfigs.group,
|
||||
this.user._id,
|
||||
null,
|
||||
(error, subscription) => {
|
||||
should.exist(error)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getEntityWithoutAuthorizationCheck', function() {
|
||||
it('get publisher', function(done) {
|
||||
return this.UserMembershipHandler.getEntityWithoutAuthorizationCheck(
|
||||
@@ -181,63 +106,6 @@ describe('UserMembershipHandler', function() {
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('institutions', function() {
|
||||
it('get institution', function(done) {
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.institution.v1Id,
|
||||
EntityConfigs.institution,
|
||||
this.user,
|
||||
null,
|
||||
(error, institution) => {
|
||||
should.not.exist(error)
|
||||
const expectedQuery = {
|
||||
v1Id: this.institution.v1Id,
|
||||
managerIds: ObjectId(this.user._id)
|
||||
}
|
||||
assertCalledWith(this.Institution.findOne, expectedQuery)
|
||||
expect(institution).to.equal(this.institution)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('handle errors', function(done) {
|
||||
this.Institution.findOne.yields(new Error('nope'))
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.fakeEntityId,
|
||||
EntityConfigs.institution,
|
||||
this.user._id,
|
||||
null,
|
||||
(error, institution) => {
|
||||
should.exist(error)
|
||||
expect(error).to.not.be.an.instanceof(Errors.NotFoundError)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('publishers', function() {
|
||||
it('get publisher', function(done) {
|
||||
return this.UserMembershipHandler.getEntity(
|
||||
this.publisher.slug,
|
||||
EntityConfigs.publisher,
|
||||
this.user,
|
||||
null,
|
||||
(error, institution) => {
|
||||
should.not.exist(error)
|
||||
const expectedQuery = {
|
||||
slug: this.publisher.slug,
|
||||
managerIds: ObjectId(this.user._id)
|
||||
}
|
||||
assertCalledWith(this.Publisher.findOne, expectedQuery)
|
||||
expect(institution).to.equal(this.publisher)
|
||||
return done()
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getUsers', function() {
|
||||
|
||||
Reference in New Issue
Block a user