Skip to content

Commit ff89e19

Browse files
authored
Merge pull request #1562 from CVEProject/cb_1543_1544_registry_update_delete
Resolves #1543, #1544 - Refactored registry org update and delete endpoints to use base org repo
2 parents f324de8 + 46b2409 commit ff89e19

File tree

6 files changed

+377
-167
lines changed

6 files changed

+377
-167
lines changed

src/controller/registry-org.controller/index.js

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
const express = require('express')
22
const router = express.Router()
33
const mw = require('../../middleware/middleware')
4-
const errorMsgs = require('../../middleware/errorMessages')
5-
const { body, param, query } = require('express-validator')
4+
const { param, query } = require('express-validator')
65
const controller = require('./registry-org.controller')
7-
const { parseGetParams, parsePostParams, parseDeleteParams, parseError, isOrgRole } = require('./registry-org.middleware')
8-
const { toUpperCaseArray, toLowerCaseArray, isFlatStringArray } = require('../../middleware/middleware')
6+
const { parseGetParams, parsePostParams, parseDeleteParams, parseError } = require('./registry-org.middleware')
97
const getConstants = require('../../constants').getConstants
108
const CONSTANTS = getConstants()
119

@@ -300,49 +298,17 @@ router.put('/registryOrg/:shortname',
300298
}
301299
}
302300
*/
301+
mw.useRegistry(),
303302
mw.validateUser,
304303
mw.onlySecretariat,
305304
param(['shortname']).isString().trim(),
306-
body(['short_name']).isString().trim().notEmpty().isLength({ min: CONSTANTS.MIN_SHORTNAME_LENGTH, max: CONSTANTS.MAX_SHORTNAME_LENGTH }),
307-
body(['long_name']).isString().trim().notEmpty(),
308-
body(['cve_program_org_function']).isString().trim().default('CNA'),
309-
body(['root_or_tlr']).default(false).isBoolean(),
310-
body(['oversees']).default([]).isArray(),
311-
body(
312-
[
313-
'charter_or_scope',
314-
'disclosure_policy',
315-
'product_list',
316-
'reports_to',
317-
'contact_info.poc',
318-
'contact_info.poc_email',
319-
'contact_info.poc_phone',
320-
'contact_info.org_email',
321-
'contact_info.website'
322-
])
323-
.default('')
324-
.isString(),
325-
body(['authority.active_roles']).optional()
326-
.custom(isFlatStringArray)
327-
.customSanitizer(toUpperCaseArray)
328-
.custom(isOrgRole),
329-
body(['soft_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),
330-
body(['hard_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),
331-
body(['contact_info.additional_contact_users']).optional()
332-
.custom(isFlatStringArray),
333-
body(['contact_info.admins']).optional()
334-
.custom(isFlatStringArray),
335-
body(['aliases']).optional()
336-
.custom(isFlatStringArray)
337-
.customSanitizer(toLowerCaseArray),
338-
// TO-DO: validate users here once implemented
339305
parseError,
340306
parsePostParams,
341-
parseGetParams,
342307
controller.UPDATE_ORG
343308
)
344309

345-
router.delete('/registryOrg/:identifier',
310+
router.delete(
311+
'/registryOrg/:identifier',
346312
/*
347313
#swagger.tags = ['Registry Organization']
348314
#swagger.operationId = 'deleteRegistryOrg'
@@ -413,17 +379,15 @@ router.delete('/registryOrg/:identifier',
413379
}
414380
}
415381
*/
382+
mw.useRegistry(),
416383
mw.validateUser,
417-
// TODO: permissions
418384
mw.onlySecretariat,
419385
param(['identifier']).isString().trim(),
420386
parseError,
421387
parseDeleteParams,
422388
controller.DELETE_ORG
423389
)
424390

425-
console.log(controller.USER_ALL)
426-
427391
router.get('/registryOrg/:shortname/users',
428392
/*
429393
#swagger.tags = ['Registry User']

src/controller/registry-org.controller/registry-org.controller.js

Lines changed: 67 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const mongoose = require('mongoose')
22
const logger = require('../../middleware/logger')
33
const { getConstants } = require('../../constants')
4-
const RegistryOrg = require('../../model/registry-org')
54
const errors = require('./error')
65
const error = new errors.RegistryOrgControllerError()
76
const validateUUID = require('uuid').validate
@@ -196,96 +195,60 @@ async function createOrg (req, res, next) {
196195
*/
197196
async function updateOrg (req, res, next) {
198197
try {
198+
const session = await mongoose.startSession()
199199
const shortName = req.ctx.params.shortname
200-
const userRepo = req.ctx.repositories.getRegistryUserRepository()
201-
const registryOrgRepo = req.ctx.repositories.getRegistryOrgRepository()
200+
const repo = req.ctx.repositories.getBaseOrgRepository()
201+
const body = req.ctx.body
202+
let updatedOrg
202203

203-
const org = await registryOrgRepo.findOneByShortName(shortName)
204-
if (!org) {
205-
logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization could not be updated in MongoDB because it does not exist.' })
206-
return res.status(404).json(error.orgDnePathParam(shortName))
207-
}
204+
try {
205+
session.startTransaction()
206+
const org = await repo.findOneByShortName(shortName)
207+
if (!org) {
208+
logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization could not be updated because it does not exist.' })
209+
await session.abortTransaction()
210+
return res.status(404).json(error.orgDnePathParam(shortName))
211+
}
208212

209-
const orgUUID = await registryOrgRepo.getOrgUUID(shortName)
210-
211-
const newOrg = new RegistryOrg()
212-
newOrg.contact_info = { ...org.contact_info }
213-
214-
for (const k in req.ctx.query) {
215-
const key = k.toLowerCase()
216-
217-
if (key === 'long_name') {
218-
newOrg.long_name = req.ctx.query.long_name
219-
} else if (key === 'short_name') {
220-
newOrg.short_name = req.ctx.query.short_name
221-
} else if (key === 'aliases') {
222-
// TODO: handle aliases
223-
} else if (key === 'cve_program_org_function') {
224-
newOrg.cve_program_org_function = req.ctx.query.cve_program_org_function
225-
// TODO: validate against enum?
226-
} else if (key === 'authority') {
227-
// TODO: handle active_roles
228-
} else if (key === 'reports_to') {
229-
// TODO: validate org
230-
} else if (key === 'oversees') {
231-
// TODO: validate orgs
232-
} else if (key === 'root_or_tlr') {
233-
newOrg.root_or_tlr = req.ctx.query.root_or_tlr
234-
} else if (key === 'users') {
235-
// TODO: validate users
236-
} else if (key === 'charter_or_scope') {
237-
newOrg.charter_or_scope = req.ctx.query.charter_or_scope
238-
} else if (key === 'disclosure_policy') {
239-
newOrg.disclosure_policy = req.ctx.query.disclosure_policy
240-
} else if (key === 'product_list') {
241-
newOrg.product_list = req.ctx.query.product_list
242-
} else if (key === 'soft_quota') {
243-
newOrg.soft_quota = req.ctx.query.soft_quota
244-
} else if (key === 'hard_quota') {
245-
newOrg.hard_quota = req.ctx.query.hard_quota
246-
} else if (key === 'contact_info.additional_contact_users') {
247-
// TODO: validate users
248-
} else if (key === 'contact_info.poc') {
249-
newOrg.contact_info.poc = req.ctx.query['contact_info.poc']
250-
} else if (key === 'contact_info.poc_email') {
251-
newOrg.contact_info.poc_email = req.ctx.query['contact_info.poc_email']
252-
} else if (key === 'contact_info.poc_phone') {
253-
newOrg.contact_info.poc_phone = req.ctx.query['contact_info.poc_phone']
254-
} else if (key === 'contact_info.admins') {
255-
// TODO: validate admins
256-
} else if (key === 'contact_info.org_email') {
257-
newOrg.contact_info.org_email = req.ctx.query['contact_info.org_email']
258-
} else if (key === 'contact_info.website') {
259-
newOrg.contact_info.website = req.ctx.query['contact_info.website']
213+
const result = repo.validateOrg(body, { session })
214+
if (!result.isValid) {
215+
logger.error(JSON.stringify({ uuid: req.ctx.uuid, message: 'CVE JSON schema validation FAILED.' }))
216+
await session.abortTransaction()
217+
return res.status(400).json({ message: 'Parameters were invalid', errors: result.errors })
260218
}
219+
220+
// Check for duplicate short_name
221+
if (body?.short_name !== shortName && await repo.orgExists(body?.short_name, { session })) {
222+
logger.info({
223+
uuid: req.ctx.uuid,
224+
message: `${shortName} organization could not be updated because new short name ${body?.short_name} already exists.`
225+
})
226+
await session.abortTransaction()
227+
return res.status(400).json(error.duplicateShortname(body?.short_name))
228+
}
229+
230+
updatedOrg = await repo.updateOrgFull(shortName, body, { session })
231+
await session.commitTransaction()
232+
} catch (updateErr) {
233+
await session.abortTransaction()
234+
throw updateErr
235+
} finally {
236+
await session.endSession()
261237
}
262238

263-
await registryOrgRepo.updateByUUID(orgUUID, newOrg)
264-
const agt = setAggregateOrgObj({ UUID: orgUUID })
265-
let result = await registryOrgRepo.aggregate(agt)
266-
result = result.length > 0 ? result[0] : null
239+
const responseMessage = {
240+
message: `${body?.short_name} organization was successfully updated.`,
241+
updated: updatedOrg
242+
}
267243

268244
const payload = {
269245
action: 'update_registry_org',
270-
change: result.short_name + ' was successfully updated.',
246+
change: body?.short_name + ' was successfully updated.',
271247
req_UUID: req.ctx.uuid,
272-
org_UUID: await registryOrgRepo.getOrgUUID(req.ctx.org),
273-
user: result
248+
org_UUID: await repo.getOrgUUID(req.ctx.org),
249+
org: updatedOrg
274250
}
275-
payload.user_UUID = await userRepo.getUserUUID(req.ctx.user, payload.org_UUID)
276251
logger.info(JSON.stringify(payload))
277-
278-
let msgStr = ''
279-
if (Object.keys(req.ctx.query).length > 0) {
280-
msgStr = result.short_name + ' was successfully updated.'
281-
} else {
282-
msgStr = 'No updates were specified for ' + result.short_name + '.'
283-
}
284-
const responseMessage = {
285-
message: msgStr,
286-
updated: result
287-
}
288-
289252
return res.status(200).json(responseMessage)
290253
} catch (err) {
291254
next(err)
@@ -306,28 +269,39 @@ async function updateOrg (req, res, next) {
306269
*/
307270
async function deleteOrg (req, res, next) {
308271
try {
309-
const userRepo = req.ctx.repositories.getUserRepository()
310-
const orgRepo = req.ctx.repositories.getOrgRepository()
311-
const registryOrgRepo = req.ctx.repositories.getRegistryOrgRepository()
312-
const orgUUID = req.ctx.params.identifier
272+
const session = await mongoose.startSession()
273+
const repo = req.ctx.repositories.getBaseOrgRepository()
274+
const shortName = req.ctx.params.identifier
313275

314-
const org = await registryOrgRepo.findOneByUUID(orgUUID)
276+
try {
277+
session.startTransaction()
278+
const org = await repo.findOneByShortName(shortName)
279+
if (!org) {
280+
logger.info({ uuid: req.ctx.uuid, message: shortName + ' organization could not be deleted because it does not exist.' })
281+
await session.abortTransaction()
282+
return res.status(404).json(error.orgDnePathParam(shortName))
283+
}
284+
285+
await repo.deleteOrg(shortName, { session })
286+
await session.commitTransaction()
287+
} catch (deleteErr) {
288+
await session.abortTransaction()
289+
throw deleteErr
290+
} finally {
291+
await session.endSession()
292+
}
315293

316-
await registryOrgRepo.deleteByUUID(orgUUID)
294+
const responseMessage = {
295+
message: `${shortName} organization was successfully deleted.`
296+
}
317297

318298
const payload = {
319299
action: 'delete_registry_org',
320-
change: org.short_name + ' was successfully deleted.',
300+
change: shortName + ' was successfully deleted.',
321301
req_UUID: req.ctx.uuid,
322-
org_UUID: await orgRepo.getOrgUUID(req.ctx.org)
302+
org_UUID: await repo.getOrgUUID(req.ctx.org)
323303
}
324-
payload.user_UUID = await userRepo.getUserUUID(req.ctx.user, payload.org_UUID)
325304
logger.info(JSON.stringify(payload))
326-
327-
const responseMessage = {
328-
message: org.short_name + ' was successfully deleted.'
329-
}
330-
331305
return res.status(200).json(responseMessage)
332306
} catch (err) {
333307
next(err)
@@ -489,38 +463,6 @@ async function createUserByOrg (req, res, next) {
489463
}
490464
}
491465

492-
function setAggregateOrgObj (query) {
493-
return [
494-
{
495-
$match: query
496-
},
497-
{
498-
$project: {
499-
_id: false,
500-
UUID: true,
501-
long_name: true,
502-
short_name: true,
503-
aliases: true,
504-
cve_program_org_function: true,
505-
authority: true,
506-
reports_to: true,
507-
oversees: true,
508-
root_or_tlr: true,
509-
users: true,
510-
charter_or_scope: true,
511-
disclosure_policy: true,
512-
product_list: true,
513-
soft_quota: true,
514-
hard_quota: true,
515-
contact_info: true,
516-
in_use: true,
517-
created: true,
518-
last_updated: true
519-
}
520-
}
521-
]
522-
}
523-
524466
module.exports = {
525467
ALL_ORGS: getAllOrgs,
526468
SINGLE_ORG: getOrg,

0 commit comments

Comments
 (0)