From 48b1a9da6e8f5ec6bb83dd459b29664c14825208 Mon Sep 17 00:00:00 2001 From: VLE2FE Date: Fri, 29 May 2020 10:40:17 +0200 Subject: [PATCH] separated groups and suppliers for material PUT and POST --- src/routes/material.spec.ts | 71 +++++++++++++++++++++++---------- src/routes/material.ts | 66 ++++++++++++++++++++---------- src/routes/template.spec.ts | 1 - src/routes/validate/material.ts | 2 + 4 files changed, 96 insertions(+), 44 deletions(-) diff --git a/src/routes/material.spec.ts b/src/routes/material.spec.ts index 31d7137..43a66ae 100644 --- a/src/routes/material.spec.ts +++ b/src/routes/material.spec.ts @@ -1,10 +1,12 @@ import should from 'should/as-function'; import _ from 'lodash'; import MaterialModel from '../models/material'; +import MaterialGroupModel from '../models/material_groups'; +import MaterialSupplierModel from '../models/material_suppliers'; import TestHelper from "../test/helper"; import globals from '../globals'; -// TODO: separate supplier/ material name into own collections + describe('/material', () => { let server; @@ -267,7 +269,17 @@ describe('/material', () => { MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => { if (err) return done(err); should(data).have.property('status',globals.status.validated); - done(); + MaterialGroupModel.find({name: 'PA46'}).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.lengthOf(1); + should(data[0]._id.toString()).be.eql('900000000000000000000001'); + MaterialSupplierModel.find({name: 'DSM'}).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.lengthOf(1); + should(data[0]._id.toString()).be.eql('110000000000000000000001'); + done(); + }); + }); }); }); }); @@ -302,9 +314,21 @@ describe('/material', () => { MaterialModel.findById('100000000000000000000001').lean().exec((err, data:any) => { if (err) return done(err); data._id = data._id.toString(); + data.group_id = data.group_id.toString(); + data.supplier_id = data.supplier_id.toString(); data.numbers = data.numbers.map(e => {return {color: e.color, number: e.number}}); - should(data).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', mineral: '0', glass_fiber: '35', carbon_fiber: '0', numbers: [{color: 'black', number: '5514212901'}, {color: 'signalviolet', number: '5514612901'}], status: 0, __v: 0}); - done(); + should(data).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier_id: '110000000000000000000002', group_id: '900000000000000000000002', mineral: '0', glass_fiber: '35', carbon_fiber: '0', numbers: [{color: 'black', number: '5514212901'}, {color: 'signalviolet', number: '5514612901'}], status: 0, __v: 0}); + MaterialGroupModel.find({name: 'PA6/6T'}).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.lengthOf(1); + should(data[0]._id.toString()).be.eql('900000000000000000000002'); + MaterialSupplierModel.find({name: 'BASF'}).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.lengthOf(1); + should(data[0]._id.toString()).be.eql('110000000000000000000002'); + done(); + }); + }); }); }); }); @@ -436,8 +460,10 @@ describe('/material', () => { MaterialModel.findById('100000000000000000000002').lean().exec((err, data: any) => { if (err) return done(err); data._id = data._id.toString(); + data.group_id = data.group_id.toString(); + data.supplier_id = data.supplier_id.toString(); data.numbers = data.numbers.map(e => {return {color: e.color, number: e.number}}); - should(data).be.eql({_id: '100000000000000000000002', name: 'Ultramid T KR 4355 G7', supplier: 'BASF', group: 'PA6/6T', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: '5514212901'}, {color: 'signalviolet', number: '5514612901'}], status: -1, __v: 0} + should(data).be.eql({_id: '100000000000000000000002', name: 'Ultramid T KR 4355 G7', supplier_id: '110000000000000000000002', group_id: '900000000000000000000002', mineral: 0, glass_fiber: 35, carbon_fiber: 0, numbers: [{color: 'black', number: '5514212901'}, {color: 'signalviolet', number: '5514612901'}], status: -1, __v: 0} ); done(); }); @@ -583,20 +609,25 @@ describe('/material', () => { req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []} }).end(err => { if (err) return done (err); - MaterialModel.find({name: 'Crastin CE 2510'}).lean().exec((err, data: any) => { + MaterialModel.find({name: 'Crastin CE 2510'}).lean().exec((err, materialData: any) => { if (err) return done (err); - should(data).have.lengthOf(1); - should(data[0]).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', 'status', '__v'); - should(data[0]).have.property('_id'); - should(data[0]).have.property('name', 'Crastin CE 2510'); - should(data[0]).have.property('supplier', 'Du Pont'); - should(data[0]).have.property('group', 'PBT'); - should(data[0]).have.property('mineral', '0'); - should(data[0]).have.property('glass_fiber', '30'); - should(data[0]).have.property('carbon_fiber', '0'); - should(data[0]).have.property('status',globals.status.new); - should(data[0].numbers).have.lengthOf(0); - done(); + should(materialData).have.lengthOf(1); + should(materialData[0]).have.only.keys('_id', 'name', 'supplier_id', 'group_id', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', 'status', '__v'); + should(materialData[0]).have.property('name', 'Crastin CE 2510'); + should(materialData[0]).have.property('mineral', '0'); + should(materialData[0]).have.property('glass_fiber', '30'); + should(materialData[0]).have.property('carbon_fiber', '0'); + should(materialData[0]).have.property('status',globals.status.new); + should(materialData[0].numbers).have.lengthOf(0); + MaterialGroupModel.findById(materialData[0].group_id).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.property('name', 'PBT') + MaterialSupplierModel.findById(materialData[0].supplier_id).lean().exec((err, data) => { + if (err) return done(err); + should(data).have.property('name', 'Du Pont'); + done(); + }); + }); }); }); }); @@ -625,11 +656,9 @@ describe('/material', () => { MaterialModel.find({name: 'Crastin CE 2510'}).lean().exec((err, data: any) => { if (err) return done (err); should(data).have.lengthOf(1); - should(data[0]).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', 'status', '__v'); + should(data[0]).have.only.keys('_id', 'name', 'supplier_id', 'group_id', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers', 'status', '__v'); should(data[0]).have.property('_id'); should(data[0]).have.property('name', 'Crastin CE 2510'); - should(data[0]).have.property('supplier', 'Du Pont'); - should(data[0]).have.property('group', 'PBT'); should(data[0]).have.property('mineral', '0'); should(data[0]).have.property('glass_fiber', '30'); should(data[0]).have.property('carbon_fiber', '0'); diff --git a/src/routes/material.ts b/src/routes/material.ts index efdd38b..2d95607 100644 --- a/src/routes/material.ts +++ b/src/routes/material.ts @@ -4,8 +4,8 @@ import _ from 'lodash'; import MaterialValidate from './validate/material'; import MaterialModel from '../models/material' import SampleModel from '../models/sample'; -import MaterialGroupsModel from '../models/material_groups'; -import MaterialSuppliersModel from '../models/material_suppliers'; +import MaterialGroupModel from '../models/material_groups'; +import MaterialSupplierModel from '../models/material_suppliers'; import IdValidate from './validate/id'; import res400 from './validate/res400'; import mongoose from 'mongoose'; @@ -20,11 +20,7 @@ router.get('/materials', (req, res, next) => { MaterialModel.find({status:globals.status.validated}).populate('group_id').populate('supplier_id').lean().exec((err, data) => { if (err) return next(err); - console.log(data); - data.forEach((material: any) => { // map group and supplier - material.group = material.group_id.name; - material.supplier = material.supplier_id.name; - }); + res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors }); }); @@ -34,10 +30,7 @@ router.get('/materials/:state(new|deleted)', (req, res, next) => { MaterialModel.find({status: globals.status[req.params.state]}).populate('group_id').populate('supplier_id').lean().exec((err, data) => { if (err) return next(err); - data.forEach((material: any) => { // map group and supplier - material.group = material.group_id.name; - material.supplier = material.supplier_id.name; - }); + res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors }); }); @@ -52,8 +45,6 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => { return res.status(404).json({status: 'Not found'}); } - data.group = data.group_id.name; - data.supplier = data.supplier_id.name; if (data.status === globals.status.deleted && !req.auth(res, ['maintain', 'admin'], 'all')) return; // deleted materials only available for maintain/admin res.json(MaterialValidate.output(data)); }); @@ -62,7 +53,7 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => { router.put('/material/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return; - const {error, value: material} = MaterialValidate.input(req.body, 'change'); + let {error, value: material} = MaterialValidate.input(req.body, 'change'); if (error) return res400(error, res); MaterialModel.findById(req.params.id).lean().exec(async (err, materialData: any) => { @@ -75,13 +66,21 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => { if (material.hasOwnProperty('name') && material.name !== materialData.name) { if (!await nameCheck(material, res, next)) return; } + if (material.hasOwnProperty('group')) { + material = await groupResolve(material, next); + if (!material) return; + } + if (material.hasOwnProperty('supplier')) { + material = await supplierResolve(material, next); + if (!material) return; + } // check for changes - if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), material)) { + if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), IdValidate.stringify(material))) { material.status = globals.status.new; // set status to new } - await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).lean().exec((err, data) => { + await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true}).populate('group_id').populate('supplier_id').lean().exec((err, data) => { if (err) return next(err); res.json(MaterialValidate.output(data)); }); @@ -97,7 +96,7 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => { if (data.length) { return res.status(400).json({status: 'Material still in use'}); } - MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).lean().exec((err, data) => { + MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).populate('group_id').populate('supplier_id').lean().exec((err, data) => { if (err) return next(err); if (data) { res.json({status: 'OK'}); @@ -122,17 +121,24 @@ router.put('/material/restore/' + IdValidate.parameter(), (req, res, next) => { }); }); -router.post('/material/new', async (req, res, next) => { // TODO: check supplier and group, also for PUT and DELETE +router.post('/material/new', async (req, res, next) => { if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return; - const {error, value: material} = MaterialValidate.input(req.body, 'new'); + let {error, value: material} = MaterialValidate.input(req.body, 'new'); if (error) return res400(error, res); if (!await nameCheck(material, res, next)) return; + material = await groupResolve(material, next); + if (!material) return; + material = await supplierResolve(material, next); + if (!material) return; + material.status = globals.status.new; // set status to new - await new MaterialModel(material).save((err, data) => { + await new MaterialModel(material).save(async (err, data) => { if (err) return next(err); + await data.populate('group_id').populate('supplier_id').execPopulate().catch(err => next(err)); + if (data instanceof Error) return; res.json(MaterialValidate.output(data.toObject())); }); }); @@ -140,7 +146,7 @@ router.post('/material/new', async (req, res, next) => { // TODO: check supplie router.get('/material/groups', (req, res, next) => { if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return; - MaterialGroupsModel.find().lean().exec((err, data: any) => { + MaterialGroupModel.find().lean().exec((err, data: any) => { if (err) return next(err); res.json(_.compact(data.map(e => MaterialValidate.outputGroups(e.name)))); // validate all and filter null values from validation errors @@ -150,7 +156,7 @@ router.get('/material/groups', (req, res, next) => { router.get('/material/suppliers', (req, res, next) => { if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return; - MaterialSuppliersModel.find().lean().exec((err, data: any) => { + MaterialSupplierModel.find().lean().exec((err, data: any) => { if (err) return next(err); res.json(_.compact(data.map(e => MaterialValidate.outputSuppliers(e.name)))); // validate all and filter null values from validation errors @@ -169,4 +175,20 @@ async function nameCheck (material, res, next) { // check if name was already t return false; } return true; +} + +async function groupResolve (material, next) { + const groupData = await MaterialGroupModel.findOneAndUpdate({name: material.group}, {name: material.group}, {upsert: true, new: true}).lean().exec().catch(err => next(err)) as any; + if (groupData instanceof Error) return false; + material.group_id = groupData._id; + delete material.group; + return material; +} + +async function supplierResolve (material, next) { + const supplierData = await MaterialSupplierModel.findOneAndUpdate({name: material.supplier}, {name: material.supplier}, {upsert: true, new: true}).lean().exec().catch(err => next(err)) as any; + if (supplierData instanceof Error) return false; + material.supplier_id = supplierData._id; + delete material.supplier; + return material; } \ No newline at end of file diff --git a/src/routes/template.spec.ts b/src/routes/template.spec.ts index 54adfcb..7f07d1d 100644 --- a/src/routes/template.spec.ts +++ b/src/routes/template.spec.ts @@ -5,7 +5,6 @@ import TemplateMeasurementModel from '../models/measurement_template'; import TestHelper from "../test/helper"; // TODO: do not allow usage of old templates for new samples -// TODO: remove number_prefix // TODO: template parameters are not allowed to be condition_template describe('/template', () => { diff --git a/src/routes/validate/material.ts b/src/routes/validate/material.ts index 225391a..7a2c3fb 100644 --- a/src/routes/validate/material.ts +++ b/src/routes/validate/material.ts @@ -70,6 +70,8 @@ export default class MaterialValidate { // validate input for material static output (data) { // validate output and strip unwanted properties, returns null if not valid data = IdValidate.stringify(data); + data.group = data.group_id.name; + data.supplier = data.supplier_id.name; const {value, error} = Joi.object({ _id: IdValidate.get(), name: this.material.name,