1- const argon2 = require ( 'argon2' )
2- const cryptoRandomString = require ( 'crypto-random-string' )
3- const uuid = require ( 'uuid' )
1+ const mongoose = require ( 'mongoose' )
42const logger = require ( '../../middleware/logger' )
53const { getConstants } = require ( '../../constants' )
64const errors = require ( '../user.controller/error' )
@@ -9,6 +7,9 @@ const error = new errors.UserControllerError()
97async function getAllUsers ( req , res , next ) {
108 try {
119 const CONSTANTS = getConstants ( )
10+ const session = await mongoose . startSession ( )
11+ const repo = req . ctx . repositories . getBaseUserRepository ( )
12+ let returnValue
1213
1314 // temporary measure to allow tests to work after fixing #920
1415 // tests required changing the global limit to force pagination
@@ -19,107 +20,98 @@ async function getAllUsers (req, res, next) {
1920 const options = CONSTANTS . PAGINATOR_OPTIONS
2021 options . sort = { short_name : 'asc' }
2122 options . page = req . ctx . query . page ? parseInt ( req . ctx . query . page ) : CONSTANTS . PAGINATOR_PAGE // if 'page' query parameter is not defined, set 'page' to the default page value
22- const repo = req . ctx . repositories . getRegistryUserRepository ( )
2323
24- const agt = setAggregateUserObj ( { } )
25- const pg = await repo . aggregatePaginate ( agt , options )
26-
27- const payload = { users : pg . itemsList }
28-
29- if ( pg . itemCount >= CONSTANTS . PAGINATOR_OPTIONS . limit ) {
30- payload . totalCount = pg . itemCount
31- payload . itemsPerPage = pg . itemsPerPage
32- payload . pageCount = pg . pageCount
33- payload . currentPage = pg . currentPage
34- payload . prevPage = pg . prevPage
35- payload . nextPage = pg . nextPage
24+ try {
25+ returnValue = await repo . getAllUsers ( options )
26+ } finally {
27+ await session . endSession ( )
3628 }
3729
3830 logger . info ( { uuid : req . ctx . uuid , message : 'The user information was sent to the secretariat user.' } )
39- return res . status ( 200 ) . json ( payload )
31+ return res . status ( 200 ) . json ( returnValue )
4032 } catch ( err ) {
4133 next ( err )
4234 }
4335}
4436
4537async function getUser ( req , res , next ) {
4638 try {
47- const repo = req . ctx . repositories . getRegistryUserRepository ( )
39+ const repo = req . ctx . repositories . getBaseUserRepository ( )
4840 const identifier = req . ctx . params . identifier
49- const agt = setAggregateUserObj ( { UUID : identifier } )
50- let result = await repo . aggregate ( agt )
51- result = result . length > 0 ? result [ 0 ] : null
5241
53- logger . info ( { uuid : req . ctx . uuid , message : identifier + ' user was sent to the user.' , user : result } )
42+ const result = await repo . findUserByUUID ( identifier )
43+ if ( ! result ) {
44+ logger . info ( { uuid : req . ctx . uuid , message : identifier + 'user could not be found.' } )
45+ return res . status ( 404 ) . json ( error . userDne ( identifier ) )
46+ }
5447 return res . status ( 200 ) . json ( result )
5548 } catch ( err ) {
5649 next ( err )
5750 }
5851}
5952
6053async function createUser ( req , res , next ) {
54+ const session = await mongoose . startSession ( )
6155 try {
62- // const requesterUsername = req.ctx.user
63- // const requesterShortName = req.ctx.org
64- const orgRepo = req . ctx . repositories . getOrgRepository ( )
65- const userRepo = req . ctx . repositories . getUserRepository ( )
66- const registryUserRepo = req . ctx . repositories . getRegistryUserRepository ( )
56+ const orgRepo = req . ctx . repositories . getBaseOrgRepository ( )
57+ const userRepo = req . ctx . repositories . getBaseUserRepository ( )
6758 const body = req . ctx . body
59+ const orgShortName = req . ctx . params . shortname
60+ let returnValue
61+
62+ const orgUUID = await orgRepo . getOrgUUID ( orgShortName )
63+ if ( ! orgUUID ) {
64+ logger . info ( { uuid : req . ctx . uuid , message : 'The user could not be created because ' + orgShortName + ' organization does not exist.' } )
65+ return res . status ( 404 ) . json ( error . orgDnePathParam ( orgShortName ) )
66+ }
6867
69- // Short circuit if UUID provided
70- const bodyKeys = Object . keys ( body ) . map ( ( k ) => k . toLowerCase ( ) )
71- if ( bodyKeys . includes ( 'uuid' ) ) {
68+ // Do not allow the user to pass in a UUID
69+ if ( ( body ?. UUID ?? null ) || ( body ?. uuid ?? null ) ) {
7270 return res . status ( 400 ) . json ( error . uuidProvided ( 'user' ) )
7371 }
7472
75- // TODO: check if affiliated orgs and program orgs exist, and if their membership limit is reached
76-
77- const newUser = new RegistryUser ( )
78- Object . keys ( body ) . map ( k => k . toLowerCase ( ) ) . forEach ( k => {
79- if ( k === 'user_id' || k === 'username' ) {
80- newUser . user_id = body [ k ]
81- } else if ( k === 'name' ) {
82- newUser . name = {
83- first : '' ,
84- last : '' ,
85- middle : '' ,
86- suffix : '' ,
87- ...body . name
88- }
89- } else if ( k === 'org_affiliations' ) {
90- // TODO: dedupe
91- } else if ( k === 'cve_program_org_membership' ) {
92- // TODO: dedupe
93- }
94- } )
73+ if ( ( body ?. org_UUID ?? null ) || ( body ?. org_uuid ?? null ) ) {
74+ return res . status ( 400 ) . json ( error . uuidProvided ( 'org' ) )
75+ }
9576
96- // TODO: check that requesting user is admin of org for new user
77+ try {
78+ session . startTransaction ( )
9779
98- newUser . UUID = uuid . v4 ( )
99- const randomKey = cryptoRandomString ( { length : getConstants ( ) . CRYPTO_RANDOM_STRING_LENGTH } )
100- newUser . secret = await argon2 . hash ( randomKey )
101- newUser . last_active = null
102- newUser . deactivation_date = null
80+ const result = await userRepo . validateUser ( body )
81+ if ( body ?. role && typeof body ?. role !== 'string' ) {
82+ return res . status ( 400 ) . json ( { message : 'Parameters were invalid' , details : [ { param : 'role' , msg : 'Parameter must be a string' } ] } )
83+ }
84+ if ( ! result . isValid ) {
85+ logger . error ( JSON . stringify ( { uuid : req . ctx . uuid , message : 'User JSON schema validation FAILED.' } ) )
86+ await session . abortTransaction ( )
87+ return res . status ( 400 ) . json ( { message : 'Parameters were invalid' , errors : result . errors } )
88+ }
10389
104- await registryUserRepo . updateByUUID ( newUser . UUID , newUser , { upsert : true } )
105- const agt = setAggregateUserObj ( { UUID : newUser . UUID } )
106- let result = await registryUserRepo . aggregate ( agt )
107- result = result . length > 0 ? result [ 0 ] : null
90+ // Ask repo if user already exists
91+ if ( await userRepo . orgHasUser ( orgShortName , body ?. username , { session } ) ) {
92+ logger . info ( { uuid : req . ctx . uuid , message : `${ body ?. username } user was not created because it already exists.` } )
93+ await session . abortTransaction ( )
94+ return res . status ( 400 ) . json ( error . userExists ( body ?. username ) )
95+ }
10896
109- const payload = {
110- action : 'create_registry_user' ,
111- change : result . user_id + ' was successfully created.' ,
112- req_UUID : req . ctx . uuid ,
113- org_UUID : await orgRepo . getOrgUUID ( req . ctx . org ) ,
114- user : result
97+ const users = await userRepo . findUsersByOrgShortname ( orgShortName , { session } )
98+ if ( users . length >= 100 ) {
99+ await session . abortTransaction ( )
100+ return res . status ( 400 ) . json ( error . userLimitReached ( ) )
101+ }
102+
103+ returnValue = await userRepo . createUser ( orgShortName , body , { session, upsert : true } )
104+ await session . commitTransaction ( )
105+ } catch ( error ) {
106+ await session . abortTransaction ( )
107+ throw error
108+ } finally {
109+ await session . endSession ( )
115110 }
116- payload . user_UUID = await userRepo . getUserUUID ( req . ctx . user , payload . org_UUID )
117- logger . info ( JSON . stringify ( payload ) )
118111
119- result . secret = randomKey
120112 const responseMessage = {
121- message : result . user_id + ' was successfully created.' ,
122- created : result
113+ message : ` ${ body ? .user_id } + ' was successfully created.` ,
114+ created : returnValue
123115 }
124116
125117 return res . status ( 200 ) . json ( responseMessage )
@@ -130,48 +122,9 @@ async function createUser (req, res, next) {
130122
131123async function updateUser ( req , res , next ) {
132124 try {
133- // const username = req.ctx.params.username
134- // const shortName = req.ctx.params.shortname
135125 const userUUID = req . ctx . params . identifier
136- const userRepo = req . ctx . repositories . getUserRepository ( )
137- const orgRepo = req . ctx . repositories . getOrgRepository ( )
138- const registryUserRepo = req . ctx . repositories . getRegistryUserRepository ( )
139- // const orgUUID = await orgRepo.getOrgUUID(shortName)
140- // Check if requester is Admin of the designated user's org
141-
142- const user = await registryUserRepo . findOneByUUID ( userUUID )
143- const newUser = new RegistryUser ( )
144-
145- // Sets the name values to what currently exists in the database, this ensures data is retained during partial name updates
146- newUser . name . first = user . name . first
147- newUser . name . last = user . name . last
148- newUser . name . middle = user . name . middle
149- newUser . name . suffix = user . name . suffix
150-
151- // TODO: check permissions
152- // Check to ensure that the user has the right permissions to edit the fields tha they are requesting to edit, and fail fast if they do not.
153- // if (Object.keys(req.ctx.query).length > 0 && Object.keys(req.ctx.query).some((key) => { return queryParameterPermissions[key] }) && !(isAdmin || isSecretariat)) {
154- // logger.info({ uuid: req.ctx.uuid, message: 'The user could not be updated because ' + requesterUsername + ' user is not Org Admin or Secretariat to modify these fields.' })
155- // return res.status(403).json(error.notOrgAdminOrSecretariatUpdate())
156- // }
157-
158- for ( const k in req . ctx . query ) {
159- const key = k . toLowerCase ( )
160-
161- if ( key === 'new_user_id' ) {
162- newUser . user_id = req . ctx . query . new_user_id
163- } else if ( key === 'name.first' ) {
164- newUser . name . first = req . ctx . query [ 'name.first' ]
165- } else if ( key === 'name.last' ) {
166- newUser . name . last = req . ctx . query [ 'name.last' ]
167- } else if ( key === 'name.middle' ) {
168- newUser . name . middle = req . ctx . query [ 'name.middle' ]
169- } else if ( key === 'name.suffix' ) {
170- newUser . name . suffix = req . ctx . query [ 'name.suffix' ]
171- }
172-
173- // TODO: process org affiliations and program org membership updates
174- }
126+ const userRepo = req . ctx . repositories . getBaseUserRepository ( )
127+ const orgRepo = req . ctx . repositories . getBaseOrgRepository ( )
175128
176129 await registryUserRepo . updateByUUID ( userUUID , newUser )
177130 const agt = setAggregateUserObj ( { UUID : userUUID } )
0 commit comments