Archived
2

separated groups and suppliers for material GET

This commit is contained in:
VLE2FE 2020-05-28 17:05:23 +02:00
parent c7d25bd7cb
commit 14ba1655ba
13 changed files with 291 additions and 33 deletions

View File

@ -19,9 +19,9 @@
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
/materials/{group}: /materials/{state}:
parameters: parameters:
- $ref: 'api.yaml#/components/parameters/Group' - $ref: 'api.yaml#/components/parameters/State'
get: get:
summary: lists all new/deleted materials summary: lists all new/deleted materials
description: 'Auth: basic, levels: maintain, admin' description: 'Auth: basic, levels: maintain, admin'
@ -168,5 +168,51 @@
$ref: 'api.yaml#/components/responses/401' $ref: 'api.yaml#/components/responses/401'
403: 403:
$ref: 'api.yaml#/components/responses/403' $ref: 'api.yaml#/components/responses/403'
500:
$ref: 'api.yaml#/components/responses/500'
/material/groups:
get:
summary: list all existing material groups
description: 'Auth: all, levels: read, write, maintain, dev, admin'
tags:
- /material
responses:
200:
description: all material groups
content:
application/json:
schema:
type: array
items:
type: string
example: PA66
401:
$ref: 'api.yaml#/components/responses/401'
403:
$ref: 'api.yaml#/components/responses/403'
500:
$ref: 'api.yaml#/components/responses/500'
/material/suppliers:
get:
summary: list all existing material suppliers
description: 'Auth: all, levels: read, write, maintain, dev, admin'
tags:
- /material
responses:
200:
description: all material suppliers
content:
application/json:
schema:
type: array
items:
type: string
example: BASF
401:
$ref: 'api.yaml#/components/responses/401'
403:
$ref: 'api.yaml#/components/responses/403'
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'

View File

@ -14,7 +14,7 @@ Name:
schema: schema:
type: string type: string
Group: State:
name: group name: group
description: 'possible values: new, deleted' description: 'possible values: new, deleted'
in: path in: path

View File

@ -19,9 +19,9 @@
500: 500:
$ref: 'api.yaml#/components/responses/500' $ref: 'api.yaml#/components/responses/500'
/samples/{group}: /samples/{state}:
parameters: parameters:
- $ref: 'api.yaml#/components/parameters/Group' - $ref: 'api.yaml#/components/parameters/State'
get: get:
summary: all new/deleted samples in overview summary: all new/deleted samples in overview
description: 'Auth: basic, levels: maintain, admin' description: 'Auth: basic, levels: maintain, admin'

View File

@ -1,9 +1,11 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import MaterialSupplierModel from '../models/material_suppliers';
import MaterialGroupsModel from '../models/material_groups';
const MaterialSchema = new mongoose.Schema({ const MaterialSchema = new mongoose.Schema({
name: {type: String, index: {unique: true}}, name: {type: String, index: {unique: true}},
supplier: String, supplier_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialSupplierModel},
group: String, group_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialGroupsModel},
mineral: String, mineral: String,
glass_fiber: String, glass_fiber: String,
carbon_fiber: String, carbon_fiber: String,

View File

@ -0,0 +1,7 @@
import mongoose from 'mongoose';
const MaterialGroupsSchema = new mongoose.Schema({
name: {type: String, index: {unique: true}}
});
export default mongoose.model('material_groups', MaterialGroupsSchema);

View File

@ -0,0 +1,7 @@
import mongoose from 'mongoose';
const MaterialSuppliersSchema = new mongoose.Schema({
name: {type: String, index: {unique: true}}
});
export default mongoose.model('material_suppliers', MaterialSuppliersSchema);

View File

@ -4,7 +4,6 @@ import MaterialModel from '../models/material';
import TestHelper from "../test/helper"; import TestHelper from "../test/helper";
import globals from '../globals'; import globals from '../globals';
// TODO: color name must be unique to get color number
// TODO: separate supplier/ material name into own collections // TODO: separate supplier/ material name into own collections
describe('/material', () => { describe('/material', () => {
@ -80,7 +79,7 @@ describe('/material', () => {
}); });
}); });
describe('GET /materials/{group}', () => { describe('GET /materials/{state}', () => {
it('returns all new materials', done => { it('returns all new materials', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',
@ -767,4 +766,92 @@ describe('/material', () => {
}); });
}); });
}); });
describe('GET /material/groups', () => {
it('returns all groups', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/groups',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.material_groups.length);
should(res.body[0]).be.eql(json.collections.material_groups[0].name);
should(res.body).matchEach(group => {
should(group).be.type('string');
});
done();
});
});
it('works with an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/groups',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.material_groups.length);
should(res.body[0]).be.eql(json.collections.material_groups[0].name);
should(res.body).matchEach(group => {
should(group).be.type('string');
});
done();
});
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/groups',
httpStatus: 401
});
});
});
describe('GET /material/suppliers', () => {
it('returns all suppliers', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/suppliers',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.material_suppliers.length);
should(res.body[0]).be.eql(json.collections.material_suppliers[0].name);
should(res.body).matchEach(supplier => {
should(supplier).be.type('string');
});
done();
});
});
it('works with an API key', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/suppliers',
auth: {key: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.material_suppliers.length);
should(res.body[0]).be.eql(json.collections.material_suppliers[0].name);
should(res.body).matchEach(supplier => {
should(supplier).be.type('string');
});
done();
});
});
it('rejects unauthorized requests', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/material/suppliers',
httpStatus: 401
});
});
});
}); });

View File

@ -4,6 +4,8 @@ import _ from 'lodash';
import MaterialValidate from './validate/material'; import MaterialValidate from './validate/material';
import MaterialModel from '../models/material' import MaterialModel from '../models/material'
import SampleModel from '../models/sample'; import SampleModel from '../models/sample';
import MaterialGroupsModel from '../models/material_groups';
import MaterialSuppliersModel from '../models/material_suppliers';
import IdValidate from './validate/id'; import IdValidate from './validate/id';
import res400 from './validate/res400'; import res400 from './validate/res400';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
@ -16,17 +18,26 @@ const router = express.Router();
router.get('/materials', (req, res, next) => { router.get('/materials', (req, res, next) => {
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return; if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
MaterialModel.find({status:globals.status.validated}).lean().exec((err, data) => { MaterialModel.find({status:globals.status.validated}).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err); 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 res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
}); });
}); });
router.get('/materials/:group(new|deleted)', (req, res, next) => { router.get('/materials/:state(new|deleted)', (req, res, next) => {
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return; if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
MaterialModel.find({status: globals.status[req.params.group]}).lean().exec((err, data) => { MaterialModel.find({status: globals.status[req.params.state]}).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err); 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 res.json(_.compact(data.map(e => MaterialValidate.output(e)))); // validate all and filter null values from validation errors
}); });
}); });
@ -34,12 +45,15 @@ router.get('/materials/:group(new|deleted)', (req, res, next) => {
router.get('/material/' + IdValidate.parameter(), (req, res, next) => { router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return; if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
MaterialModel.findById(req.params.id).lean().exec((err, data: any) => { MaterialModel.findById(req.params.id).populate('group_id').populate('supplier_id').lean().exec((err, data: any) => {
if (err) return next(err); if (err) return next(err);
if (!data) { if (!data) {
return res.status(404).json({status: 'Not found'}); 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 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)); res.json(MaterialValidate.output(data));
}); });
@ -108,7 +122,7 @@ router.put('/material/restore/' + IdValidate.parameter(), (req, res, next) => {
}); });
}); });
router.post('/material/new', async (req, res, next) => { router.post('/material/new', async (req, res, next) => { // TODO: check supplier and group, also for PUT and DELETE
if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return; if (!req.auth(res, ['write', 'maintain', 'dev', 'admin'], 'basic')) return;
const {error, value: material} = MaterialValidate.input(req.body, 'new'); const {error, value: material} = MaterialValidate.input(req.body, 'new');
@ -123,6 +137,26 @@ router.post('/material/new', async (req, res, next) => {
}); });
}); });
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) => {
if (err) return next(err);
res.json(_.compact(data.map(e => MaterialValidate.outputGroups(e.name)))); // validate all and filter null values from validation errors
});
});
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) => {
if (err) return next(err);
res.json(_.compact(data.map(e => MaterialValidate.outputSuppliers(e.name)))); // validate all and filter null values from validation errors
});
});
module.exports = router; module.exports = router;

View File

@ -3,6 +3,7 @@ import MeasurementModel from '../models/measurement';
import TestHelper from "../test/helper"; import TestHelper from "../test/helper";
import globals from '../globals'; import globals from '../globals';
// TODO: test unique material names and produced error code
describe('/measurement', () => { describe('/measurement', () => {
let server; let server;

View File

@ -84,7 +84,7 @@ describe('/sample', () => {
}); });
}); });
describe('GET /samples/{group}', () => { describe('GET /samples/{state}', () => {
it('returns all new samples', done => { it('returns all new samples', done => {
TestHelper.request(server, done, { TestHelper.request(server, done, {
method: 'get', method: 'get',

View File

@ -27,10 +27,10 @@ router.get('/samples', (req, res, next) => {
}) })
}); });
router.get('/samples/:group(new|deleted)', (req, res, next) => { router.get('/samples/:state(new|deleted)', (req, res, next) => {
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return; if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
SampleModel.find({status: globals.status[req.params.group]}).lean().exec((err, data) => { SampleModel.find({status: globals.status[req.params.state]}).lean().exec((err, data) => {
if (err) return next(err); if (err) return next(err);
res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors res.json(_.compact(data.map(e => SampleValidate.output(e)))); // validate all and filter null values from validation errors
}); });

View File

@ -83,6 +83,16 @@ export default class MaterialValidate { // validate input for material
return error !== undefined? null : value; return error !== undefined? null : value;
} }
static outputGroups (data) {// validate groups output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.group.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputSuppliers (data) {// validate suppliers output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.supplier.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputV() { // return output validator static outputV() { // return output validator
return Joi.object({ return Joi.object({
_id: IdValidate.get(), _id: IdValidate.get(),

View File

@ -149,8 +149,8 @@
{ {
"_id": {"$oid":"100000000000000000000001"}, "_id": {"$oid":"100000000000000000000001"},
"name": "Stanyl TW 200 F8", "name": "Stanyl TW 200 F8",
"supplier": "DSM", "supplier_id": {"$oid":"110000000000000000000001"},
"group": "PA46", "group_id": {"$oid":"900000000000000000000001"},
"mineral": 0, "mineral": 0,
"glass_fiber": 40, "glass_fiber": 40,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -170,8 +170,8 @@
{ {
"_id": {"$oid":"100000000000000000000002"}, "_id": {"$oid":"100000000000000000000002"},
"name": "Ultramid T KR 4355 G7", "name": "Ultramid T KR 4355 G7",
"supplier": "BASF", "supplier_id": {"$oid":"110000000000000000000002"},
"group": "PA6/6T", "group_id": {"$oid":"900000000000000000000002"},
"mineral": 0, "mineral": 0,
"glass_fiber": 35, "glass_fiber": 35,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -191,8 +191,8 @@
{ {
"_id": {"$oid":"100000000000000000000003"}, "_id": {"$oid":"100000000000000000000003"},
"name": "PA GF 50 black (2706)", "name": "PA GF 50 black (2706)",
"supplier": "Akro-Plastic", "supplier_id": {"$oid":"110000000000000000000003"},
"group": "PA66+PA6I/6T", "group_id": {"$oid":"900000000000000000000003"},
"mineral": 0, "mineral": 0,
"glass_fiber": 0, "glass_fiber": 0,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -204,8 +204,8 @@
{ {
"_id": {"$oid":"100000000000000000000004"}, "_id": {"$oid":"100000000000000000000004"},
"name": "Schulamid 66 GF 25 H", "name": "Schulamid 66 GF 25 H",
"supplier": "Schulmann", "supplier_id": {"$oid":"110000000000000000000004"},
"group": "PA66", "group_id": {"$oid":"900000000000000000000004"},
"mineral": 0, "mineral": 0,
"glass_fiber": 25, "glass_fiber": 25,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -221,8 +221,8 @@
{ {
"_id": {"$oid":"100000000000000000000005"}, "_id": {"$oid":"100000000000000000000005"},
"name": "Amodel A 1133 HS", "name": "Amodel A 1133 HS",
"supplier": "Solvay", "supplier_id": {"$oid":"110000000000000000000005"},
"group": "PPA", "group_id": {"$oid":"900000000000000000000005"},
"mineral": 0, "mineral": 0,
"glass_fiber": 33, "glass_fiber": 33,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -238,8 +238,8 @@
{ {
"_id": {"$oid":"100000000000000000000006"}, "_id": {"$oid":"100000000000000000000006"},
"name": "PK-HM natural (4773)", "name": "PK-HM natural (4773)",
"supplier": "Akro-Plastic", "supplier_id": {"$oid":"110000000000000000000003"},
"group": "PK", "group_id": {"$oid":"900000000000000000000006"},
"mineral": 0, "mineral": 0,
"glass_fiber": 0, "glass_fiber": 0,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -255,8 +255,8 @@
{ {
"_id": {"$oid":"100000000000000000000007"}, "_id": {"$oid":"100000000000000000000007"},
"name": "Ultramid A4H", "name": "Ultramid A4H",
"supplier": "BASF", "supplier_id": {"$oid":"110000000000000000000002"},
"group": "PA66", "group_id": {"$oid":"900000000000000000000004"},
"mineral": 0, "mineral": 0,
"glass_fiber": 0, "glass_fiber": 0,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -272,8 +272,8 @@
{ {
"_id": {"$oid":"100000000000000000000008"}, "_id": {"$oid":"100000000000000000000008"},
"name": "Latamid 66 H 2 G 30", "name": "Latamid 66 H 2 G 30",
"supplier": "LATI", "supplier_id": {"$oid":"110000000000000000000006"},
"group": "PA66", "group_id": {"$oid":"900000000000000000000004"},
"mineral": 0, "mineral": 0,
"glass_fiber": 30, "glass_fiber": 30,
"carbon_fiber": 0, "carbon_fiber": 0,
@ -287,6 +287,70 @@
"__v": 0 "__v": 0
} }
], ],
"material_groups": [
{
"_id": {"$oid":"900000000000000000000001"},
"name": "PA46",
"__v": 0
},
{
"_id": {"$oid":"900000000000000000000002"},
"name": "PA6/6T",
"__v": 0
},
{
"_id": {"$oid":"900000000000000000000003"},
"name": "PA66+PA6I/6T",
"__v": 0
},
{
"_id": {"$oid":"900000000000000000000004"},
"name": "PA66",
"__v": 0
},
{
"_id": {"$oid":"900000000000000000000005"},
"name": "PPA",
"__v": 0
},
{
"_id": {"$oid":"900000000000000000000006"},
"name": "PK",
"__v": 0
}
],
"material_suppliers": [
{
"_id": {"$oid":"110000000000000000000001"},
"name": "DSM",
"__v": 0
},
{
"_id": {"$oid":"110000000000000000000002"},
"name": "BASF",
"__v": 0
},
{
"_id": {"$oid":"110000000000000000000003"},
"name": "Akro-Plastic",
"__v": 0
},
{
"_id": {"$oid":"110000000000000000000004"},
"name": "Schulmann",
"__v": 0
},
{
"_id": {"$oid":"110000000000000000000005"},
"name": "Solvay",
"__v": 0
},
{
"_id": {"$oid":"110000000000000000000006"},
"name": "LATI",
"__v": 0
}
],
"measurements": [ "measurements": [
{ {
"_id": {"$oid":"800000000000000000000001"}, "_id": {"$oid":"800000000000000000000001"},