restructured material
This commit is contained in:
parent
e976d45ded
commit
78d35c520e
@ -15,10 +15,19 @@ Name:
|
||||
type: string
|
||||
|
||||
State:
|
||||
name: group
|
||||
name: state
|
||||
description: 'possible values: new, deleted'
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: deleted
|
||||
|
||||
Collection:
|
||||
name: collection
|
||||
description: 'possible values: condition, measurement, material'
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: condition
|
@ -115,23 +115,19 @@ Material:
|
||||
group:
|
||||
type: string
|
||||
example: PA46
|
||||
mineral:
|
||||
type: number
|
||||
example: 0
|
||||
glass_fiber:
|
||||
type: number
|
||||
example: 40
|
||||
carbon_fiber:
|
||||
type: number
|
||||
example: 0
|
||||
properties:
|
||||
type: object
|
||||
properties:
|
||||
material_template:
|
||||
$ref: 'api.yaml#/components/schemas/Id'
|
||||
example:
|
||||
condition_template: 5ea0450ed851c30a90e70894
|
||||
mineral: 0
|
||||
glass_fiber: 40
|
||||
carbon_fiber: 0
|
||||
numbers:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: 'api.yaml#/components/schemas/Color'
|
||||
properties:
|
||||
number:
|
||||
type: string
|
||||
example: 5514263423
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
/template/conditions:
|
||||
/template/{collection}s:
|
||||
parameters:
|
||||
- $ref: 'api.yaml#/components/parameters/Collection'
|
||||
get:
|
||||
summary: all available condition methods
|
||||
summary: all available templates
|
||||
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||
tags:
|
||||
- /template
|
||||
@ -8,7 +10,7 @@
|
||||
- BasicAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: list of conditions
|
||||
description: list of templates
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -20,11 +22,12 @@
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
|
||||
/template/condition/{id}:
|
||||
/template/{collection}/{id}:
|
||||
parameters:
|
||||
- $ref: 'api.yaml#/components/parameters/Collection'
|
||||
- $ref: 'api.yaml#/components/parameters/Id'
|
||||
get:
|
||||
summary: condition method details
|
||||
summary: template details
|
||||
description: 'Auth: basic, levels: read, write, maintain, admin'
|
||||
tags:
|
||||
- /template
|
||||
@ -32,7 +35,7 @@
|
||||
- BasicAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: condition details
|
||||
description: template details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -44,7 +47,7 @@
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
put:
|
||||
summary: change condition method
|
||||
summary: change template
|
||||
description: 'Auth: basic, levels: maintain, admin'
|
||||
x-doc: With a change a new version is set, resulting in a new template with a new id
|
||||
tags:
|
||||
@ -59,7 +62,7 @@
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
responses:
|
||||
200:
|
||||
description: condition details
|
||||
description: template details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@ -75,116 +78,11 @@
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
|
||||
/template/condition/new:
|
||||
post:
|
||||
summary: add condition method
|
||||
description: 'Auth: basic, levels: maintain, admin'
|
||||
tags:
|
||||
- /template
|
||||
security:
|
||||
- BasicAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
responses:
|
||||
200:
|
||||
description: condition details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
400:
|
||||
$ref: 'api.yaml#/components/responses/400'
|
||||
401:
|
||||
$ref: 'api.yaml#/components/responses/401'
|
||||
403:
|
||||
$ref: 'api.yaml#/components/responses/403'
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
|
||||
/template/measurements:
|
||||
get:
|
||||
summary: all available measurement methods
|
||||
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||
tags:
|
||||
- /template
|
||||
security:
|
||||
- BasicAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: list of measurement methods
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
401:
|
||||
$ref: 'api.yaml#/components/responses/401'
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
/template/measurement/{id}:
|
||||
/template/{collection}/new:
|
||||
parameters:
|
||||
- $ref: 'api.yaml#/components/parameters/Id'
|
||||
get:
|
||||
summary: measurement method details
|
||||
description: 'Auth: basic, levels: read, write, maintain, admin'
|
||||
tags:
|
||||
- /template
|
||||
security:
|
||||
- BasicAuth: []
|
||||
responses:
|
||||
200:
|
||||
description: measurement details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
400:
|
||||
$ref: 'api.yaml#/components/responses/400'
|
||||
401:
|
||||
$ref: 'api.yaml#/components/responses/401'
|
||||
404:
|
||||
$ref: 'api.yaml#/components/responses/404'
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
put:
|
||||
summary: change measurement method
|
||||
description: 'Auth: basic, levels: maintain, admin'
|
||||
tags:
|
||||
- /template
|
||||
security:
|
||||
- BasicAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
responses:
|
||||
200:
|
||||
description: measurement details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
400:
|
||||
$ref: 'api.yaml#/components/responses/400'
|
||||
401:
|
||||
$ref: 'api.yaml#/components/responses/401'
|
||||
403:
|
||||
$ref: 'api.yaml#/components/responses/403'
|
||||
404:
|
||||
$ref: 'api.yaml#/components/responses/404'
|
||||
500:
|
||||
$ref: 'api.yaml#/components/responses/500'
|
||||
|
||||
/template/measurement/new:
|
||||
- $ref: 'api.yaml#/components/parameters/Collection'
|
||||
post:
|
||||
summary: add measurement method
|
||||
summary: add template
|
||||
description: 'Auth: basic, levels: maintain, admin'
|
||||
tags:
|
||||
- /template
|
||||
@ -198,7 +96,7 @@
|
||||
$ref: 'api.yaml#/components/schemas/Template'
|
||||
responses:
|
||||
200:
|
||||
description: measurement details
|
||||
description: template details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
|
@ -7,13 +7,8 @@ const MaterialSchema = new mongoose.Schema({
|
||||
name: {type: String, index: {unique: true}},
|
||||
supplier_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialSupplierModel},
|
||||
group_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialGroupsModel},
|
||||
mineral: Number,
|
||||
glass_fiber: Number,
|
||||
carbon_fiber: Number,
|
||||
numbers: [{
|
||||
color: String,
|
||||
number: String
|
||||
}],
|
||||
properties: mongoose.Schema.Types.Mixed,
|
||||
numbers: [String],
|
||||
status: Number
|
||||
}, {minimize: false});
|
||||
|
||||
|
20
src/models/material_template.ts
Normal file
20
src/models/material_template.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import mongoose from 'mongoose';
|
||||
import db from '../db';
|
||||
|
||||
const MaterialTemplateSchema = new mongoose.Schema({
|
||||
first_id: mongoose.Schema.Types.ObjectId,
|
||||
name: String,
|
||||
version: Number,
|
||||
parameters: [new mongoose.Schema({
|
||||
name: String,
|
||||
range: mongoose.Schema.Types.Mixed
|
||||
} ,{ _id : false })]
|
||||
}, {minimize: false}); // to allow empty objects
|
||||
|
||||
// changelog query helper
|
||||
MaterialTemplateSchema.query.log = function <Q extends mongoose.DocumentQuery<any, any>> (req) {
|
||||
db.log(req, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
export default mongoose.model<any, mongoose.Model<any, any>>('material_template', MaterialTemplateSchema);
|
@ -1,5 +1,4 @@
|
||||
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';
|
||||
@ -7,7 +6,6 @@ import TestHelper from "../test/helper";
|
||||
import globals from '../globals';
|
||||
|
||||
|
||||
|
||||
describe('/material', () => {
|
||||
let server;
|
||||
before(done => TestHelper.before(done));
|
||||
@ -27,19 +25,13 @@ describe('/material', () => {
|
||||
const json = require('../test/db.json');
|
||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === globals.status.validated).length);
|
||||
should(res.body).matchEach(material => {
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(material).have.property('_id').be.type('string');
|
||||
should(material).have.property('name').be.type('string');
|
||||
should(material).have.property('supplier').be.type('string');
|
||||
should(material).have.property('group').be.type('string');
|
||||
should(material).have.property('mineral').be.type('number');
|
||||
should(material).have.property('glass_fiber').be.type('number');
|
||||
should(material).have.property('carbon_fiber').be.type('number');
|
||||
should(material.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color').be.type('string');
|
||||
should(number).have.property('number').be.type('string');
|
||||
});
|
||||
should(material.properties).have.property('material_template').be.type('string');
|
||||
should(material.numbers).be.instanceof(Array);
|
||||
});
|
||||
done();
|
||||
});
|
||||
@ -55,19 +47,13 @@ describe('/material', () => {
|
||||
const json = require('../test/db.json');
|
||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === globals.status.validated).length);
|
||||
should(res.body).matchEach(material => {
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(material).have.property('_id').be.type('string');
|
||||
should(material).have.property('name').be.type('string');
|
||||
should(material).have.property('supplier').be.type('string');
|
||||
should(material).have.property('group').be.type('string');
|
||||
should(material).have.property('mineral').be.type('number');
|
||||
should(material).have.property('glass_fiber').be.type('number');
|
||||
should(material).have.property('carbon_fiber').be.type('number');
|
||||
should(material.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color').be.type('string');
|
||||
should(number).have.property('number').be.type('string');
|
||||
});
|
||||
should(material.properties).have.property('material_template').be.type('string');
|
||||
should(material.numbers).be.instanceof(Array);
|
||||
});
|
||||
done();
|
||||
});
|
||||
@ -83,19 +69,13 @@ describe('/material', () => {
|
||||
const json = require('../test/db.json');
|
||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === globals.status.new).length);
|
||||
should(res.body).matchEach(material => {
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(material).have.property('_id').be.type('string');
|
||||
should(material).have.property('name').be.type('string');
|
||||
should(material).have.property('supplier').be.type('string');
|
||||
should(material).have.property('group').be.type('string');
|
||||
should(material).have.property('mineral').be.type('number');
|
||||
should(material).have.property('glass_fiber').be.type('number');
|
||||
should(material).have.property('carbon_fiber').be.type('number');
|
||||
should(material.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color').be.type('string');
|
||||
should(number).have.property('number').be.type('string');
|
||||
});
|
||||
should(material.properties).have.property('material_template').be.type('string');
|
||||
should(material.numbers).be.instanceof(Array);
|
||||
});
|
||||
done();
|
||||
});
|
||||
@ -131,19 +111,13 @@ describe('/material', () => {
|
||||
let asyncCounter = res.body.length;
|
||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.new).length);
|
||||
should(res.body).matchEach(material => {
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(material).have.property('_id').be.type('string');
|
||||
should(material).have.property('name').be.type('string');
|
||||
should(material).have.property('supplier').be.type('string');
|
||||
should(material).have.property('group').be.type('string');
|
||||
should(material).have.property('mineral').be.type('number');
|
||||
should(material).have.property('glass_fiber').be.type('number');
|
||||
should(material).have.property('carbon_fiber').be.type('number');
|
||||
should(material.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color').be.type('string');
|
||||
should(number).have.property('number').be.type('string');
|
||||
});
|
||||
should(material.properties).have.property('material_template').be.type('string');
|
||||
should(material.numbers).be.instanceof(Array);
|
||||
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
||||
should(data).have.property('status',globals.status.new);
|
||||
if (--asyncCounter === 0) {
|
||||
@ -165,19 +139,13 @@ describe('/material', () => {
|
||||
let asyncCounter = res.body.length;
|
||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.deleted).length);
|
||||
should(res.body).matchEach(material => {
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(material).have.property('_id').be.type('string');
|
||||
should(material).have.property('name').be.type('string');
|
||||
should(material).have.property('supplier').be.type('string');
|
||||
should(material).have.property('group').be.type('string');
|
||||
should(material).have.property('mineral').be.type('number');
|
||||
should(material).have.property('glass_fiber').be.type('number');
|
||||
should(material).have.property('carbon_fiber').be.type('number');
|
||||
should(material.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color').be.type('string');
|
||||
should(number).have.property('number').be.type('string');
|
||||
});
|
||||
should(material.properties).have.property('material_template').be.type('string');
|
||||
should(material.numbers).be.instanceof(Array);
|
||||
MaterialModel.findById(material._id).lean().exec((err, data) => {
|
||||
should(data).have.property('status',globals.status.deleted);
|
||||
if (--asyncCounter === 0) {
|
||||
@ -219,7 +187,7 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]}
|
||||
res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']}
|
||||
});
|
||||
});
|
||||
it('returns the right material for an API key', done => {
|
||||
@ -228,7 +196,7 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000003',
|
||||
auth: {key: 'admin'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '100000000000000000000003', name: 'PA GF 50 black (2706)', supplier: 'Akro-Plastic', group: 'PA66+PA6I/6T', mineral: 0, glass_fiber: 0, carbon_fiber: 0, numbers: []}
|
||||
res: {_id: '100000000000000000000003', name: 'PA GF 50 black (2706)', supplier: 'Akro-Plastic', group: 'PA66+PA6I/6T', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 0, carbon_fiber: 0}, numbers: []}
|
||||
});
|
||||
});
|
||||
it('returns a material with a color without number', done => {
|
||||
@ -237,7 +205,7 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000007',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '100000000000000000000007', name: 'Ultramid A4H', supplier: 'BASF', group: 'PA66', mineral: 0, glass_fiber: 0, carbon_fiber: 0, numbers: [{color: 'black', number: ''}]}
|
||||
res: {_id: '100000000000000000000007', name: 'Ultramid A4H', supplier: 'BASF', group: 'PA66', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 0, carbon_fiber: 0}, numbers: []}
|
||||
});
|
||||
});
|
||||
it('returns a deleted material for a maintain/admin user', done => {
|
||||
@ -246,7 +214,7 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000008',
|
||||
auth: {basic: 'admin'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '100000000000000000000008', name: 'Latamid 66 H 2 G 30', supplier: 'LATI', group: 'PA66', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'blue', number: '5513943509'}]}
|
||||
res: {_id: '100000000000000000000008', name: 'Latamid 66 H 2 G 30', supplier: 'LATI', group: 'PA66', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: ['5513943509']}
|
||||
});
|
||||
});
|
||||
it('returns 403 for a write user when requesting a deleted material', done => {
|
||||
@ -290,7 +258,7 @@ describe('/material', () => {
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {},
|
||||
res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]}
|
||||
res: {_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']}
|
||||
});
|
||||
});
|
||||
it('keeps unchanged properties', done => {
|
||||
@ -299,10 +267,10 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]}
|
||||
req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']}
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']});
|
||||
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
||||
if (err) return done(err);
|
||||
should(data).have.property('status',globals.status.validated);
|
||||
@ -329,7 +297,24 @@ describe('/material', () => {
|
||||
req: {name: 'Stanyl TW 200 F8'}
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}, {color: 'natural', number: '5514263422'}]});
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']});
|
||||
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
||||
if (err) return done(err);
|
||||
should(data).have.property('status',globals.status.validated);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('keeps unchanged properties', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}}
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423', '5514263422']});
|
||||
MaterialModel.findById('100000000000000000000001').lean().exec((err, data) => {
|
||||
if (err) return done(err);
|
||||
should(data).have.property('status',globals.status.validated);
|
||||
@ -343,17 +328,16 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {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'}]}
|
||||
req: {name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 35, carbon_fiber: 0}, numbers: ['5514212901', '5514612901']}
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).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'}]});
|
||||
should(res.body).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 35, carbon_fiber: 0}, numbers: ['5514212901', '5514612901']});
|
||||
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_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});
|
||||
should(data).be.eql({_id: '100000000000000000000001', name: 'UltramidTKR4355G7_2', supplier_id: '110000000000000000000002', group_id: '900000000000000000000002', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 35, carbon_fiber: 0}, numbers: ['5514212901', '5514612901'], status: 0, __v: 0});
|
||||
MaterialGroupModel.find({name: 'PA6/6T'}).lean().exec((err, data) => {
|
||||
if (err) return done(err);
|
||||
should(data).have.lengthOf(1);
|
||||
@ -374,7 +358,7 @@ describe('/material', () => {
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {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'}]},
|
||||
req: {name: 'UltramidTKR4355G7_2', supplier: 'BASF', group: 'PA6/6T', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 35, carbon_fiber: 0}, numbers: ['5514212901', '5514612901']},
|
||||
log: {
|
||||
collection: 'materials',
|
||||
dataAdd: {
|
||||
@ -386,16 +370,6 @@ describe('/material', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
it('accepts a color without number', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000007',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {numbers: [{color: 'black', number: ''}, {color: 'natural', number: ''}]},
|
||||
res: {_id: '100000000000000000000007', name: 'Ultramid A4H', supplier: 'BASF', group: 'PA66', mineral: 0, glass_fiber: 0, carbon_fiber: 0, numbers: [{color: 'black', number: ''}, {color: 'natural', number: ''}]}
|
||||
});
|
||||
})
|
||||
it('rejects already existing material names', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
@ -406,46 +380,16 @@ describe('/material', () => {
|
||||
res: {status: 'Material name already taken'}
|
||||
});
|
||||
});
|
||||
it('rejects a wrong mineral property', done => {
|
||||
it('rejects wrong material properties', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {mineral: 'x'},
|
||||
req: {properties: {material_template: '130000000000000000000003', mineral: 'x', glass_fiber: 0, carbon_fiber: 0}},
|
||||
res: {status: 'Invalid body format', details: '"mineral" must be a number'}
|
||||
});
|
||||
});
|
||||
it('rejects a wrong glass_fiber property', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {glass_fiber: 'x'},
|
||||
res: {status: 'Invalid body format', details: '"glass_fiber" must be a number'}
|
||||
});
|
||||
});
|
||||
it('rejects a wrong carbon_fiber property', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {carbon_fiber: 'x'},
|
||||
res: {status: 'Invalid body format', details: '"carbon_fiber" must be a number'}
|
||||
});
|
||||
});
|
||||
it('rejects a wrong color name property', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {numbers: [{colorxx: 'black', number: '55'}]},
|
||||
res: {status: 'Invalid body format', details: '"numbers[0].color" is required'}
|
||||
});
|
||||
});
|
||||
it('rejects an invalid id', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
@ -455,6 +399,86 @@ describe('/material', () => {
|
||||
req: {},
|
||||
});
|
||||
});
|
||||
it('rejects not specified properties parameters', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 0, carbon_fiber: 0, x: 55}},
|
||||
res: {status: 'Invalid body format', details: '"x" is not allowed'}
|
||||
});
|
||||
});
|
||||
it('rejects a properties parameter not in the value range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000009',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '130000000000000000000002', stickiness: 'xx'}},
|
||||
res: {status: 'Invalid body format', details: '"stickiness" must be one of [not so sticky, medium, very sticky]'}
|
||||
});
|
||||
});
|
||||
it('rejects a properties parameter below minimum range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: -5, carbon_fiber: 0}},
|
||||
res: {status: 'Invalid body format', details: '"glass_fiber" must be larger than or equal to 0'}
|
||||
});
|
||||
});
|
||||
it('rejects a properties parameter above maximum range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 0, carbon_fiber: 105}},
|
||||
res: {status: 'Invalid body format', details: '"carbon_fiber" must be less than or equal to 100'}
|
||||
});
|
||||
});
|
||||
it('rejects an invalid material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '1300000000000h0000000001', mineral: 0, glass_fiber: 0, carbon_fiber: 0}},
|
||||
res: {status: 'Material template not available'}
|
||||
});
|
||||
});
|
||||
it('rejects an unknown material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '100000000000000000000001', mineral: 0, glass_fiber: 0, carbon_fiber: 0}},
|
||||
res: {status: 'Material template not available'}
|
||||
});
|
||||
});
|
||||
it('rejects an old version of a material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {properties: {material_template: '130000000000000000000001', glass_fiber: 0}},
|
||||
res: {status: 'Old template version not allowed'}
|
||||
});
|
||||
});
|
||||
it('allows keeping an old version of a material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/material/100000000000000000000010',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {properties: {material_template: '130000000000000000000001', glass_fiber: 5}},
|
||||
res: {_id: '100000000000000000000010', name: 'Latamid 66 G 40', numbers: ['5513943509'], supplier: 'LATI', group: 'PA66', properties: {material_template: '130000000000000000000001', glass_fiber: 5}}
|
||||
});
|
||||
});
|
||||
it('rejects editing a deleted material', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
@ -516,8 +540,8 @@ describe('/material', () => {
|
||||
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_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}
|
||||
data.properties.material_template = data.properties.material_template.toString();
|
||||
should(data).be.eql({_id: '100000000000000000000002', name: 'Ultramid T KR 4355 G7', supplier_id: '110000000000000000000002', group_id: '900000000000000000000002', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 35, carbon_fiber: 0}, numbers: ['5514212901', '5514612901'], status: -1, __v: 0}
|
||||
);
|
||||
done();
|
||||
});
|
||||
@ -732,22 +756,19 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: '05515798402'}]}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: ['5515798402']}
|
||||
}).end((err, res) => {
|
||||
if (err) return done (err);
|
||||
should(res.body).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(res.body).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
||||
should(res.body).have.property('_id').be.type('string');
|
||||
should(res.body).have.property('name', 'Crastin CE 2510');
|
||||
should(res.body).have.property('supplier', 'Du Pont');
|
||||
should(res.body).have.property('group', 'PBT');
|
||||
should(res.body).have.property('mineral', 0);
|
||||
should(res.body).have.property('glass_fiber', 30);
|
||||
should(res.body).have.property('carbon_fiber', 0);
|
||||
should(res.body.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color', 'black');
|
||||
should(number).have.property('number', '05515798402');
|
||||
});
|
||||
should(res.body.properties).have.property('material_template', '130000000000000000000003');
|
||||
should(res.body.properties).have.property('mineral', 0);
|
||||
should(res.body.properties).have.property('glass_fiber', 30);
|
||||
should(res.body.properties).have.property('carbon_fiber', 0);
|
||||
should(res.body).have.property('numbers', ['5515798402']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -757,17 +778,18 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', 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, materialData: any) => {
|
||||
if (err) return done (err);
|
||||
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.only.keys('_id', 'name', 'supplier_id', 'group_id', 'properties', '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].properties).have.property('material_template', '130000000000000000000003');
|
||||
should(materialData[0].properties).have.property('mineral', 0);
|
||||
should(materialData[0].properties).have.property('glass_fiber', 30);
|
||||
should(materialData[0].properties).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) => {
|
||||
@ -788,7 +810,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: []},
|
||||
log: {
|
||||
collection: 'materials',
|
||||
dataAdd: {status: 0},
|
||||
@ -796,50 +818,13 @@ describe('/material', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
it('accepts a color without number', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: ''}]}
|
||||
}).end((err, res) => {
|
||||
if (err) return done (err);
|
||||
should(res.body).have.only.keys('_id', 'name', 'supplier', 'group', 'mineral', 'glass_fiber', 'carbon_fiber', 'numbers');
|
||||
should(res.body).have.property('_id').be.type('string');
|
||||
should(res.body).have.property('name', 'Crastin CE 2510');
|
||||
should(res.body).have.property('supplier', 'Du Pont');
|
||||
should(res.body).have.property('group', 'PBT');
|
||||
should(res.body).have.property('mineral', 0);
|
||||
should(res.body).have.property('glass_fiber', 30);
|
||||
should(res.body).have.property('carbon_fiber', 0);
|
||||
should(res.body.numbers).matchEach(number => {
|
||||
should(number).have.only.keys('color', 'number');
|
||||
should(number).have.property('color', 'black');
|
||||
should(number).have.property('number', '');
|
||||
});
|
||||
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_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('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(_.omit(data[0].numbers[0], '_id')).be.eql({color: 'black', number: ''});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
it('rejects already existing material names', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', mineral: 0, glass_fiber: 40, carbon_fiber: 0, numbers: [{color: 'black', number: '5514263423'}]},
|
||||
req: {name: 'Stanyl TW 200 F8', supplier: 'DSM', group: 'PA46', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 40, carbon_fiber: 0}, numbers: ['5514263423']},
|
||||
res: {status: 'Material name already taken'}
|
||||
});
|
||||
});
|
||||
@ -849,7 +834,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"name" is required'}
|
||||
});
|
||||
});
|
||||
@ -859,7 +844,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {name: 'Crastin CE 2510', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"supplier" is required'}
|
||||
});
|
||||
});
|
||||
@ -869,7 +854,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"group" is required'}
|
||||
});
|
||||
});
|
||||
@ -879,7 +864,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', glass_fiber: 30, carbon_fiber: 0}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"mineral" is required'}
|
||||
});
|
||||
});
|
||||
@ -889,7 +874,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, carbon_fiber: 0, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, carbon_fiber: 0}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"glass_fiber" is required'}
|
||||
});
|
||||
});
|
||||
@ -899,7 +884,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, numbers: [{color: 'black', number: '5515798402'}]},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"carbon_fiber" is required'}
|
||||
});
|
||||
});
|
||||
@ -909,28 +894,78 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0},
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}},
|
||||
res: {status: 'Invalid body format', details: '"numbers" is required'}
|
||||
});
|
||||
});
|
||||
it('rejects a missing color name', done => {
|
||||
it('rejects not specified properties parameters', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{number: '5515798402'}]},
|
||||
res: {status: 'Invalid body format', details: '"numbers[0].color" is required'}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, carbon_fiber: 0, glass_fiber: 30, x: 47}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"x" is not allowed'}
|
||||
});
|
||||
});
|
||||
it('rejects a missing color number', done => {
|
||||
it('rejects a properties parameter not in the value range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: [{color: 'black'}]},
|
||||
res: {status: 'Invalid body format', details: '"numbers[0].number" is required'}
|
||||
req: {name: 'Glue2', supplier: 'BASF', group: 'Glue', properties: {material_template: '130000000000000000000002', stickiness: 'not so much'}, numbers: []},
|
||||
res: {status: 'Invalid body format', details: '"stickiness" must be one of [not so sticky, medium, very sticky]'}
|
||||
});
|
||||
});
|
||||
it('rejects a properties parameter below minimum range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', glass_fiber: -0.3}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"glass_fiber" must be larger than or equal to 0'}
|
||||
});
|
||||
});
|
||||
it('rejects a properties parameter above maximum range', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', glass_fiber: 100.001}, numbers: ['5515798402']},
|
||||
res: {status: 'Invalid body format', details: '"glass_fiber" must be less than or equal to 100'}
|
||||
});
|
||||
});
|
||||
it('rejects an invalid material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000h00000000000003', glass_fiber: 30}, numbers: ['5515798402']},
|
||||
res: {status: 'Material template not available'}
|
||||
});
|
||||
});
|
||||
it('rejects an unknown material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '100000000000000000000003', glass_fiber: 30}, numbers: ['5515798402']},
|
||||
res: {status: 'Material template not available'}
|
||||
});
|
||||
});
|
||||
it('rejects an old version of a material template', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000001', glass_fiber: 30}, numbers: ['5515798402']},
|
||||
res: {status: 'Old template version not allowed'}
|
||||
});
|
||||
});
|
||||
it('rejects an API key', done => {
|
||||
@ -939,7 +974,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {key: 'janedoe'},
|
||||
httpStatus: 401,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: []}
|
||||
});
|
||||
});
|
||||
it('rejects requests from a read user', done => {
|
||||
@ -948,7 +983,7 @@ describe('/material', () => {
|
||||
url: '/material/new',
|
||||
auth: {basic: 'user'},
|
||||
httpStatus: 403,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: []}
|
||||
});
|
||||
});
|
||||
it('rejects unauthorized requests', done => {
|
||||
@ -956,7 +991,7 @@ describe('/material', () => {
|
||||
method: 'post',
|
||||
url: '/material/new',
|
||||
httpStatus: 401,
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', mineral: 0, glass_fiber: 30, carbon_fiber: 0, numbers: []}
|
||||
req: {name: 'Crastin CE 2510', supplier: 'Du Pont', group: 'PBT', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 30, carbon_fiber: 0}, numbers: []}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -11,6 +11,8 @@ import res400 from './validate/res400';
|
||||
import mongoose from 'mongoose';
|
||||
import globals from '../globals';
|
||||
import db from '../db';
|
||||
import MaterialTemplateModel from '../models/material_template';
|
||||
import ParametersValidate from './validate/parameters';
|
||||
|
||||
|
||||
|
||||
@ -92,6 +94,9 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
|
||||
material = await supplierResolve(material, req, next);
|
||||
if (!material) return;
|
||||
}
|
||||
if (material.hasOwnProperty('properties')) {
|
||||
if (!await propertiesCheck(material.properties, 'change', res, next, materialData.properties.material_template.toString() !== material.properties.material_template)) return;
|
||||
}
|
||||
|
||||
// check for changes
|
||||
if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), IdValidate.stringify(material))) {
|
||||
@ -149,7 +154,7 @@ router.post('/material/new', async (req, res, next) => {
|
||||
if (!material) return;
|
||||
material = await supplierResolve(material, req, next);
|
||||
if (!material) return;
|
||||
|
||||
if (!await propertiesCheck(material.properties, 'new', res, next)) return;
|
||||
|
||||
material.status = globals.status.new; // set status to new
|
||||
await new MaterialModel(material).save(async (err, data) => {
|
||||
@ -211,6 +216,34 @@ async function supplierResolve (material, req, next) {
|
||||
return material;
|
||||
}
|
||||
|
||||
async function propertiesCheck (properties, param, res, next, checkVersion = true) { // validate material properties, returns false if invalid, otherwise template data
|
||||
if (!properties.material_template || !IdValidate.valid(properties.material_template)) { // template id not found
|
||||
res.status(400).json({status: 'Material template not available'});
|
||||
return false;
|
||||
}
|
||||
const materialData = await MaterialTemplateModel.findById(properties.material_template).lean().exec().catch(err => next(err)) as any;
|
||||
if (materialData instanceof Error) return false;
|
||||
if (!materialData) { // template not found
|
||||
res.status(400).json({status: 'Material template not available'});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkVersion) {
|
||||
// get all template versions and check if given is latest
|
||||
const materialVersions = await MaterialTemplateModel.find({first_id: materialData.first_id}).sort({version: -1}).lean().exec().catch(err => next(err)) as any;
|
||||
if (materialVersions instanceof Error) return false;
|
||||
if (properties.material_template !== materialVersions[0]._id.toString()) { // template not latest
|
||||
res.status(400).json({status: 'Old template version not allowed'});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// validate parameters
|
||||
const {error, value: ignore} = ParametersValidate.input(_.omit(properties, 'material_template'), materialData.parameters, param);
|
||||
if (error) {res400(error, res); return false;}
|
||||
return materialData;
|
||||
}
|
||||
|
||||
function setStatus (status, req, res, next) { // set measurement status
|
||||
MaterialModel.findByIdAndUpdate(req.params.id, {status: status}).log(req).lean().exec((err, data) => {
|
||||
if (err) return next(err);
|
||||
|
@ -600,7 +600,7 @@ describe('/measurement', () => {
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {sample_id: '400000000000h00000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '300000000000000000000002'},
|
||||
res: {status: 'Invalid body format', details: '"sample_id" with value "400000000000h00000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid object id'}
|
||||
});
|
||||
});
|
||||
it('rejects a sample id not available', done => {
|
||||
@ -620,7 +620,7 @@ describe('/measurement', () => {
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {sample_id: '400000000000000000000001', values: {'weight %': 0.8, 'standard deviation': 0.1}, measurement_template: '30000000000h000000000002'},
|
||||
res: {status: 'Invalid body format', details: '"measurement_template" with value "30000000000h000000000002" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid object id'}
|
||||
});
|
||||
});
|
||||
it('rejects a measurement_template not available', done => {
|
||||
|
@ -7,10 +7,9 @@ import TestHelper from "../test/helper";
|
||||
import globals from '../globals';
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
// TODO: generate output for ML in format DPT -> data, implement filtering, field selection
|
||||
// TODO: generate csv
|
||||
// TODO: write script for data import
|
||||
|
||||
// TODO: allowed types: tension rod, part, granulate, other
|
||||
// TODO: filter by conditions and material properties
|
||||
|
||||
describe('/sample', () => {
|
||||
let server;
|
||||
@ -262,14 +261,14 @@ describe('/sample', () => {
|
||||
it('multiplies the sample information for each spectrum', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/samples?status=all&fields[]=number&fields[]=measurements.spectrum',
|
||||
url: '/samples?status=all&fields[]=number&fields[]=measurements.spectrum.dpt',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).have.lengthOf(2);
|
||||
should(res.body[0]).have.property('spectrum', [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]);
|
||||
should(res.body[1]).have.property('spectrum', [[3996.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]);
|
||||
should(res.body[0].spectrum).have.property('dpt', [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]);
|
||||
should(res.body[1].spectrum).have.property('dpt', [[3996.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@ -338,16 +337,16 @@ describe('/sample', () => {
|
||||
it('filters multiple properties', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/samples?status=all&fields[]=number&fields[]=material.glass_fiber&fields[]=batch&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.glass_fiber%22%2C%22values%22%3A%5B33%5D%7D&filters[]=%7B%22mode%22%3A%22lte%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22Rng33%22%5D%7D&filters[]=%7B%22mode%22%3A%22nin%22%2C%22field%22%3A%22batch%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
|
||||
url: '/samples?status=all&fields[]=number&fields[]=batch&filters[]=%7B%22mode%22%3A%22lte%22%2C%22field%22%3A%22number%22%2C%22values%22%3A%5B%22Rng33%22%5D%7D&filters[]=%7B%22mode%22%3A%22nin%22%2C%22field%22%3A%22batch%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200
|
||||
}).end((err, res) => {
|
||||
if (err) return done(err);
|
||||
should(res.body).have.lengthOf(1);
|
||||
should(res.body[0]).be.eql({number: '32', material: {glass_fiber: 33}, batch: '1653000308'});
|
||||
should(res.body).have.lengthOf(3);
|
||||
should(res.body[0]).be.eql({number: '1', batch: ''});
|
||||
done();
|
||||
});
|
||||
}); // TODO: do measurement pipeline, check if it works with UI
|
||||
});
|
||||
it('rejects an invalid JSON string as a filters parameter', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
@ -372,7 +371,7 @@ describe('/sample', () => {
|
||||
url: '/samples?status=all&fields[]=number&fields[]=material.glass_fiber&fields[]=batch&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22xx%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
res: {status: 'Invalid body format', details: '"filters[0].field" with value "xx" fails to match the required pattern: /^(_id|color|number|type|batch|added|material\\.name|material\\.supplier|material\\.group|material\\.mineral|material\\.glass_fiber|material\\.carbon_fiber|material\\.number|measurements\\.(?!spectrum).+|condition|material_id|material|note_id|user_id|material\\._id|material\\.numbers|measurements\\.spectrum)$/m'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid JSON string for filter parameter'}
|
||||
});
|
||||
});
|
||||
it('rejects unknown measurement names', done => {
|
||||
@ -402,10 +401,10 @@ describe('/sample', () => {
|
||||
it('returns only the fields specified', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/samples?status=all&page-size=1&fields[]=number&fields[]=condition&fields[]=color&fields[]=material.name&fields[]=material.mineral',
|
||||
url: '/samples?status=all&page-size=1&fields[]=number&fields[]=condition&fields[]=color&fields[]=material.name&fields[]=material.supplier',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
res: [{number: '1', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, color: 'black', material: {name: 'Schulamid 66 GF 25 H', mineral: 0}}]
|
||||
res: [{number: '1', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, color: 'black', material: {name: 'Schulamid 66 GF 25 H', supplier: 'Schulmann'}}]
|
||||
});
|
||||
});
|
||||
it('rejects a from-id not in the database', done => {
|
||||
@ -432,7 +431,7 @@ describe('/sample', () => {
|
||||
url: '/samples?status=all&page-size=1&fields[]=xx',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
res: {status: 'Invalid body format', details: '"fields[0]" with value "xx" fails to match the required pattern: /^(_id|color|number|type|batch|added|material\\.name|material\\.supplier|material\\.group|material\\.mineral|material\\.glass_fiber|material\\.carbon_fiber|material\\.number|measurements\\.(?!spectrum).+|condition|material_id|material|note_id|user_id|material\\._id|material\\.numbers|measurements\\.spectrum)$/m'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid field name'}
|
||||
});
|
||||
});
|
||||
it('rejects a negative page size', done => {
|
||||
@ -450,7 +449,7 @@ describe('/sample', () => {
|
||||
url: '/samples?from-id=40000000000h000000000002',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
res: {status: 'Invalid body format', details: '"from-id" with value "40000000000h000000000002" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid object id'}
|
||||
});
|
||||
});
|
||||
it('rejects a to-page without page-size', done => {
|
||||
@ -619,7 +618,7 @@ describe('/sample', () => {
|
||||
url: '/sample/400000000000000000000003',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
|
||||
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
|
||||
});
|
||||
});
|
||||
it('works with an API key', done => {
|
||||
@ -628,7 +627,7 @@ describe('/sample', () => {
|
||||
url: '/sample/400000000000000000000003',
|
||||
auth: {key: 'janedoe'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
|
||||
res: {_id: '400000000000000000000003', number: '33', type: 'part', color: 'black', batch: '1704-005', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {comment: '', sample_references: [{sample_id: '400000000000000000000004', relation: 'granulate to sample'}], custom_fields: {'not allowed for new applications': true}}, measurements: [{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003'}], user: 'admin'}
|
||||
});
|
||||
});
|
||||
it('returns a deleted sample for a maintain/admin user', done => {
|
||||
@ -637,7 +636,7 @@ describe('/sample', () => {
|
||||
url: '/sample/400000000000000000000005',
|
||||
auth: {basic: 'admin'},
|
||||
httpStatus: 200,
|
||||
res: {_id: '400000000000000000000005', number: 'Rng33', type: 'granulate', color: 'black', batch: '1653000308', condition: {condition_template: '200000000000000000000003'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', mineral: 0, glass_fiber: 33, carbon_fiber: 0, numbers: [{color: 'black', number: '5514262406'}]}, notes: {}, measurements: [], user: 'admin'}
|
||||
res: {_id: '400000000000000000000005', number: 'Rng33', type: 'granulate', color: 'black', batch: '1653000308', condition: {condition_template: '200000000000000000000003'}, material: {_id: '100000000000000000000005', name: 'Amodel A 1133 HS', supplier: 'Solvay', group: 'PPA', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['5514262406']}, notes: {}, measurements: [], user: 'admin'}
|
||||
});
|
||||
});
|
||||
it('returns 403 for a write user when requesting a deleted sample', done => {
|
||||
@ -895,26 +894,6 @@ describe('/sample', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
it('rejects a color not defined for the material', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/sample/400000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||
res: {status: 'Color not available for material'}
|
||||
});
|
||||
});
|
||||
it('rejects an undefined color for the same material', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/sample/400000000000000000000001',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {type: 'part', color: 'signalviolet', batch: '114531', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||
res: {status: 'Color not available for material'}
|
||||
});
|
||||
});
|
||||
it('rejects an unknown material id', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
@ -952,7 +931,7 @@ describe('/sample', () => {
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {type: 'part', color: 'signalviolet', batch: '114531', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||
res: {status: 'Invalid body format', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid object id'}
|
||||
});
|
||||
});
|
||||
it('rejects an invalid id', done => {
|
||||
@ -1054,7 +1033,7 @@ describe('/sample', () => {
|
||||
res: {_id: '400000000000000000000004', number: '32', type: 'granulate', color: 'black', batch: '1653000308', condition: {p1: 36, condition_template: '200000000000000000000004'}, material_id: '100000000000000000000005', note_id: '500000000000000000000003', user_id: '000000000000000000000003', added: '2004-01-10T13:37:04.000Z'}
|
||||
});
|
||||
});
|
||||
it('rejects an changing back to an empty condition', done => {
|
||||
it('rejects changing back to an empty condition', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'put',
|
||||
url: '/sample/400000000000000000000001',
|
||||
@ -1642,16 +1621,6 @@ describe('/sample', () => {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('rejects a color not defined for the material', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
url: '/sample/new',
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {color: 'green', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||
res: {status: 'Color not available for material'}
|
||||
});
|
||||
});
|
||||
it('rejects an unknown material id', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'post',
|
||||
@ -1853,7 +1822,7 @@ describe('/sample', () => {
|
||||
auth: {basic: 'janedoe'},
|
||||
httpStatus: 400,
|
||||
req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '10000000000h000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
|
||||
res: {status: 'Invalid body format', details: '"material_id" with value "10000000000h000000000001" fails to match the required pattern: /[0-9a-f]{24}/'}
|
||||
res: {status: 'Invalid body format', details: 'Invalid object id'}
|
||||
});
|
||||
});
|
||||
it('rejects an API key', done => {
|
||||
|
@ -27,6 +27,9 @@ const router = express.Router();
|
||||
// TODO: convert filter value to number according to table model
|
||||
// TODO: validation for filter parameters
|
||||
// TODO: location/device sort/filter
|
||||
|
||||
// TODO: think about material numbers
|
||||
|
||||
router.get('/samples', async (req, res, next) => {
|
||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'all')) return;
|
||||
|
||||
@ -311,7 +314,7 @@ router.get('/samples', async (req, res, next) => {
|
||||
if (!fieldsToAdd.find(e => /spectrum\./.test(e))) { // use streaming when including spectrum files
|
||||
collection.aggregate(query).exec((err, data) => {
|
||||
if (err) return next(err);
|
||||
if (data[0].count) {
|
||||
if (data[0] && data[0].count) {
|
||||
res.header('x-total-items', data[0].count.length > 0 ? data[0].count[0].count : 0);
|
||||
res.header('Access-Control-Expose-Headers', 'x-total-items');
|
||||
data = data[0].samples;
|
||||
@ -425,14 +428,12 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
|
||||
|
||||
// only maintain and admin are allowed to edit other user's data
|
||||
if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||
|
||||
if (sample.hasOwnProperty('material_id')) {
|
||||
if (!await materialCheck(sample, res, next)) return;
|
||||
}
|
||||
else if (sample.hasOwnProperty('color')) {
|
||||
if (!await materialCheck(sample, res, next, sampleData.material_id)) return;
|
||||
}
|
||||
|
||||
if (sample.hasOwnProperty('condition') && !(_.isEmpty(sample.condition) && _.isEmpty(sampleData.condition))) { // do not execute check if condition is and was empty
|
||||
if (!await conditionCheck(sample.condition, 'change', res, next, sampleData.condition.condition_template.toString() !== sample.condition.condition_template)) return;
|
||||
}
|
||||
@ -615,11 +616,8 @@ module.exports = router;
|
||||
|
||||
async function numberGenerate (sample, req, res, next) { // generate number in format Location32, returns false on error
|
||||
const sampleData = await SampleModel
|
||||
// .findOne({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
|
||||
// .sort({number: -1})
|
||||
// .lean()
|
||||
.aggregate([
|
||||
{$match: {number: new RegExp('^' + 'Rng' + '[0-9]+$', 'm')}},
|
||||
{$match: {number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')}},
|
||||
// {$addFields: {number2: {$toDecimal: {$arrayElemAt: [{$split: [{$arrayElemAt: [{$split: ['$number', 'Rng']}, 1]}, '_']}, 0]}}}}, // not working with MongoDb 3.6
|
||||
{$addFields: {sortNumber: {$let: {
|
||||
vars: {tmp: {$concat: ['000000000000000000000000000000', {$arrayElemAt: [{$split: [{$arrayElemAt: [{$split: ['$number', 'Rng']}, 1]}, '_']}, 0]}]}},
|
||||
@ -650,10 +648,6 @@ async function materialCheck (sample, res, next, id = sample.material_id) { //
|
||||
res.status(400).json({status: 'Material not available'});
|
||||
return false;
|
||||
}
|
||||
if (sample.hasOwnProperty('color') && sample.color !== '' && !materialData.numbers.find(e => e.color === sample.color)) { // color for material not specified
|
||||
res.status(400).json({status: 'Color not available for material'});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -764,7 +758,6 @@ function addFilterQueries (queryPtr, filters) { // returns array of match queri
|
||||
}
|
||||
|
||||
function filterQueries (filters) {
|
||||
console.log(filters);
|
||||
return filters.map(e => {
|
||||
if (e.mode === 'or') { // allow or queries (needed for $ne added)
|
||||
return {['$' + e.mode]: e.values};
|
||||
|
@ -895,4 +895,49 @@ describe('/template', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/template/material', () => {
|
||||
describe('GET /template/materials', () => {
|
||||
it('returns all material templates', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/template/materials',
|
||||
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.measurement_templates.length);
|
||||
should(res.body).matchEach(measurement => {
|
||||
should(measurement).have.only.keys('_id', 'name', 'version', 'parameters');
|
||||
should(measurement).have.property('_id').be.type('string');
|
||||
should(measurement).have.property('name').be.type('string');
|
||||
should(measurement).have.property('version').be.type('number');
|
||||
should(measurement.parameters).matchEach(number => {
|
||||
should(number).have.only.keys('name', 'range');
|
||||
should(number).have.property('name').be.type('string');
|
||||
should(number).have.property('range').be.type('object');
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('rejects an API key', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/template/materials',
|
||||
auth: {key: 'janedoe'},
|
||||
httpStatus: 401
|
||||
});
|
||||
});
|
||||
it('rejects unauthorized requests', done => {
|
||||
TestHelper.request(server, done, {
|
||||
method: 'get',
|
||||
url: '/template/materials',
|
||||
httpStatus: 401
|
||||
});
|
||||
});
|
||||
});
|
||||
// other methods should be covered by measurement and condition tests
|
||||
});
|
||||
});
|
@ -13,7 +13,7 @@ import db from '../db';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/template/:collection(measurements|conditions)', (req, res, next) => {
|
||||
router.get('/template/:collection(measurements|conditions|materials)', (req, res, next) => {
|
||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
||||
|
||||
req.params.collection = req.params.collection.replace(/s$/g, ''); // remove trailing s
|
||||
@ -23,7 +23,7 @@ router.get('/template/:collection(measurements|conditions)', (req, res, next) =>
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/template/:collection(measurement|condition)/' + IdValidate.parameter(), (req, res, next) => {
|
||||
router.get('/template/:collection(measurement|condition|material)/' + IdValidate.parameter(), (req, res, next) => {
|
||||
if (!req.auth(res, ['read', 'write', 'maintain', 'dev', 'admin'], 'basic')) return;
|
||||
|
||||
model(req).findById(req.params.id).lean().exec((err, data) => {
|
||||
@ -37,7 +37,7 @@ router.get('/template/:collection(measurement|condition)/' + IdValidate.paramete
|
||||
});
|
||||
});
|
||||
|
||||
router.put('/template/:collection(measurement|condition)/' + IdValidate.parameter(), async (req, res, next) => {
|
||||
router.put('/template/:collection(measurement|condition|material)/' + IdValidate.parameter(), async (req, res, next) => {
|
||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||
|
||||
const {error, value: template} = TemplateValidate.input(req.body, 'change');
|
||||
@ -62,7 +62,7 @@ router.put('/template/:collection(measurement|condition)/' + IdValidate.paramete
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/template/:collection(measurement|condition)/new', async (req, res, next) => {
|
||||
router.post('/template/:collection(measurement|condition|material)/new', async (req, res, next) => {
|
||||
if (!req.auth(res, ['maintain', 'admin'], 'basic')) return;
|
||||
|
||||
const {error, value: template} = TemplateValidate.input(req.body, 'new');
|
||||
|
@ -302,7 +302,7 @@ describe('/user', () => {
|
||||
auth: {basic: 'admin'},
|
||||
httpStatus: 400,
|
||||
req: {pass: 'password'},
|
||||
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$)[a-zA-Z0-9!"#%&\'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]{8,}$/'}
|
||||
res: {status: 'Invalid body format', details: 'password must have at least 8 characters, one uppercase and one lowercase character, one number and at least one of the following characters: !\"\\#%&\'()*+,-.\\/:;<=>?@[]^_`\u0000|}~'}
|
||||
});
|
||||
});
|
||||
it('rejects requests from non-admins for another user', done => {
|
||||
@ -584,7 +584,7 @@ describe('/user', () => {
|
||||
auth: {basic: 'admin'},
|
||||
httpStatus: 400,
|
||||
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'password', level: 'read', location: 'Rng', device_name: 'Alpha II'},
|
||||
res: {status: 'Invalid body format', details: '"pass" with value "password" fails to match the required pattern: /^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&\'()*+,-.\\/:;<=>?@[\\]^_`{|}~])(?=\\S+$)[a-zA-Z0-9!"#%&\'()*+,\\-.\\/:;<=>?@[\\]^_`{|}~]{8,}$/'}
|
||||
res: {status: 'Invalid body format', details: 'password must have at least 8 characters, one uppercase and one lowercase character, one number and at least one of the following characters: !\"\\#%&\'()*+,-.\\/:;<=>?@[]^_`\u0000|}~'}
|
||||
});
|
||||
});
|
||||
it('rejects requests from non-admins', done => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Joi from '@hapi/joi';
|
||||
|
||||
export default class IdValidate {
|
||||
private static id = Joi.string().pattern(new RegExp('[0-9a-f]{24}')).length(24);
|
||||
private static id = Joi.string().pattern(new RegExp('[0-9a-f]{24}')).length(24).messages({'string.pattern.base': 'Invalid object id'});
|
||||
|
||||
static get () { // return joi validation
|
||||
return this.id;
|
||||
|
@ -13,31 +13,13 @@ export default class MaterialValidate { // validate input for material
|
||||
group: Joi.string()
|
||||
.max(128),
|
||||
|
||||
mineral: Joi.number()
|
||||
.integer()
|
||||
.min(0)
|
||||
.max(100),
|
||||
|
||||
glass_fiber: Joi.number()
|
||||
.integer()
|
||||
.min(0)
|
||||
.max(100),
|
||||
|
||||
carbon_fiber: Joi.number()
|
||||
.integer()
|
||||
.min(0)
|
||||
.max(100),
|
||||
properties: Joi.object(),
|
||||
|
||||
numbers: Joi.array()
|
||||
.items(Joi.object({
|
||||
color: Joi.string()
|
||||
.max(128)
|
||||
.required(),
|
||||
number: Joi.string()
|
||||
.max(128)
|
||||
.allow('')
|
||||
.required()
|
||||
}))
|
||||
.items(
|
||||
Joi.string()
|
||||
.length(10)
|
||||
)
|
||||
};
|
||||
|
||||
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
||||
@ -46,9 +28,7 @@ export default class MaterialValidate { // validate input for material
|
||||
name: this.material.name.required(),
|
||||
supplier: this.material.supplier.required(),
|
||||
group: this.material.group.required(),
|
||||
mineral: this.material.mineral.required(),
|
||||
glass_fiber: this.material.glass_fiber.required(),
|
||||
carbon_fiber: this.material.carbon_fiber.required(),
|
||||
properties: this.material.properties.required(),
|
||||
numbers: this.material.numbers.required()
|
||||
}).validate(data);
|
||||
}
|
||||
@ -57,9 +37,7 @@ export default class MaterialValidate { // validate input for material
|
||||
name: this.material.name,
|
||||
supplier: this.material.supplier,
|
||||
group: this.material.group,
|
||||
mineral: this.material.mineral,
|
||||
glass_fiber: this.material.glass_fiber,
|
||||
carbon_fiber: this.material.carbon_fiber,
|
||||
properties: this.material.properties,
|
||||
numbers: this.material.numbers
|
||||
}).validate(data);
|
||||
}
|
||||
@ -77,9 +55,7 @@ export default class MaterialValidate { // validate input for material
|
||||
name: this.material.name,
|
||||
supplier: this.material.supplier,
|
||||
group: this.material.group,
|
||||
mineral: this.material.mineral,
|
||||
glass_fiber: this.material.glass_fiber,
|
||||
carbon_fiber: this.material.carbon_fiber,
|
||||
properties: this.material.properties,
|
||||
numbers: this.material.numbers
|
||||
}).validate(data, {stripUnknown: true});
|
||||
return error !== undefined? null : value;
|
||||
@ -101,9 +77,7 @@ export default class MaterialValidate { // validate input for material
|
||||
name: this.material.name,
|
||||
supplier: this.material.supplier,
|
||||
group: this.material.group,
|
||||
mineral: this.material.mineral,
|
||||
glass_fiber: this.material.glass_fiber,
|
||||
carbon_fiber: this.material.carbon_fiber,
|
||||
properties: this.material.properties,
|
||||
numbers: this.material.numbers
|
||||
});
|
||||
}
|
||||
|
@ -195,7 +195,6 @@ export default class SampleValidate {
|
||||
validator = Joi.object(this.sample);
|
||||
}
|
||||
const {value, error} = validator.validate({[field]: e});
|
||||
console.log(value);
|
||||
if (error) throw error; // reject invalid values // TODO: return exact error description, handle in frontend filters
|
||||
return value[field];
|
||||
});
|
||||
@ -212,10 +211,10 @@ export default class SampleValidate {
|
||||
'page-size': Joi.number().integer().min(1),
|
||||
sort: Joi.string().pattern(new RegExp('^(' + this.sortKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')-(asc|desc)$', 'm')).default('_id-asc'),
|
||||
csv: Joi.boolean().default(false),
|
||||
fields: Joi.array().items(Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm'))).default(['_id','number','type','batch','material_id','color','condition','note_id','user_id','added']),
|
||||
fields: Joi.array().items(Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm'))).default(['_id','number','type','batch','material_id','color','condition','note_id','user_id','added']).messages({'string.pattern.base': 'Invalid field name'}),
|
||||
filters: Joi.array().items(Joi.object({
|
||||
mode: Joi.string().valid('eq', 'ne', 'lt', 'lte', 'gt', 'gte', 'in', 'nin'),
|
||||
field: Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')),
|
||||
field: Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')).messages({'string.pattern.base': 'Invalid filter field name'}),
|
||||
values: Joi.array().items(Joi.alternatives().try(Joi.string().max(128), Joi.number(), Joi.boolean(), Joi.date().iso())).min(1)
|
||||
})).default([])
|
||||
}).with('to-page', 'page-size').validate(data);
|
||||
|
@ -15,8 +15,10 @@ export default class TemplateValidate {
|
||||
Joi.object({
|
||||
name: Joi.string()
|
||||
.max(128)
|
||||
.invalid('condition_template')
|
||||
.required(),
|
||||
.invalid('condition_template', 'material_template')
|
||||
.pattern(/^[^.]+$/)
|
||||
.required()
|
||||
.messages({'string.pattern.base': 'name must not contain a dot'}),
|
||||
|
||||
range: Joi.object({
|
||||
values: Joi.array()
|
||||
|
@ -8,7 +8,8 @@ export default class UserValidate { // validate input for user
|
||||
name: Joi.string()
|
||||
.lowercase()
|
||||
.pattern(new RegExp('^[a-z0-9-_.]+$'))
|
||||
.max(128),
|
||||
.max(128)
|
||||
.messages({'string.pattern.base': 'name must only contain a-z0-9_.'}),
|
||||
|
||||
email: Joi.string()
|
||||
.email({minDomainSegments: 2})
|
||||
@ -17,7 +18,8 @@ export default class UserValidate { // validate input for user
|
||||
|
||||
pass: Joi.string()
|
||||
.pattern(/^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&'()*+,-.\/:;<=>?@[\]^_`{|}~])(?=\S+$)[a-zA-Z0-9!"#%&'()*+,\-.\/:;<=>?@[\]^_`{|}~]{8,}$/)
|
||||
.max(128),
|
||||
.max(128)
|
||||
.messages({'string.pattern.base': 'password must have at least 8 characters, one uppercase and one lowercase character, one number and at least one of the following characters: !"\\#%&\'()*+,-.\\/:;<=>?@[]^_`\\{|}~'}),
|
||||
|
||||
level: Joi.string()
|
||||
.valid(...globals.levels),
|
||||
|
182
src/test/db.json
182
src/test/db.json
@ -150,18 +150,15 @@
|
||||
"name": "Stanyl TW 200 F8",
|
||||
"supplier_id": {"$oid":"110000000000000000000001"},
|
||||
"group_id": {"$oid":"900000000000000000000001"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 40,
|
||||
"carbon_fiber": 0,
|
||||
"numbers": [
|
||||
{
|
||||
"color": "black",
|
||||
"number": "5514263423"
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
{
|
||||
"color": "natural",
|
||||
"number": "5514263422"
|
||||
}
|
||||
"numbers": [
|
||||
"5514263423",
|
||||
"5514263422"
|
||||
],
|
||||
"status": 10,
|
||||
"__v": 0
|
||||
@ -171,18 +168,15 @@
|
||||
"name": "Ultramid T KR 4355 G7",
|
||||
"supplier_id": {"$oid":"110000000000000000000002"},
|
||||
"group_id": {"$oid":"900000000000000000000002"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 35,
|
||||
"carbon_fiber": 0,
|
||||
"numbers": [
|
||||
{
|
||||
"color": "black",
|
||||
"number": "5514212901"
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
{
|
||||
"color": "signalviolet",
|
||||
"number": "5514612901"
|
||||
}
|
||||
"numbers": [
|
||||
"5514212901",
|
||||
"5514612901"
|
||||
],
|
||||
"status": 10,
|
||||
"__v": 0
|
||||
@ -192,9 +186,12 @@
|
||||
"name": "PA GF 50 black (2706)",
|
||||
"supplier_id": {"$oid":"110000000000000000000003"},
|
||||
"group_id": {"$oid":"900000000000000000000003"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 0,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
],
|
||||
"status": 10,
|
||||
@ -205,14 +202,14 @@
|
||||
"name": "Schulamid 66 GF 25 H",
|
||||
"supplier_id": {"$oid":"110000000000000000000004"},
|
||||
"group_id": {"$oid":"900000000000000000000004"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 25,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
{
|
||||
"color": "black",
|
||||
"number": "5513933405"
|
||||
}
|
||||
"5513933405"
|
||||
],
|
||||
"status": 10,
|
||||
"__v": 0
|
||||
@ -222,14 +219,14 @@
|
||||
"name": "Amodel A 1133 HS",
|
||||
"supplier_id": {"$oid":"110000000000000000000005"},
|
||||
"group_id": {"$oid":"900000000000000000000005"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 33,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
{
|
||||
"color": "black",
|
||||
"number": "5514262406"
|
||||
}
|
||||
"5514262406"
|
||||
],
|
||||
"status": 10,
|
||||
"__v": 0
|
||||
@ -239,14 +236,14 @@
|
||||
"name": "PK-HM natural (4773)",
|
||||
"supplier_id": {"$oid":"110000000000000000000003"},
|
||||
"group_id": {"$oid":"900000000000000000000006"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 0,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
{
|
||||
"color": "natural",
|
||||
"number": "10000000"
|
||||
}
|
||||
"1000000000"
|
||||
],
|
||||
"status": -1,
|
||||
"__v": 0
|
||||
@ -256,14 +253,13 @@
|
||||
"name": "Ultramid A4H",
|
||||
"supplier_id": {"$oid":"110000000000000000000002"},
|
||||
"group_id": {"$oid":"900000000000000000000004"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 0,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
{
|
||||
"color": "black",
|
||||
"number": ""
|
||||
}
|
||||
],
|
||||
"status": 0,
|
||||
"__v": 0
|
||||
@ -273,17 +269,47 @@
|
||||
"name": "Latamid 66 H 2 G 30",
|
||||
"supplier_id": {"$oid":"110000000000000000000006"},
|
||||
"group_id": {"$oid":"900000000000000000000004"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000003"},
|
||||
"mineral": 0,
|
||||
"glass_fiber": 30,
|
||||
"carbon_fiber": 0,
|
||||
"carbon_fiber": 0
|
||||
},
|
||||
"numbers": [
|
||||
{
|
||||
"color": "blue",
|
||||
"number": "5513943509"
|
||||
}
|
||||
"5513943509"
|
||||
],
|
||||
"status": -1,
|
||||
"__v": 0
|
||||
},
|
||||
{
|
||||
"_id": {"$oid":"100000000000000000000009"},
|
||||
"name": "Glue 1",
|
||||
"supplier_id": {"$oid":"110000000000000000000002"},
|
||||
"group_id": {"$oid":"900000000000000000000007"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000002"},
|
||||
"stickiness": "medium"
|
||||
},
|
||||
"numbers": [
|
||||
"5513943509"
|
||||
],
|
||||
"status": 0,
|
||||
"__v": 0
|
||||
},
|
||||
{
|
||||
"_id": {"$oid":"100000000000000000000010"},
|
||||
"name": "Latamid 66 G 40",
|
||||
"supplier_id": {"$oid":"110000000000000000000006"},
|
||||
"group_id": {"$oid":"900000000000000000000004"},
|
||||
"properties": {
|
||||
"material_template": {"$oid": "130000000000000000000001"},
|
||||
"glass_fiber": 40
|
||||
},
|
||||
"numbers": [
|
||||
"5513943509"
|
||||
],
|
||||
"status": 0,
|
||||
"__v": 0
|
||||
}
|
||||
],
|
||||
"material_groups": [
|
||||
@ -316,6 +342,11 @@
|
||||
"_id": {"$oid":"900000000000000000000006"},
|
||||
"name": "PK",
|
||||
"__v": 0
|
||||
},
|
||||
{
|
||||
"_id": {"$oid":"900000000000000000000007"},
|
||||
"name": "Fabric glue",
|
||||
"__v": 0
|
||||
}
|
||||
],
|
||||
"material_suppliers": [
|
||||
@ -565,6 +596,69 @@
|
||||
"__v": 0
|
||||
}
|
||||
],
|
||||
"material_templates": [
|
||||
{
|
||||
"_id": {"$oid":"130000000000000000000001"},
|
||||
"first_id": {"$oid":"130000000000000000000001"},
|
||||
"name": "plastic",
|
||||
"version": 1,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "glass_fiber",
|
||||
"range": {
|
||||
"min": 0,
|
||||
"max": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"__v": 0
|
||||
},
|
||||
{
|
||||
"_id": {"$oid":"130000000000000000000002"},
|
||||
"first_id": {"$oid":"130000000000000000000002"},
|
||||
"name": "glue",
|
||||
"version": 1,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "stickiness",
|
||||
"range": {
|
||||
"values": ["not so sticky", "medium", "very sticky"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"__v": 0
|
||||
},
|
||||
{
|
||||
"_id": {"$oid":"130000000000000000000003"},
|
||||
"first_id": {"$oid":"130000000000000000000001"},
|
||||
"name": "plastic",
|
||||
"version": 2,
|
||||
"parameters": [
|
||||
{
|
||||
"name": "glass_fiber",
|
||||
"range": {
|
||||
"min": 0,
|
||||
"max": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "carbon_fiber",
|
||||
"range": {
|
||||
"min": 0,
|
||||
"max": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mineral",
|
||||
"range": {
|
||||
"min": 0,
|
||||
"max": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"__v": 0
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"_id": {"$oid":"000000000000000000000001"},
|
||||
|
Reference in New Issue
Block a user