small material changes for easier UI implementation
This commit is contained in:
parent
36ca627d1b
commit
b59b3ea9ea
@ -20,7 +20,13 @@
|
|||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: 'api.yaml#/components/schemas/Material'
|
allOf:
|
||||||
|
- $ref: 'api.yaml#/components/schemas/Material'
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
description: can be deleted/new/validated
|
||||||
|
example: new
|
||||||
401:
|
401:
|
||||||
$ref: 'api.yaml#/components/responses/401'
|
$ref: 'api.yaml#/components/responses/401'
|
||||||
500:
|
500:
|
||||||
|
@ -24,11 +24,12 @@ describe('/material', () => {
|
|||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers', 'status');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
should(material).have.property('name').be.type('string');
|
should(material).have.property('name').be.type('string');
|
||||||
should(material).have.property('supplier').be.type('string');
|
should(material).have.property('supplier').be.type('string');
|
||||||
should(material).have.property('group').be.type('string');
|
should(material).have.property('group').be.type('string');
|
||||||
|
should(material).have.property('status', 'validated');
|
||||||
should(material.properties).have.property('material_template').be.type('string');
|
should(material.properties).have.property('material_template').be.type('string');
|
||||||
should(material.numbers).be.instanceof(Array);
|
should(material.numbers).be.instanceof(Array);
|
||||||
});
|
});
|
||||||
@ -46,11 +47,12 @@ describe('/material', () => {
|
|||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers', 'status');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
should(material).have.property('name').be.type('string');
|
should(material).have.property('name').be.type('string');
|
||||||
should(material).have.property('supplier').be.type('string');
|
should(material).have.property('supplier').be.type('string');
|
||||||
should(material).have.property('group').be.type('string');
|
should(material).have.property('group').be.type('string');
|
||||||
|
should(material).have.property('status', 'validated');
|
||||||
should(material.properties).have.property('material_template').be.type('string');
|
should(material.properties).have.property('material_template').be.type('string');
|
||||||
should(material.numbers).be.instanceof(Array);
|
should(material.numbers).be.instanceof(Array);
|
||||||
});
|
});
|
||||||
@ -60,7 +62,7 @@ describe('/material', () => {
|
|||||||
it('allows filtering by state', done => {
|
it('allows filtering by state', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/materials?status=new',
|
url: '/materials?status[]=new',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200
|
httpStatus: 200
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
@ -68,24 +70,57 @@ describe('/material', () => {
|
|||||||
const json = require('../test/db.json');
|
const json = require('../test/db.json');
|
||||||
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'new').length);
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'new').length);
|
||||||
should(res.body).matchEach(material => {
|
should(res.body).matchEach(material => {
|
||||||
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers', 'status');
|
||||||
should(material).have.property('_id').be.type('string');
|
should(material).have.property('_id').be.type('string');
|
||||||
should(material).have.property('name').be.type('string');
|
should(material).have.property('name').be.type('string');
|
||||||
should(material).have.property('supplier').be.type('string');
|
should(material).have.property('supplier').be.type('string');
|
||||||
should(material).have.property('group').be.type('string');
|
should(material).have.property('group').be.type('string');
|
||||||
|
should(material).have.property('status', 'new');
|
||||||
should(material.properties).have.property('material_template').be.type('string');
|
should(material.properties).have.property('material_template').be.type('string');
|
||||||
should(material.numbers).be.instanceof(Array);
|
should(material.numbers).be.instanceof(Array);
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('allows filtering by deleted state for admins', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/materials?status[]=deleted',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 200
|
||||||
|
}).end((err, res) => {
|
||||||
|
if (err) return done(err);
|
||||||
|
const json = require('../test/db.json');
|
||||||
|
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'deleted').length);
|
||||||
|
should(res.body).matchEach(material => {
|
||||||
|
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers', 'status');
|
||||||
|
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('status', 'deleted');
|
||||||
|
should(material.properties).have.property('material_template').be.type('string');
|
||||||
|
should(material.numbers).be.instanceof(Array);
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects filtering by deleted state for a write user', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/materials?status[]=deleted',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 400,
|
||||||
|
res: {status: 'Invalid body format', details: '"status[0]" must be one of [validated, new]'}
|
||||||
|
});
|
||||||
|
});
|
||||||
it('rejects an invalid state name', done => {
|
it('rejects an invalid state name', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/materials?status=xxx',
|
url: '/materials?status[]=xxx',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 400,
|
httpStatus: 400,
|
||||||
res: {status: 'Invalid body format', details: '"status" must be one of [validated, new, all]'}
|
res: {status: 'Invalid body format', details: '"status[0]" must be one of [validated, new]'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects unauthorized requests', done => {
|
it('rejects unauthorized requests', done => {
|
||||||
|
@ -21,7 +21,8 @@ const router = express.Router();
|
|||||||
router.get('/materials', (req, res, next) => {
|
router.get('/materials', (req, res, next) => {
|
||||||
if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
|
if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
const {error, value: filters} = MaterialValidate.query(req.query);
|
const {error, value: filters} =
|
||||||
|
MaterialValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
|
|
||||||
let conditions;
|
let conditions;
|
||||||
@ -38,11 +39,12 @@ router.get('/materials', (req, res, next) => {
|
|||||||
conditions = {status: globals.status.val};
|
conditions = {status: globals.status.val};
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialModel.find(conditions).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
|
MaterialModel.find(conditions).sort({name: 1}).populate('group_id').populate('supplier_id')
|
||||||
|
.lean().exec((err, data) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
|
|
||||||
// validate all and filter null values from validation errors
|
// validate all and filter null values from validation errors
|
||||||
res.json(_.compact(data.map(e => MaterialValidate.output(e))));
|
res.json(_.compact(data.map(e => MaterialValidate.output(e, true))));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ export default class MaterialValidate { // validate input for material
|
|||||||
.items(
|
.items(
|
||||||
Joi.string()
|
Joi.string()
|
||||||
.max(64)
|
.max(64)
|
||||||
)
|
),
|
||||||
|
|
||||||
|
status: Joi.string()
|
||||||
|
.valid(...Object.values(globals.status))
|
||||||
};
|
};
|
||||||
|
|
||||||
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
static input (data, param) { // validate input, set param to 'new' to make all attributes required
|
||||||
@ -47,18 +50,22 @@ export default class MaterialValidate { // validate input for material
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static output (data) { // validate output and strip unwanted properties, returns null if not valid
|
static output (data, status = false) { // validate output and strip unwanted properties, returns null if not valid
|
||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
data.group = data.group_id.name;
|
data.group = data.group_id.name;
|
||||||
data.supplier = data.supplier_id.name;
|
data.supplier = data.supplier_id.name;
|
||||||
const {value, error} = Joi.object({
|
const validate: any = {
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
name: this.material.name,
|
name: this.material.name,
|
||||||
supplier: this.material.supplier,
|
supplier: this.material.supplier,
|
||||||
group: this.material.group,
|
group: this.material.group,
|
||||||
properties: this.material.properties,
|
properties: this.material.properties,
|
||||||
numbers: this.material.numbers
|
numbers: this.material.numbers
|
||||||
}).validate(data, {stripUnknown: true});
|
};
|
||||||
|
if (status) {
|
||||||
|
validate.status = this.material.status;
|
||||||
|
}
|
||||||
|
const {value, error} = Joi.object(validate).validate(data, {stripUnknown: true});
|
||||||
return error !== undefined? null : value;
|
return error !== undefined? null : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,9 +90,13 @@ export default class MaterialValidate { // validate input for material
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static query (data) {
|
static query (data, dev = false) {
|
||||||
|
const acceptedStatuses = [globals.status.val, globals.status.new];
|
||||||
|
if (dev) { // dev and admin can also access deleted samples
|
||||||
|
acceptedStatuses.push(globals.status.del)
|
||||||
|
}
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
status: Joi.string().valid(globals.status.val, globals.status.new, 'all')
|
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val])
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user