From 53c1627037a2c51764e71dfe5bc2bd29771d553e Mon Sep 17 00:00:00 2001 From: Michael Taylor Date: Mon, 17 Jan 2022 14:28:06 -0500 Subject: [PATCH] fix: fix data assertion usage --- src/controllers/organization.controller.js | 16 +---- src/controllers/project.controller.js | 6 +- src/controllers/staging.controller.js | 2 +- src/controllers/units.controller.js | 65 +++++++++++-------- .../organizations/organizations.model.js | 20 ++++++ src/routes/index.js | 8 ++- src/utils/csv-utils.js | 32 +++++---- src/utils/data-assertions.js | 11 ++++ 8 files changed, 94 insertions(+), 66 deletions(-) diff --git a/src/controllers/organization.controller.js b/src/controllers/organization.controller.js index 071ea9d8..9f030b27 100644 --- a/src/controllers/organization.controller.js +++ b/src/controllers/organization.controller.js @@ -1,19 +1,5 @@ import { Organization } from '../models/organizations'; export const findAll = async (req, res) => { - return res.json({ - ...(await Organization.getHomeOrg()), - '35f92331-c8d7-4e9e-a8d2-cd0a86cbb2cf': { - name: 'chili', - icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/chili.svg', - }, - 'fbffae6b-0203-4ac0-a08b-1551b730783b': { - name: 'belgium', - icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/belgium.svg', - }, - '70150fde-57f6-44a6-9486-1fef49528475': { - name: 'bulgaria', - icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/bulgaria.svg', - }, - }); + return res.json(await Organization.getOrgsMap()); }; diff --git a/src/controllers/project.controller.js b/src/controllers/project.controller.js index b84df860..b7155f4c 100644 --- a/src/controllers/project.controller.js +++ b/src/controllers/project.controller.js @@ -139,7 +139,7 @@ export const update = async (req, res) => { req.body.warehouseProjectId, ); - assertOrgIsHomeOrg(res, originalRecord.orgUid); + await assertOrgIsHomeOrg(originalRecord.orgUid); const stagedData = { uuid: req.body.warehouseProjectId, @@ -167,7 +167,7 @@ export const destroy = async (req, res) => { req.body.warehouseProjectId, ); - assertOrgIsHomeOrg(res, originalRecord.orgUid); + await assertOrgIsHomeOrg(originalRecord.orgUid); const stagedData = { uuid: req.body.warehouseProjectId, @@ -190,7 +190,7 @@ export const destroy = async (req, res) => { export const batchUpload = async (req, res) => { try { - const csvFile = await assertCsvFileInRequest(req); + const csvFile = assertCsvFileInRequest(req); await createProjectRecordsFromCsv(csvFile); res.json({ diff --git a/src/controllers/staging.controller.js b/src/controllers/staging.controller.js index 3087cad0..1d82d0a9 100644 --- a/src/controllers/staging.controller.js +++ b/src/controllers/staging.controller.js @@ -116,7 +116,7 @@ export const commit = async (req, res) => { export const destroy = async (req, res) => { try { - assertStagingRecordExists(req.body.uuid); + await assertStagingRecordExists(req.body.uuid); await Staging.destroy({ where: { uuid: req.body.uuid, diff --git a/src/controllers/units.controller.js b/src/controllers/units.controller.js index 6392a736..8346f6b1 100644 --- a/src/controllers/units.controller.js +++ b/src/controllers/units.controller.js @@ -18,6 +18,7 @@ import { assertUnitRecordExists, assertSumOfSplitUnitsIsValid, assertCsvFileInRequest, + assertOrgUidIsValid, } from '../utils/data-assertions'; import { createUnitRecordsFromCsv } from '../utils/csv-utils'; @@ -44,12 +45,15 @@ export const create = async (req, res) => { data: JSON.stringify([newRecord]), }; + console.log(stagedData); + await Staging.create(stagedData); res.json({ message: 'Unit created successfully', }); } catch (error) { + console.log('###', error); res.status(400).json({ message: 'Batch Upload Failed.', error: error.message, @@ -123,7 +127,11 @@ export const update = async (req, res) => { req.body.warehouseUnitId, ); - assertOrgIsHomeOrg(res, originalRecord.orgUid); + await assertOrgIsHomeOrg(originalRecord.orgUid); + + if (req.body.unitOwnerOrgUid) { + await assertOrgUidIsValid(req.body.unitOwnerOrgUid, 'unitOwnerOrgUid'); + } const stagedData = { uuid: req.body.warehouseUnitId, @@ -151,7 +159,7 @@ export const destroy = async (req, res) => { req.body.warehouseUnitId, ); - assertOrgIsHomeOrg(res, originalRecord.orgUid); + await assertOrgIsHomeOrg(originalRecord.orgUid); const stagedData = { uuid: req.body.warehouseUnitId, @@ -181,7 +189,7 @@ export const split = async (req, res) => { delete originalRecord.createdAt; delete originalRecord.updatedAt; - assertOrgIsHomeOrg(res, originalRecord.orgUid); + await assertOrgIsHomeOrg(originalRecord.orgUid); const { unitBlockStart } = assertSumOfSplitUnitsIsValid( originalRecord.serialNumberBlock, @@ -190,29 +198,32 @@ export const split = async (req, res) => { let lastAvailableUnitBlock = unitBlockStart; - const splitRecords = req.body.records.map((record) => { - const newRecord = _.cloneDeep(originalRecord); - newRecord.warehouseUnitId = uuidv4(); - newRecord.unitCount = record.unitCount; - - const newUnitBlockStart = lastAvailableUnitBlock; - lastAvailableUnitBlock += Number(record.unitCount); - const newUnitBlockEnd = lastAvailableUnitBlock; - // move to the next available block - lastAvailableUnitBlock += 1; - - newRecord.serialNumberBlock = createSerialNumberStr( - originalRecord.serialNumberBlock, - newUnitBlockStart, - newUnitBlockEnd, - ); - - if (record.unitOwnerOrgUid) { - newRecord.unitOwnerOrgUid = record.unitOwnerOrgUid; - } - - return newRecord; - }); + const splitRecords = await Promise.all( + req.body.records.map(async (record) => { + const newRecord = _.cloneDeep(originalRecord); + newRecord.warehouseUnitId = uuidv4(); + newRecord.unitCount = record.unitCount; + + const newUnitBlockStart = lastAvailableUnitBlock; + lastAvailableUnitBlock += Number(record.unitCount); + const newUnitBlockEnd = lastAvailableUnitBlock; + // move to the next available block + lastAvailableUnitBlock += 1; + + newRecord.serialNumberBlock = createSerialNumberStr( + originalRecord.serialNumberBlock, + newUnitBlockStart, + newUnitBlockEnd, + ); + + if (record.unitOwnerOrgUid) { + await assertOrgUidIsValid(record.unitOwnerOrgUid, 'unitOwnerOrgUid'); + newRecord.unitOwnerOrgUid = record.unitOwnerOrgUid; + } + + return newRecord; + }), + ); const stagedData = { uuid: req.body.warehouseUnitId, @@ -237,7 +248,7 @@ export const split = async (req, res) => { export const batchUpload = async (req, res) => { try { - const csvFile = await assertCsvFileInRequest(req); + const csvFile = assertCsvFileInRequest(req); await createUnitRecordsFromCsv(csvFile); res.json({ diff --git a/src/models/organizations/organizations.model.js b/src/models/organizations/organizations.model.js index 230f3814..3c835b8a 100644 --- a/src/models/organizations/organizations.model.js +++ b/src/models/organizations/organizations.model.js @@ -16,6 +16,26 @@ class Organization extends Model { }, }; } + + static async getOrgsMap() { + const homeOrg = await Organization.getHomeOrg(); + const stubbedOrganizations = { + ...homeOrg, + '35f92331-c8d7-4e9e-a8d2-cd0a86cbb2cf': { + name: 'chili', + icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/chili.svg', + }, + 'fbffae6b-0203-4ac0-a08b-1551b730783b': { + name: 'belgium', + icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/belgium.svg', + }, + '70150fde-57f6-44a6-9486-1fef49528475': { + name: 'bulgaria', + icon: 'https://climate-warehouse.s3.us-west-2.amazonaws.com/public/orgs/bulgaria.svg', + }, + }; + return stubbedOrganizations; + } } Organization.init(ModelTypes, { diff --git a/src/routes/index.js b/src/routes/index.js index 6f1a6bcd..dde35407 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -24,10 +24,12 @@ sequelize.authenticate().then(() => console.log('Connected to database')); app.use((err, req, res) => { if (_.get(err, 'error.details')) { // format Joi validation errors - return res - .status(400) - .json(err.error.details.map((detail) => detail.message)); + return res.status(400).json({ + message: 'API Validation error', + errors: err.error.details.map((detail) => detail.message), + }); } return res.status(400).json(err); }); + export default app; diff --git a/src/utils/csv-utils.js b/src/utils/csv-utils.js index 8638ecac..a69b0f4d 100644 --- a/src/utils/csv-utils.js +++ b/src/utils/csv-utils.js @@ -9,6 +9,7 @@ import { Staging, Organization, Unit, Project } from '../models'; import { assertOrgIsHomeOrg, assertUnitRecordExists, + assertOrgUidIsValid, } from '../utils/data-assertions'; export const createUnitRecordsFromCsv = (csvFile) => { @@ -23,31 +24,32 @@ export const createUnitRecordsFromCsv = (csvFile) => { .subscribe(async (newRecord) => { let action = 'UPDATE'; + const orgUid = _.head(Object.keys(await Organization.getHomeOrg())); + if (newRecord.warehouseUnitId) { // Fail if they supplied their own warehouseUnitId and it doesnt exist const possibleExistingRecord = await assertUnitRecordExists( newRecord.warehouseUnitId, ); - assertOrgIsHomeOrg(possibleExistingRecord.dataValues.orgUid); + await assertOrgIsHomeOrg(possibleExistingRecord.dataValues.orgUid); } else { // When creating new unitd assign a uuid to is so // multiple organizations will always have unique ids const uuid = uuidv4(); newRecord.warehouseUnitId = uuid; + newRecord.orgUid = orgUid; action = 'INSERT'; } - const orgUid = _.head(Object.keys(await Organization.getHomeOrg())); - - // All new records are registered within this org, but give them a chance to override this - if (!newRecord.orgUid) { - newRecord.orgUid = orgUid; - } - // All new records are owned by this org, but give them a chance to override this - if (!newRecord.unitOwnerOrgUid) { + if (newRecord.unitOwnerOrgUid) { + await assertOrgUidIsValid( + newRecord.unitOwnerOrgUid, + 'unitOwnerOrgUid', + ); + } else { newRecord.unitOwnerOrgUid = orgUid; } @@ -93,21 +95,17 @@ export const createProjectRecordsFromCsv = (csvFile) => { newRecord.warehouseProjectId, ); - assertOrgIsHomeOrg(possibleExistingRecord.dataValues.orgUid); + await assertOrgIsHomeOrg(possibleExistingRecord.dataValues.orgUid); } else { // When creating new unitd assign a uuid to is so // multiple organizations will always have unique ids const uuid = uuidv4(); newRecord.warehouseProjectId = uuid; - action = 'INSERT'; - } - - const orgUid = _.head(Object.keys(await Organization.getHomeOrg())); - - // All new records are registered within this org, but give them a chance to override this - if (!newRecord.orgUid) { + const orgUid = _.head(Object.keys(await Organization.getHomeOrg())); newRecord.orgUid = orgUid; + + action = 'INSERT'; } const stagedData = { diff --git a/src/utils/data-assertions.js b/src/utils/data-assertions.js index 00997d79..f6303ac2 100644 --- a/src/utils/data-assertions.js +++ b/src/utils/data-assertions.js @@ -5,6 +5,17 @@ import _ from 'lodash'; import { Organization, Unit, Project, Staging } from '../models'; import { transformSerialNumberBlock } from '../utils/helpers'; +export const assertOrgUidIsValid = async (orgUid, fieldName) => { + const orgMap = await Organization.getOrgsMap(); + if (!orgMap[orgUid]) { + throw new Error( + `The orgUid: ${orgUid}, provided for '${fieldName}' is not in the list of subscribed organizations, either remove it or add it to your organizations and try again`, + ); + } + + return orgMap; +}; + export const assertCsvFileInRequest = (req) => { if (!_.get(req, 'files.csv')) { throw new Error('Can not file the required csv file in request');