diff --git a/api-docs/openapi.json b/api-docs/openapi.json index 1a7ebad46..34fb3cedf 100644 --- a/api-docs/openapi.json +++ b/api-docs/openapi.json @@ -2099,7 +2099,7 @@ "Organization" ], "summary": "Updates information about the organization specified by short name (accessible to Secretariat)", - "description": "
User must belong to an organization with the Secretariat role
Secretariat: Updates any organization's information
", + "description": "User must belong to an organization with the Secretariat role, or user must belong to the organization specified by short name
Secretariat: Updates any organization's information
Non-secretariat: Updates 'last_active' timestamp to show that an org is still active
", "operationId": "orgUpdateSingle", "parameters": [ { @@ -2142,7 +2142,14 @@ "content": { "application/json": { "schema": { - "$ref": "../schemas/org/update-org-response.json" + "oneOf": [ + { + "$ref": "../schemas/org/update-org-response.json" + }, + { + "$ref": "../schemas/org/am-i-alive-response.json" + } + ] } } } diff --git a/schemas/org/am-i-alive-response.json b/schemas/org/am-i-alive-response.json new file mode 100644 index 000000000..b9b3d55b0 --- /dev/null +++ b/schemas/org/am-i-alive-response.json @@ -0,0 +1,20 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success description" + }, + "updated": { + "type": "object", + "properties": { + "last_active": { + "type": "string", + "format": "date-time", + "description": "The time the organization was last active." + } + } + } + } + } \ No newline at end of file diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js index 15a160a62..2c9279835 100644 --- a/src/controller/org.controller/index.js +++ b/src/controller/org.controller/index.js @@ -245,9 +245,10 @@ router.put('/org/:shortname', #swagger.summary = "Updates information about the organization specified by short name (accessible to Secretariat)" #swagger.description = "User must belong to an organization with the Secretariat role
+User must belong to an organization with the Secretariat role, or user must belong to the organization specified by short name
Secretariat: Updates any organization's information
" +Secretariat: Updates any organization's information
+Non-secretariat: Updates 'last_active' timestamp to show that an org is still active
" #swagger.parameters['shortname'] = { description: 'The shortname of the organization' } #swagger.parameters['$ref'] = [ '#/components/parameters/id_quota', @@ -263,7 +264,12 @@ router.put('/org/:shortname', description: 'Returns information about the organization updated', content: { "application/json": { - schema: { $ref: '../schemas/org/update-org-response.json' } + schema: { + oneOf: [ + { $ref: '../schemas/org/update-org-response.json' }, + { $ref: '../schemas/org/am-i-alive-response.json' } + ] + } } } } @@ -309,10 +315,10 @@ router.put('/org/:shortname', } */ mw.validateUser, - mw.onlySecretariat, + param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), + mw.validateOrg, query().custom((query) => { return mw.validateQueryParameterNames(query, ['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']) }), query(['new_short_name', 'id_quota', 'name', 'active_roles.add', 'active_roles.remove']).custom((val) => { return mw.containsNoInvalidCharacters(val) }), - param(['shortname']).isString().trim().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), query(['new_short_name']).optional().isString().trim().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }), query(['id_quota']).optional().not().isArray().isInt({ min: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_min, max: CONSTANTS.MONGOOSE_VALIDATION.Org_policies_id_quota_max }).withMessage(errorMsgs.ID_QUOTA), query(['name']).optional().isString().trim().notEmpty(), diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js index d1a094b57..7803da44c 100644 --- a/src/controller/org.controller/org.controller.js +++ b/src/controller/org.controller/org.controller.js @@ -329,6 +329,7 @@ async function updateOrg (req, res, next) { const addRoles = [] const orgRepo = req.ctx.repositories.getOrgRepository() const org = await orgRepo.findOneByShortName(shortName) + const orgMakingChanges = req.ctx.org let agt = setAggregateOrgObj({ short_name: shortName }) // org doesn't exist @@ -337,30 +338,38 @@ async function updateOrg (req, res, next) { return res.status(404).json(error.orgDnePathParam(shortName)) } - Object.keys(req.ctx.query).forEach(k => { - const key = k.toLowerCase() - - if (key === 'new_short_name') { - newOrg.short_name = req.ctx.query.new_short_name - agt = setAggregateOrgObj({ short_name: newOrg.short_name }) - } else if (key === 'name') { - newOrg.name = req.ctx.query.name - } else if (key === 'id_quota') { - newOrg.policies.id_quota = req.ctx.query.id_quota - } else if (key === 'active_roles.add') { - if (Array.isArray(req.ctx.query['active_roles.add'])) { - req.ctx.query['active_roles.add'].forEach(r => { - addRoles.push(r) - }) - } - } else if (key === 'active_roles.remove') { - if (Array.isArray(req.ctx.query['active_roles.remove'])) { - req.ctx.query['active_roles.remove'].forEach(r => { - removeRoles.push(r) - }) + const isSec = await orgRepo.isSecretariat(orgMakingChanges) + + if (isSec) { + Object.keys(req.ctx.query).forEach(k => { + const key = k.toLowerCase() + + if (key === 'new_short_name') { + newOrg.short_name = req.ctx.query.new_short_name + agt = setAggregateOrgObj({ short_name: newOrg.short_name }) + } else if (key === 'name') { + newOrg.name = req.ctx.query.name + } else if (key === 'id_quota') { + newOrg.policies.id_quota = req.ctx.query.id_quota + } else if (key === 'active_roles.add') { + if (Array.isArray(req.ctx.query['active_roles.add'])) { + req.ctx.query['active_roles.add'].forEach(r => { + addRoles.push(r) + }) + } + } else if (key === 'active_roles.remove') { + if (Array.isArray(req.ctx.query['active_roles.remove'])) { + req.ctx.query['active_roles.remove'].forEach(r => { + removeRoles.push(r) + }) + } } - } - }) + }) + } + + if (shortName === orgMakingChanges) { + newOrg.last_active = Date.now() + } // updating the org's roles if (org) { @@ -403,6 +412,13 @@ async function updateOrg (req, res, next) { result = await orgRepo.aggregate(agt) result = result.length > 0 ? result[0] : null + if (!isSec) { + if (!result || !result.last_active) { + return res.status(500).json(error.serverError()) + } + result = { last_active: result.last_active } + } + const responseMessage = { message: shortName + ' organization was successfully updated.', updated: result @@ -819,7 +835,8 @@ function setAggregateOrgObj (query) { name: true, 'authority.active_roles': true, 'policies.id_quota': true, - time: true + time: true, + last_active: true } } ] diff --git a/src/middleware/middleware.js b/src/middleware/middleware.js index ed4972195..35e505103 100644 --- a/src/middleware/middleware.js +++ b/src/middleware/middleware.js @@ -135,6 +135,32 @@ async function validateUser (req, res, next) { } } +async function validateOrg (req, res, next) { + const org = req.ctx.org + const reqOrg = req.params.shortname + const orgRepo = req.ctx.repositories.getOrgRepository() + const CONSTANTS = getConstants() + + try { + logger.info({ uuid: req.ctx.uuid, message: 'Authenticating org: ' + org }) + + const isSec = await orgRepo.isSecretariat(org) + if (!isSec) { + if (org !== reqOrg) { + logger.info({ uuid: req.ctx.uuid, message: org + ' is not a ' + CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT + ' or the same as ' + reqOrg + ' and is not allowed to make these changes.' }) + return res.status(403).json(error.secretariatOnly()) + } else if (Object.keys(req.query).length > 0) { + return res.status(403).json(error.secretariatOnly()) + } + } + + logger.info({ uuid: req.ctx.uuid, message: 'Confirmed ' + org + ' has the authority to make changes to ' + reqOrg }) + next() + } catch (err) { + next(err) + } +} + // Checks that the requester belongs to an org that has the 'BULK_DOWNLOAD' role async function onlySecretariatOrBulkDownload (req, res, next) { const org = req.ctx.org @@ -483,6 +509,7 @@ module.exports = { setCacheControl, optionallyValidateUser, validateUser, + validateOrg, onlySecretariat, onlySecretariatOrBulkDownload, onlySecretariatOrAdmin, diff --git a/src/model/org.js b/src/model/org.js index 48f3b226c..2c0964dc1 100644 --- a/src/model/org.js +++ b/src/model/org.js @@ -24,7 +24,8 @@ const schema = { created: Date, modified: Date }, - inUse: Boolean + inUse: Boolean, + last_active: Date } const OrgSchema = new mongoose.Schema(schema, { collection: 'Org', timestamps: { createdAt: 'time.created', updatedAt: 'time.modified' } }) diff --git a/test/integration-tests/org/putOrgTest.js b/test/integration-tests/org/putOrgTest.js new file mode 100644 index 000000000..28c3a0625 --- /dev/null +++ b/test/integration-tests/org/putOrgTest.js @@ -0,0 +1,201 @@ +/* eslint-disable no-unused-expressions */ +const chai = require('chai') +chai.use(require('chai-http')) +const expect = chai.expect + +const constants = require('../constants.js') +const app = require('../../../src/index.js') + +const params = { name: 'Test Organization', id_quota: 100 } +const secretariatParams = { name: 'MITRE Corporation', id_quota: 100000 } +const cnaParams = { name: 'Adams, Nielsen and Hensley', id_quota: 1309 } + +describe('Testing org put endpoint', () => { + context('Positive Tests', () => { + it('Allows update made by a secretariat to itself', async () => { + await chai.request(app) + .put('/api/org/mitre') + .set({ ...constants.headers }) + .query(params) + .send() + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.name).to.equal(params.name) + expect(res.body.updated.policies.id_quota).to.equal(params.id_quota) + expect(err).to.be.undefined + }) + await chai.request(app) + .put('/api/org/mitre') + .set({ ...constants.headers }) + .query(secretariatParams) + .send() + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.name).to.equal(secretariatParams.name) + expect(res.body.updated.policies.id_quota).to.equal(secretariatParams.id_quota) + expect(err).to.be.undefined + }) + }) + it('Allows update made by a secretariat to another org', async () => { + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.headers }) + .query(params) + .send() + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.name).to.equal(params.name) + expect(res.body.updated.policies.id_quota).to.equal(params.id_quota) + expect(err).to.be.undefined + }) + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.headers }) + .query(cnaParams) + .send() + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.name).to.equal(cnaParams.name) + expect(res.body.updated.policies.id_quota).to.equal(cnaParams.id_quota) + expect(err).to.be.undefined + }) + }) + it('Update made by a secretariat to another org does NOT update last_active field', async () => { + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.headers }) + .query(params) + .send() + .then((res, err) => { + expect(res.body.updated.last_active).to.be.undefined + expect(res).to.have.status(200) + expect(err).to.be.undefined + }) + }) + it('Update made by a secretariat to itself DOES update last_active field', async () => { + const now = Date.now() + await chai.request(app) + .put('/api/org/mitre') + .set({ ...constants.headers }) + .query(params) + .send() + .then((res, err) => { + expect(res.body.updated.last_active).to.not.be.null + // Assert that that the last_active field was updated under 2 seconds ago + const lastActive = Date.parse(res.body.updated.last_active) + const diff = Math.abs(now - lastActive) + const withinTwoSeconds = diff < 2000 + expect(withinTwoSeconds).to.be.true + expect(res).to.have.status(200) + expect(err).to.be.undefined + }) + }) + it('Update made by non-secretariat org to itself ONLY updates last_active field', async () => { + const now = Date.now() + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.nonSecretariatUserHeaders }) + .send() + .then((res, err) => { + // Assert that that the last_active field was updated under 2 seconds ago + const lastActive = Date.parse(res.body.updated.last_active) + const diff = Math.abs(now - lastActive) + const withinTwoSeconds = diff < 2000 + expect(withinTwoSeconds).to.be.true + // Assert no other fields were changed + expect(res).to.have.status(200) + expect(res.body.updated.active_roles).to.be.undefined + expect(res.body.updated.name).to.be.undefined + expect(res.body.updated.policies).to.be.undefined + expect(err).to.be.undefined + }) + }) + it('Request body ignored in update made by non-secretariat org to itself', async () => { + const requestBody = { + key1: 'value1', + key2: 'value2', + key3: 'value3', + key4: 'value4', + key5: 'value5', + key6: 'value6', + key7: 'value7', + key8: 'value8' + } + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.nonSecretariatUserHeaders }) + .send(requestBody) + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.last_active).to.not.be.null + expect(res.body.updated.active_roles).to.be.undefined + expect(res.body.updated.name).to.be.undefined + expect(res.body.updated.policies).to.be.undefined + expect(err).to.be.undefined + }) + }) + it('Request body ignored in update made by secretariat to itself', async () => { + const requestBody = { + key1: 'value1', + key2: 'value2', + key3: 'value3', + key4: 'value4', + key5: 'value5', + key6: 'value6', + key7: 'value7', + key8: 'value8' + } + await chai.request(app) + .put('/api/org/mitre') + .set({ ...constants.headers }) + .query(params) + .send(requestBody) + .then((res, err) => { + expect(res).to.have.status(200) + expect(res.body.updated.last_active).to.not.be.null + expect(res.body.updated.name).to.equal(params.name) + expect(res.body.updated.policies.id_quota).to.equal(params.id_quota) + expect(err).to.be.undefined + }) + }) + }) + context('Negative Tests', () => { + it('Fails update made by a non-secretariat org to a different org', async () => { + await chai.request(app) + .put('/api/org/cause_8') + .set({ ...constants.nonSecretariatUserHeaders }) + .send() + .then((res, err) => { + expect(res).to.have.status(403) + expect(err).to.be.undefined + expect(res.body).to.haveOwnProperty('error') + expect(res.body.error).to.equal('SECRETARIAT_ONLY') + }) + }) + it('Fails update to fields made by a non-secretariat org to itself', async () => { + await chai.request(app) + .put('/api/org/win_5') + .set({ ...constants.nonSecretariatUserHeaders }) + .query(params) + .send() + .then((res, err) => { + expect(res).to.have.status(403) + expect(err).to.be.undefined + expect(res.body).to.haveOwnProperty('error') + expect(res.body.error).to.equal('SECRETARIAT_ONLY') + }) + }) + it('Fails update made by a non-secretariat org to a secretariat', async () => { + await chai.request(app) + .put('/api/org/mitre') + .set({ ...constants.nonSecretariatUserHeaders }) + .send() + .then((res, err) => { + expect(res).to.have.status(403) + expect(err).to.be.undefined + expect(res.body).to.haveOwnProperty('error') + expect(res.body.error).to.equal('SECRETARIAT_ONLY') + }) + }) + }) +}) diff --git a/test/unit-tests/middleware/validateOrgTest.js b/test/unit-tests/middleware/validateOrgTest.js new file mode 100644 index 000000000..af239880f --- /dev/null +++ b/test/unit-tests/middleware/validateOrgTest.js @@ -0,0 +1,172 @@ +/* eslint-disable no-unused-expressions */ +const chai = require('chai') +const sinon = require('sinon') +const { validateOrg } = require('../../../src/middleware/middleware.js') +const OrgRepository = require('../../../src/repositories/orgRepository.js') +const expect = chai.expect + +const secretariat = { + short_name: 'mitre', + name: 'MITRE Corporation', + authority: { + active_roles: [ + 'SECRETARIAT', + 'CNA' + ] + }, + policies: { + id_quota: 1248 + } +} + +const nonSecretariat = { + short_name: 'win_5', + name: 'test_org', + authority: { + active_roles: [ + 'CNA' + ] + }, + policies: { + id_quota: 200 + } +} + +const nonSecretariat2 = { + short_name: 'cause_8', + name: 'test_org2', + authority: { + active_roles: [ + 'CNA' + ] + }, + policies: { + id_quota: 888 + } +} + +describe('Testing the validateOrg function', () => { + let status, json, res, next, getOrgRepository, orgRepo + beforeEach(() => { + status = sinon.stub() + json = sinon.spy() + res = { json, status } + next = sinon.stub() + status.returns(res) + + orgRepo = new OrgRepository() + getOrgRepository = sinon.stub() + getOrgRepository.returns(orgRepo) + }) + context('Positive Tests', () => { + it('Secretariat can update itself', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(true) + + const req = { + ctx: { + org: secretariat.short_name, + repositories: { + getOrgRepository + } + }, + params: { + shortname: secretariat.short_name + }, + query: { + id_quota: 111 + } + } + await validateOrg(req, res, next) + + expect(next.calledOnce).to.be.true + expect(next.firstCall.args).to.be.empty + }) + it('Secretariat can update another org', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(true) + + const req = { + ctx: { + org: secretariat.short_name, + repositories: { + getOrgRepository + } + }, + params: { + shortname: nonSecretariat.short_name + }, + query: { + id_quota: 999 + } + } + await validateOrg(req, res, next) + + expect(next.calledOnce).to.be.true + expect(next.firstCall.args).to.be.empty + }) + it('Non-secretariat can update itself', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(true) + + const req = { + ctx: { + org: nonSecretariat.short_name, + repositories: { + getOrgRepository + } + }, + params: { + shortname: nonSecretariat.short_name + } + } + await validateOrg(req, res, next) + + expect(next.calledOnce).to.be.true + expect(next.firstCall.args).to.be.empty + }) + }) + context('Negative Tests', () => { + it('Non-secretariat cannot update its fields other than last_active', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(false) + + const req = { + ctx: { + org: nonSecretariat.short_name, + repositories: { + getOrgRepository + } + }, + params: { + shortname: nonSecretariat.short_name + }, + query: { + id_quota: 999 + } + } + await validateOrg(req, res, next) + + expect(status.calledWith(403)).to.be.true + expect(next.calledOnce).to.be.false + }) + it('Non-secretariat cannot update another org', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(false) + + const req = { + ctx: { + org: nonSecretariat.short_name, + repositories: { + getOrgRepository + } + }, + params: { + shortname: nonSecretariat2.short_name + }, + query: { + id_quota: 999 + } + } + await validateOrg(req, res, next) + + expect(status.calledWith(403)).to.be.true + expect(next.calledOnce).to.be.false + }) + }) +}) diff --git a/test/unit-tests/org/orgUpdateLastActiveTest.js b/test/unit-tests/org/orgUpdateLastActiveTest.js new file mode 100644 index 000000000..33fa5bc0c --- /dev/null +++ b/test/unit-tests/org/orgUpdateLastActiveTest.js @@ -0,0 +1,138 @@ +/* eslint-disable no-unused-expressions */ +const chai = require('chai') +const sinon = require('sinon') +const { ORG_UPDATE_SINGLE } = require('../../../src/controller/org.controller/org.controller.js') +const OrgRepository = require('../../../src/repositories/orgRepository.js') +const UserRepository = require('../../../src/repositories/userRepository.js') +const expect = chai.expect + +const secretariat = { + short_name: 'mitre', + name: 'MITRE Corporation', + authority: { + active_roles: [ + 'SECRETARIAT', + 'CNA' + ] + }, + policies: { + id_quota: 1248 + } +} + +const nonSecretariat = { + short_name: 'win_5', + name: 'test_org', + authority: { + active_roles: [ + 'CNA' + ] + }, + policies: { + id_quota: 200 + } +} + +describe('Testing the updateOrg function', () => { + let status, json, res, next, getOrgRepository, orgRepo, getUserRepository, + userRepo, updateOrg + beforeEach(() => { + status = sinon.stub() + json = sinon.spy() + res = { json, status } + next = sinon.spy() + status.returns(res) + + orgRepo = new OrgRepository() + getOrgRepository = sinon.stub() + getOrgRepository.returns(orgRepo) + + userRepo = new UserRepository() + getUserRepository = sinon.stub() + getUserRepository.returns(userRepo) + + updateOrg = sinon.stub(orgRepo, 'updateByOrgUUID').returns(true) + sinon.stub(orgRepo, 'getOrgUUID').returns(true) + sinon.stub(userRepo, 'getUserUUID').returns(true) + }) + context('Positive Tests', () => { + it('Secretariat updates itself', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(true) + sinon.stub(orgRepo, 'findOneByShortName').returns(secretariat) + sinon.stub(orgRepo, 'aggregate').returns([secretariat]) + + const req = { + ctx: { + org: secretariat.short_name, + repositories: { + getOrgRepository, + getUserRepository + }, + params: { + shortname: secretariat.short_name + }, + query: { + id_quota: 111 + } + } + } + await ORG_UPDATE_SINGLE(req, res, next) + + expect(status.args[0][0]).to.equal(200) + expect(updateOrg.args[0][1].policies.id_quota).to.equal(req.ctx.query.id_quota) + }) + it('Secretariat updates a different org', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(true) + sinon.stub(orgRepo, 'findOneByShortName').returns(nonSecretariat) + sinon.stub(orgRepo, 'aggregate').returns([nonSecretariat]) + + const req = { + ctx: { + org: secretariat.short_name, + repositories: { + getOrgRepository, + getUserRepository + }, + params: { + shortname: nonSecretariat.short_name + }, + query: { + id_quota: 999 + } + } + } + await ORG_UPDATE_SINGLE(req, res, next) + + expect(status.args[0][0]).to.equal(200) + expect(updateOrg.args[0][1].policies.id_quota).to.equal(req.ctx.query.id_quota) + }) + it('Non-secretariat no params only updates last_active field', async () => { + sinon.stub(orgRepo, 'isSecretariat').returns(false) + sinon.stub(orgRepo, 'findOneByShortName').returns(nonSecretariat) + const nonSecretariatAgt = nonSecretariat + nonSecretariatAgt.last_active = Date.now() + sinon.stub(orgRepo, 'aggregate').returns([nonSecretariatAgt]) + + const req = { + ctx: { + org: nonSecretariat.short_name, + repositories: { + getOrgRepository, + getUserRepository + }, + params: { + shortname: nonSecretariat.short_name + } + } + } + await ORG_UPDATE_SINGLE(req, res, next) + + expect(status.args[0][0]).to.equal(200) + const now = Date.now() + const lastActive = updateOrg.args[0][1].last_active + const diff = Math.abs(now - lastActive) + const withinHalfASecond = diff < 500 + expect(withinHalfASecond).to.be.true + }) + }) +}) diff --git a/test/unit-tests/org/orgUpdateTest.js b/test/unit-tests/org/orgUpdateTest.js index f978d6f96..4e5f00b76 100644 --- a/test/unit-tests/org/orgUpdateTest.js +++ b/test/unit-tests/org/orgUpdateTest.js @@ -48,6 +48,10 @@ class OrgUpdatedAddingRole { async getOrgUUID () { return null } + + async isSecretariat () { + return true + } } class OrgUpdatedRemovingRole { @@ -66,6 +70,10 @@ class OrgUpdatedRemovingRole { async getOrgUUID () { return null } + + async isSecretariat () { + return true + } } describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { @@ -102,6 +110,10 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { async findOneByShortName () { return orgFixtures.existentOrg } + + async isSecretariat () { + return true + } } app.route('/org-not-updated-shortname-exists/:shortname') @@ -288,6 +300,10 @@ describe('Testing the PUT /org/:shortname endpoint in Org Controller', () => { async aggregate () { return [orgFixtures.existentOrg] } + + async isSecretariat () { + return true + } } app.route('/org-not-updated-no-query-parameters/:shortname')