Repository: CVEProject/cve-services (js)

Issue:
unlimited storage consumption by an Admin of any organization
An Admin of any organization can create many users with very large values of name fields (such as first name), limited mainly only by the permitted request rate. For many organizations, limits such as 100 users, and 100 characters per name field, would not interfere with their operations. Absence of limits on the amount of user data is potentially problematic for performance/usability reasons, e.g., when the Secretariat wants to call
```
GET /org/{shortname}/users
````
but also because of https://aws.amazon.com/documentdb/pricing/

Pull request description:
Resolves #1018 - Character and User limits
Closes Issue #1018 

# Summary
This PR adds 100 character limits to the First name, Last Name, Middle Name, and Suffix fields on users. In addition it limits ORGs to only have up to 100 users. Requests that the ORG talks to the Secretariat if there ever is a need for more than 100 users. 

# Important Changes
`example_file.js`
- Cleaned code and added comments.
- Added method to handle adding items. 

# Testing

Steps to manually test updated functionality, if possible
- [ ] 1) Run the following command `npm run test:integration`


Patch:
diff --git a/src/constants/index.js b/src/constants/index.js
index 4675180b..eebae31b 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -92,6 +92,10 @@ function getConstants () {
     },
     MAX_SHORTNAME_LENGTH: 32,
     MIN_SHORTNAME_LENGTH: 2,
+    MAX_FIRSTNAME_LENGTH: 100,
+    MAX_LASTNAME_LENGTH: 100,
+    MAX_MIDDLENAME_LENGTH: 100,
+    MAX_SUFFIX_LENGTH: 100,
     CVE_ID_PATTERN: cveSchemaV5.definitions.cveId.pattern,
     // Ajv's pattern validation uses the "u" (unicode) flag:
     // https://ajv.js.org/json-schema.html#pattern
diff --git a/src/controller/org.controller/error.js b/src/controller/org.controller/error.js
index bb83e2c3..4c4df5fd 100644
--- a/src/controller/org.controller/error.js
+++ b/src/controller/org.controller/error.js
@@ -84,6 +84,13 @@ class OrgControllerError extends idrErr.IDRError {
     err.message = 'Please have another admin user from your organization change your role.'
     return err
   }
+
+  userLimitReached () {
+    const err = {}
+    err.error = 'NUMBER_OF_USERS_IN_ORG_LIMIT_REACHED'
+    err.message = 'The requested user can not be created and added to the organization because the organization has hit its limit of 100 users. Contact the Secretariat.'
+    return err
+  }
 }
 
 module.exports = {
diff --git a/src/controller/org.controller/index.js b/src/controller/org.controller/index.js
index b2b5c128..b1630aa9 100644
--- a/src/controller/org.controller/index.js
+++ b/src/controller/org.controller/index.js
@@ -550,10 +550,10 @@ router.post('/org/:shortname/user',
   body(['username']).isString().trim().escape().notEmpty().custom(isValidUsername),
   body(['org_uuid']).optional().isString().trim().escape(),
   body(['uuid']).optional().isString().trim().escape(),
-  body(['name.first']).optional().isString().trim().escape(),
-  body(['name.last']).optional().isString().trim().escape(),
-  body(['name.middle']).optional().isString().trim().escape(),
-  body(['name.suffix']).optional().isString().trim().escape(),
+  body(['name.first']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_FIRSTNAME_LENGTH }).withMessage(errorMsgs.FIRSTNAME_LENGTH),
+  body(['name.last']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_LASTNAME_LENGTH }).withMessage(errorMsgs.LASTNAME_LENGTH),
+  body(['name.middle']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_MIDDLENAME_LENGTH }).withMessage(errorMsgs.MIDDLENAME_LENGTH),
+  body(['name.suffix']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_SUFFIX_LENGTH }).withMessage(errorMsgs.SUFFIX_LENGTH),
   body(['authority.active_roles']).optional()
     .custom(mw.isFlatStringArray)
     .customSanitizer(toUpperCaseArray)
@@ -722,10 +722,10 @@ router.put('/org/:shortname/user/:username',
   query(['active']).optional().isBoolean({ loose: true }),
   query(['new_username']).optional().isString().trim().escape().notEmpty().custom(isValidUsername),
   query(['org_short_name']).optional().isString().trim().escape().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
-  query(['name.first']).optional().isString().trim().escape(),
-  query(['name.last']).optional().isString().trim().escape(),
-  query(['name.middle']).optional().isString().trim().escape(),
-  query(['name.suffix']).optional().isString().trim().escape(),
+  body(['name.first']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_FIRSTNAME_LENGTH }).withMessage(errorMsgs.FIRSTNAME_LENGTH),
+  body(['name.last']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_LASTNAME_LENGTH }).withMessage(errorMsgs.LASTNAME_LENGTH),
+  body(['name.middle']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_MIDDLENAME_LENGTH }).withMessage(errorMsgs.MIDDLENAME_LENGTH),
+  body(['name.suffix']).optional().isString().trim().escape().isLength({ max: CONSTANTS.MAX_SUFFIX_LENGTH }).withMessage(errorMsgs.SUFFIX_LENGTH),
   query(['active_roles.add']).optional().toArray()
     .custom(isFlatStringArray)
     .customSanitizer(toUpperCaseArray)
diff --git a/src/controller/org.controller/org.controller.js b/src/controller/org.controller/org.controller.js
index bf0ae657..62e38fe3 100644
--- a/src/controller/org.controller/org.controller.js
+++ b/src/controller/org.controller/org.controller.js
@@ -445,6 +445,12 @@ async function createUser (req, res, next) {
       return res.status(404).json(error.orgDnePathParam(orgShortName))
     }
 
+    const users = await userRepo.findUsersByOrgUUID(orgUUID)
+
+    if (users >= 100) {
+      return res.status(400).json(error.userLimitReached())
+    }
+
     Object.keys(req.ctx.body).forEach(k => {
       const key = k.toLowerCase()
 
diff --git a/src/middleware/errorMessages.js b/src/middleware/errorMessages.js
index 327850cf..6f6a1b91 100644
--- a/src/middleware/errorMessages.js
+++ b/src/middleware/errorMessages.js
@@ -9,5 +9,9 @@ module.exports = {
   CVE_FILTERED_STATES: 'Invalid record state. Valid states are: PUBLISHED, REJECTED',
   COUNT_ONLY: 'Invalid count_only value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false',
   TIMESTAMP_FORMAT: "Bad date, or invalid timestamp format: valid format is yyyy-MM-ddTHH:mm:ss or yyyy-MM-ddTHH:mm:ssZZZZ (to use '+' in timezone offset, encode as '%2B)",
-  CNA_MODIFIED: 'Invalid cna_modified value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false'
+  CNA_MODIFIED: 'Invalid cna_modified value. Value should be 1, true, or yes to indicate true, or 0, false, or no to indicate false',
+  FIRSTNAME_LENGTH: 'Invalid name.first. Name must be between 1 and 100 characters in length.',
+  LASTNAME_LENGTH: 'Invalid name.last. Name must be between 1 and 100 characters in length.',
+  MIDDLENAME_LENGTH: 'Invalid name.middle. Name must be between 1 and 100 characters in length.',
+  SUFFIX_LENGTH: 'Invalid name.suffix. Name must be between 1 and 100 characters in length.'
 }
diff --git a/src/model/user.js b/src/model/user.js
index b34f6b60..e536c07d 100644
--- a/src/model/user.js
+++ b/src/model/user.js
@@ -33,6 +33,10 @@ UserSchema.query.byUUID = function (uuid) {
   return this.where({ UUID: uuid })
 }
 
+UserSchema.query.byOrgUUID = function (orgUUID) {
+  return this.where({ org_UUID: orgUUID })
+}
+
 UserSchema.query.byUserNameAndOrgUUID = function (username, orgUUID) {
   return this.where({ username: username, org_UUID: orgUUID })
 }
diff --git a/src/repositories/userRepository.js b/src/repositories/userRepository.js
index 26204d9d..4aa255a4 100644
--- a/src/repositories/userRepository.js
+++ b/src/repositories/userRepository.js
@@ -23,6 +23,10 @@ class UserRepository extends BaseRepository {
     return this.collection.findOne().byUUID(UUID)
   }
 
+  async findUsersByOrgUUID (orgUUID) {
+    return this.collection.find().byOrgUUID(orgUUID).countDocuments().exec()
+  }
+
   async findOneByUserNameAndOrgUUID (userName, orgUUID) {
     return this.collection.findOne().byUserNameAndOrgUUID(userName, orgUUID)
   }


Test patch:
diff --git a/test/integration-tests/org/postOrgUsersTest.js b/test/integration-tests/org/postOrgUsersTest.js
new file mode 100644
index 00000000..6ca02003
--- /dev/null
+++ b/test/integration-tests/org/postOrgUsersTest.js
@@ -0,0 +1,187 @@
+/* eslint-disable no-unused-expressions */
+const chai = require('chai')
+chai.use(require('chai-http'))
+const expect = chai.expect
+const { faker } = require('@faker-js/faker')
+
+const constants = require('../constants.js')
+const app = require('../../../src/index.js')
+const getConstants = require('../../../src/constants').getConstants
+const argon2 = require('argon2')
+const _ = require('lodash')
+const User = require('../../../src/model/user')
+const cryptoRandomString = require('crypto-random-string')
+
+const shortName = { shortname: 'win_5' }
+
+describe('Testing user post endpoint', () => {
+  let orgUuid
+  context('Positive Tests', () => {
+    it('Allows creation of user', async () => {
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'fakeuser999',
+          name: {
+            first: 'Dave',
+            last: 'FakeLastName',
+            middle: 'Cool',
+            suffix: 'Mr.'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(err).to.be.undefined
+          orgUuid = res.body.created.org_UUID
+        })
+    })
+  })
+  context('Negitive Test', () => {
+    it('Fails creation of user for bad long first name', async () => {
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'fakeuser9999',
+          name: {
+            first: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
+            last: 'FakeLastName',
+            middle: 'Cool',
+            suffix: 'Mr.'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(res).to.have.status(400)
+          expect(_.some(res.body.details, { msg: 'Invalid name.first. Name must be between 1 and 100 characters in length.' })).to.be.true
+          expect(err).to.be.undefined
+        })
+    })
+    it('Fails creation of user for bad long last name', async () => {
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'fakeuser1000',
+          name: {
+            first: 'FirstName',
+            last: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
+            middle: 'Cool',
+            suffix: 'Mr.'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(res).to.have.status(400)
+          expect(_.some(res.body.details, { msg: 'Invalid name.last. Name must be between 1 and 100 characters in length.' })).to.be.true
+          expect(err).to.be.undefined
+        })
+    })
+    it('Fails creation of user for bad long middle name', async () => {
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'fakeuser1001',
+          name: {
+            first: 'FirstName',
+            last: 'LastName',
+            middle: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1',
+            suffix: 'Mr.'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(res).to.have.status(400)
+          expect(_.some(res.body.details, { msg: 'Invalid name.middle. Name must be between 1 and 100 characters in length.' })).to.be.true
+          expect(err).to.be.undefined
+        })
+    })
+    it('Fails creation of user for bad long suffix name', async () => {
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'fakeuser1002',
+          name: {
+            first: 'FirstName',
+            last: 'LastName',
+            middle: 'MiddleName',
+            suffix: 'VerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnmVerylongnm1'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(res).to.have.status(400)
+          expect(_.some(res.body.details, { msg: 'Invalid name.suffix. Name must be between 1 and 100 characters in length.' })).to.be.true
+          expect(err).to.be.undefined
+        })
+    })
+    it('Fails creation of user for trying to add the 101th user', async () => {
+      const numberOfUsers = await User.where({ org_UUID: orgUuid }).countDocuments().exec()
+      for (let i = 0; i < (100 - numberOfUsers); i++) {
+        const newUser = new User()
+
+        newUser.name.first = faker.name.firstName()
+        newUser.name.last = faker.name.lastName()
+        newUser.username = faker.internet.userName({ firstName: newUser.name.first, lastName: newUser.name.last })
+        newUser.org_UUID = orgUuid
+        newUser.UUID = faker.datatype.uuid()
+        const randomKey = cryptoRandomString({ length: getConstants().CRYPTO_RANDOM_STRING_LENGTH })
+        newUser.secret = await argon2.hash(randomKey)
+
+        newUser.authority = {
+          active_roles: [
+            'ADMIN'
+          ]
+        }
+
+        await User.findOneAndUpdate().byUserNameAndOrgUUID(newUser.userName, newUser.org_UUID).updateOne(newUser).setOptions({ upsert: true })
+      }
+
+      await chai.request(app)
+        .post('/api/org/win_5/user')
+        .set({ ...constants.headers, ...shortName })
+        .send({
+          username: 'Fake101User',
+          name: {
+            first: 'Dave',
+            last: 'FakeLastName',
+            middle: 'Cool',
+            suffix: 'Mr.'
+          },
+          authority: {
+            active_roles: [
+              'ADMIN'
+            ]
+          }
+        })
+        .then((res, err) => {
+          expect(err).to.be.undefined
+          expect(res).to.have.status(400)
+          expect(res.body.error).to.contain('NUMBER_OF_USERS_IN_ORG_LIMIT_REACHED')
+        })
+    })
+  })
+})
diff --git a/test/unit-tests/user/userCreateTest.js b/test/unit-tests/user/userCreateTest.js
index 7c527104..ea3b1fce 100644
--- a/test/unit-tests/user/userCreateTest.js
+++ b/test/unit-tests/user/userCreateTest.js
@@ -1,506 +1,89 @@
-const express = require('express')
-const app = express()
+
+const sinon = require('sinon')
 const chai = require('chai')
 const expect = chai.expect
-chai.use(require('chai-http'))
-
-// Body Parser Middleware
-app.use(express.json()) // Allows us to handle raw JSON data
-app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
-const middleware = require('../../../src/middleware/middleware')
-app.use(middleware.createCtxAndReqUUID)
-
-const getConstants = require('../../../src/constants').getConstants
-const errors = require('../../../src/controller/org.controller/error')
-const error = new errors.OrgControllerError()
-
-const userFixtures = require('./mockObjects.user')
-const orgController = require('../../../src/controller/org.controller/org.controller')
-const orgParams = require('../../../src/controller/org.controller/org.middleware')
-
-class NullUserRepo {
-  async getUserUUID () {
-    return null
-  }
-
-  async findOneByUserNameAndOrgUUID () {
-    return null
-  }
-
-  async isAdmin () {
-    return null
-  }
-}
-
-class OrgCreatedUserOrgUndefined {
-  async isSecretariatUUID () {
-    return true
-  }
-
-  async getOrgUUID () {
-    return userFixtures.existentOrg.UUID
-  }
-
-  async findOneByUUID () {
-    return userFixtures.existentOrg
-  }
-}
-
-class UserCreatedOrgUndefined {
-  async findOneByUserNameAndOrgUUID () {
-    return null
-  }
-
-  async updateByUserNameAndOrgUUID () {
-    return null
-  }
-
-  async getUserUUID () {
-    return null
-  }
-
-  async isAdminUUID () {
-    return false
-  }
-}
-
-class OrgCreatedUserWithRole {
-  async isSecretariatUUID () {
-    return true
-  }
-
-  async getOrgUUID () {
-    return userFixtures.existentOrgDummy.UUID
-  }
-
-  async findOneByUUID () {
-    return userFixtures.existentOrgDummy
-  }
-}
+const { faker } = require('@faker-js/faker')
 
-class UserCreatedAdminWithRole {
-  constructor () {
-    const CONSTANTS = getConstants()
+const { USER_CREATE_SINGLE } = require('../../../src/controller/org.controller/org.controller')
 
-    this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userC))
-    this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN
-  }
+const UserRepository = require('../../../src/repositories/userRepository')
+const OrgRepository = require('../../../src/repositories/orgRepository')
 
-  async findOneByUserNameAndOrgUUID () {
-    return null
-  }
-
-  async isAdminUUID () {
-    return true
-  }
-
-  async updateByUserNameAndOrgUUID () {
-    return null
-  }
-
-  async getUserUUID () {
-    return null
-  }
+const stubOrgUUID = faker.datatype.uuid()
 
-  async aggregate () {
-    return [this.testRes1]
+const stubOrg = {
+  short_name: 'stubOrg',
+  name: 'test_user',
+  UUID: stubOrgUUID,
+  authority: {
+    active_roles: ['ADMIN', 'CNA']
   }
 }
 
-class OrgCantCreateUserOrgDoesNotMatch {
-  async getOrgUUID () {
-    return userFixtures.existentOrg.UUID
-  }
+const stubUser = {
+  username: 'stubUser',
+  org_UUID: stubOrgUUID,
+  UUID: faker.datatype.uuid()
 }
 
 describe('Testing the POST /org/:shortname/user endpoint in Org Controller', () => {
-  context('Negative Tests', () => {
-    it('User is not created because org does not exist', (done) => {
-      class OrgCantCreateUserOrgDoesNotExist {
-        async getOrgUUID () {
-          return null
-        }
-      }
-
-      app.route('/user-not-created-org-does-not-exist/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotExist() },
-            getUserRepository: () => { return new NullUserRepo() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      chai.request(app)
-        .post(`/user-not-created-org-does-not-exist/${userFixtures.nonExistentOrg.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(userFixtures.nonExistentUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(404)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          const errObj = error.orgDnePathParam(userFixtures.nonExistentOrg.short_name)
-          expect(res.body.error).to.equal(errObj.error)
-          expect(res.body.message).to.equal(errObj.message)
-          done()
-        })
-    })
-
-    it('Param org\'s UUID is provided', (done) => {
-      app.route('/user-not-created-org-uuid-provided/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotMatch() },
-            getUserRepository: () => { return new NullUserRepo() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      chai.request(app)
-        .post(`/user-not-created-org-uuid-provided/${userFixtures.existentOrg.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(userFixtures.existentUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(400)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          const errObj = error.uuidProvided('user')
-          expect(res.body.error).to.equal(errObj.error)
-          expect(res.body.message).to.equal(errObj.message)
-          done()
-        })
-    })
-
-    it('Param user\'s UUID is provided', (done) => {
-      app.route('/user-not-created-user-uuid-provided/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCantCreateUserOrgDoesNotMatch() },
-            getUserRepository: () => { return new UserCreatedOrgUndefined() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      chai.request(app)
-        .post(`/user-not-created-user-uuid-provided/${userFixtures.existentOrg.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(userFixtures.nonExistentUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(400)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          const errObj = error.uuidProvided('user')
-          expect(res.body.error).to.equal(errObj.error)
-          expect(res.body.message).to.equal(errObj.message)
-          done()
-        })
-    })
-
-    it('User is not created because it already exists', (done) => {
-      class UserNotCreatedAlreadyExists {
-        async findOneByUserNameAndOrgUUID () {
-          return userFixtures.existentUser
-        }
-
-        async isAdminUUID () {
-          return false
-        }
-      }
-
-      app.route('/user-not-created-already-exists/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCreatedUserOrgUndefined() },
-            getUserRepository: () => { return new UserNotCreatedAlreadyExists() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      const testUser = Object.assign({}, userFixtures.existentUser)
-      delete testUser.UUID
-      delete testUser.org_UUID
-
-      chai.request(app)
-        .post(`/user-not-created-already-exists/${userFixtures.existentOrg.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(testUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(400)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          const errObj = error.userExists(userFixtures.existentUser.username)
-          expect(res.body.error).to.equal(errObj.error)
-          expect(res.body.message).to.equal(errObj.message)
-          done()
-        })
-    })
-
-    it('User is not created because the requester is not an Org Admin user from the same org and is not the secretariat', done => {
-      class UserNotCreated {
-        async isAdminUUID () {
-          return true
+  let status, json, res, next, orgRepo, getOrgRepository, getUserRepository, userRepo, req, getOrg
+
+  beforeEach(() => {
+    status = sinon.stub()
+    json = sinon.spy()
+    res = { json, status }
+    next = sinon.spy()
+    status.returns(res)
+
+    userRepo = new UserRepository()
+    getUserRepository = sinon.stub()
+    getUserRepository.returns(userRepo)
+
+    orgRepo = new OrgRepository()
+    getOrgRepository = sinon.stub()
+    getOrgRepository.returns(orgRepo)
+    // May have to replace this based on tests
+    getOrg = sinon.stub(orgRepo, 'getOrgUUID').returns(stubOrgUUID)
+    sinon.stub(userRepo, 'findUsersByOrgUUID').returns(1)
+    sinon.stub(orgRepo, 'isSecretariatUUID').returns(false)
+    sinon.stub(userRepo, 'isAdminUUID').returns(true)
+    sinon.stub(userRepo, 'findOneByUserNameAndOrgUUID').returns(null)
+    sinon.stub(userRepo, 'updateByUserNameAndOrgUUID').returns(true)
+    sinon.stub(userRepo, 'aggregate').returns([stubUser])
+    sinon.stub(userRepo, 'getUserUUID').returns(stubUser.UUID)
+
+    req = {
+      ctx: {
+        org: stubOrg.short_name,
+        uuid: stubOrg.UUID,
+        params: {
+
+        },
+        repositories: {
+          getOrgRepository,
+          getUserRepository
+        },
+        body: {
+          stubUser
         }
       }
-
-      class OrgCantCreateUserNotSecretariatOrAdmin {
-        async isSecretariatUUID () {
-          return false
-        }
-
-        async getOrgUUID (shortname) {
-          if (shortname === userFixtures.existentOrgDummy.short_name) {
-            return userFixtures.existentOrgDummy.UUID
-          }
-
-          return userFixtures.owningOrg.UUID
-        }
-
-        async findOneByUUID (orgUUID) {
-          if (orgUUID === userFixtures.existentOrgDummy.UUID) {
-            return userFixtures.existentOrgDummy
-          }
-
-          return userFixtures.owningOrg
-        }
-      }
-
-      app.route('/user-not-created-not-secretariat-not-same-org-admin/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCantCreateUserNotSecretariatOrAdmin() },
-            getUserRepository: () => { return new UserNotCreated() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      const testUser = Object.assign({}, userFixtures.userA)
-      delete testUser.UUID
-      delete testUser.org_UUID
-      testUser.authority = {
-        active_roles: ['ADMIN']
-      }
-
-      chai.request(app)
-        .post(`/user-not-created-not-secretariat-not-same-org-admin/${userFixtures.existentOrgDummy.short_name}`)
-        .set(userFixtures.owningOrgHeader)
-        .send(testUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(403)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          const errObj = error.notOrgAdminOrSecretariat()
-          expect(res.body.error).to.equal(errObj.error)
-          expect(res.body.message).to.equal(errObj.message)
-          done()
-        })
-    })
+    }
   })
-
   context('Positive Tests', () => {
-    it('Requester is secretariat and not Admin: User is created with the "ADMIN" role', done => {
-      class UserCreatedWithRole {
-        constructor () {
-          const CONSTANTS = getConstants()
-
-          this.testRes1 = JSON.parse(JSON.stringify(userFixtures.userA))
-          this.testRes1.authority.active_roles[0] = CONSTANTS.USER_ROLE_ENUM.ADMIN
-        }
-
-        async findOneByUserNameAndOrgUUID () {
-          return null
-        }
-
-        async isAdminUUID () {
-          return false
-        }
-
-        async updateByUserNameAndOrgUUID () {
-          return null
-        }
-
-        async getUserUUID () {
-          return null
-        }
-
-        async aggregate () {
-          return [this.testRes1]
-        }
-      }
-
-      app.route('/user-created-secretariat-not-admin/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCreatedUserWithRole() },
-            getUserRepository: () => { return new UserCreatedWithRole() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      const testUser = JSON.parse(JSON.stringify(userFixtures.userA))
-      delete testUser.UUID
-      delete testUser.org_UUID
-      testUser.authority = {
-        active_roles: ['ADMIN']
-      }
-
-      chai.request(app)
-        .post(`/user-created-secretariat-not-admin/${userFixtures.existentOrgDummy.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(testUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(200)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          expect(res.body).to.have.property('message').and.to.be.a('string')
-          expect(res.body.message).to.equal(testUser.username + ' was successfully created.')
-          expect(res.body).to.have.property('created').and.to.be.a('object')
-          expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID)
-          expect(res.body.created).to.have.property('username').and.to.equal(testUser.username)
-          expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(1)
-          expect(res.body.created.authority.active_roles[0]).to.equal(testUser.authority.active_roles[0])
-          done()
-        })
-    })
-
-    it('Requester is Admin and is not secretariat: User is created with the "ADMIN" role', done => {
-      class OrgCreatedUserAdminWithRole {
-        async isSecretariatUUID () {
-          return false
-        }
-
-        async getOrgUUID () {
-          return userFixtures.existentOrgDummy.UUID
-        }
-
-        async findOneByUUID () {
-          return userFixtures.existentOrgDummy
-        }
-      }
-
-      app.route('/user-created-not-secretariat-same-org-admin/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCreatedUserAdminWithRole() },
-            getUserRepository: () => { return new UserCreatedAdminWithRole() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      userFixtures.userA.authority.active_roles = ['ADMIN']
-
-      const testUser = JSON.parse(JSON.stringify(userFixtures.userC))
-      delete testUser.UUID
-      delete testUser.org_UUID
-      testUser.authority = {
-        active_roles: ['ADMIN']
-      }
-
-      chai.request(app)
-        .post(`/user-created-not-secretariat-same-org-admin/${userFixtures.existentOrgDummy.short_name}`)
-        .set(userFixtures.userAHeader)
-        .send(testUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(200)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          expect(res.body).to.have.property('message').and.to.be.a('string')
-          expect(res.body.message).to.equal(testUser.username + ' was successfully created.')
-          expect(res.body).to.have.property('created').and.to.be.a('object')
-          expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID)
-          expect(res.body.created).to.have.property('username').and.to.equal(testUser.username)
-          expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(1)
-          expect(res.body.created.authority.active_roles[0]).to.equal(testUser.authority.active_roles[0])
-          userFixtures.userA.authority.active_roles = []
-          done()
-        })
+    it('User is created', async () => {
+      await USER_CREATE_SINGLE(req, res, next)
+      expect(status.args[0][0]).to.equal(200)
+      expect(res.json.args[0][0].message).contains('was successfully created')
     })
-
-    it('Requester is secretariat and Admin: User is created without a user role', done => {
-      class UserCreatedAdminWithoutRole {
-        async findOneByUserNameAndOrgUUID () {
-          return null
-        }
-
-        async isAdminUUID () {
-          return true
-        }
-
-        async updateByUserNameAndOrgUUID () {
-          return null
-        }
-
-        async getUserUUID () {
-          return null
-        }
-
-        async aggregate () {
-          return [userFixtures.userA]
-        }
-      }
-
-      app.route('/user-created-secretariat-same-org-admin/:shortname')
-        .post((req, res, next) => {
-          const factory = {
-            getOrgRepository: () => { return new OrgCreatedUserWithRole() },
-            getUserRepository: () => { return new UserCreatedAdminWithoutRole() }
-          }
-          req.ctx.repositories = factory
-          next()
-        }, orgParams.parsePostParams, orgController.USER_CREATE_SINGLE)
-
-      userFixtures.existentUser.authority.active_roles = ['ADMIN']
-      const testUser = JSON.parse(JSON.stringify(userFixtures.userA))
-      delete testUser.UUID
-      delete testUser.org_UUID
-
-      chai.request(app)
-        .post(`/user-created-secretariat-same-org-admin/${userFixtures.existentOrgDummy.short_name}`)
-        .set(userFixtures.secretariatHeader)
-        .send(testUser)
-        .end((err, res) => {
-          if (err) {
-            done(err)
-          }
-
-          expect(res).to.have.status(200)
-          expect(res).to.have.property('body').and.to.be.a('object')
-          expect(res.body).to.have.property('message').and.to.be.a('string')
-          expect(res.body.message).to.equal(userFixtures.userA.username + ' was successfully created.')
-          expect(res.body).to.have.property('created').and.to.be.a('object')
-          expect(res.body.created).to.have.property('org_UUID').and.to.equal(userFixtures.existentOrgDummy.UUID)
-          expect(res.body.created).to.have.property('username').and.to.equal(userFixtures.userA.username)
-          expect(res.body.created).to.have.nested.property('authority.active_roles').and.to.have.lengthOf(0)
-          userFixtures.existentUser.authority.active_roles = []
-          done()
-        })
+  })
+  context('Negitive tests', () => {
+    it('User Fails to be created because not in the same org', async () => {
+      req.ctx.org = 'FakeShortName'
+      getOrg.withArgs('FakeShortName').returns('FAKEUUID')
+      await USER_CREATE_SINGLE(req, res, next)
+      expect(status.args[0][0]).to.equal(403)
+      expect(res.json.args[0][0].error).contains('NOT_ORG_ADMIN_OR_SECRETARIAT')
     })
   })
 })