Archived
2

Merge pull request #23 in ~VLE2FE/definma-api from develop to master

* commit '1396fb03260c9793be019f95386996649195a0a2':
  changed password policy
  added deleted status for /samples
  fixed mail service
  changed status and returned status for /samples
This commit is contained in:
Veit Lukas (PEA4-Fe) 2020-08-07 10:54:47 +02:00
commit f2b8b53e0b
19 changed files with 318 additions and 254 deletions

View File

@ -8,11 +8,13 @@
- /sample
parameters:
- name: status
description: 'values: validated|new|all, defaults to validated'
description: 'values: validated|new, for dev/admin also deleted, defaults to validated'
in: query
schema:
type: string
example: all
type: array
items:
type: string
example: ['validated']
- name: from-id
description: first id of the requested page, if not given the results are displayed from start
in: query
@ -66,7 +68,8 @@
%5D%7D"]'
responses:
200:
description: samples overview (if the csv parameter is set, this is in CSV instead of JSON format)
description: samples overview (output depends on the fields specified)<br>
if the csv parameter is set, this is in CSV instead of JSON format
headers:
x-total-items:
description: Total number of available items when from-id is not specified and spectrum field is not
@ -79,7 +82,7 @@
schema:
type: array
items:
$ref: 'api.yaml#/components/schemas/SampleRefs'
$ref: 'api.yaml#/components/schemas/SampleDetail'
400:
$ref: 'api.yaml#/components/responses/400'
401:

View File

@ -106,6 +106,10 @@ SampleDetail:
user:
type: string
example: admin
status:
type: string
description: can be deleted/new/validated
example: new
Material:
allOf:

View File

@ -19,7 +19,8 @@ export default class db {
mode: null,
};
static connect (mode = '', done: Function = () => {}) { // set mode to test for unit/integration tests, otherwise skip parameters. done is also only needed for testing
// set mode to test for unit/integration tests, otherwise skip parameters. done is also only needed for testing
static connect (mode = '', done: Function = () => {}) {
if (this.state.db) return done(); // db is already connected
// find right connection url
@ -43,7 +44,12 @@ export default class db {
}
// connect to db
mongoose.connect(connectionString, {useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, connectTimeoutMS: 10000}, err => {
mongoose.connect(connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
connectTimeoutMS: 10000
}, err => {
if (err) done(err);
});
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
@ -86,7 +92,8 @@ export default class db {
return this.state;
}
static drop (done: Function = () => {}) { // drop all collections of connected db (only dev and test for safety reasons ;)
// drop all collections of connected db (only dev and test for safety reasons)
static drop (done: Function = () => {}) {
if (!this.state.db || this.state.mode === 'prod') return done(); // no db connection or prod db
this.state.db.db.listCollections().toArray((err, collections) => { // get list of all collections
if (collections.length === 0) { // there are no collections to drop
@ -106,7 +113,8 @@ export default class db {
}
static loadJson (json, done: Function = () => {}) { // insert given JSON data into db, uses core mongodb methods
if (!this.state.db || !json.hasOwnProperty('collections') || json.collections.length === 0) { // no db connection or nothing to load
// no db connection or nothing to load
if (!this.state.db || !json.hasOwnProperty('collections') || json.collections.length === 0) {
return done();
}
@ -126,8 +134,8 @@ export default class db {
});
}
// changelog entry
static log(req, thisOrCollection, conditions = null, data = null) { // expects (req, this (from query helper)) or (req, collection, conditions, data)
// changelog entry, expects (req, this (from query helper)) or (req, collection, conditions, data)
static log(req, thisOrCollection, conditions = null, data = null) {
if (! (conditions || data)) { // (req, this)
data = thisOrCollection._update ? _.cloneDeep(thisOrCollection._update) : {}; // replace undefined with {}
Object.keys(data).forEach(key => {
@ -136,12 +144,24 @@ export default class db {
delete data[key];
}
});
new ChangelogModel({action: req.method + ' ' + req.url, collectionName: thisOrCollection._collection.collectionName, conditions: thisOrCollection._conditions, data: data, user_id: req.authDetails.id ? req.authDetails.id : null}).save(err => {
new ChangelogModel({
action: req.method + ' ' + req.url,
collectionName: thisOrCollection._collection.collectionName,
conditions: thisOrCollection._conditions,
data: data,
user_id: req.authDetails.id ? req.authDetails.id : null
}).save(err => {
if (err) console.error(err);
});
}
else { // (req, collection, conditions, data)
new ChangelogModel({action: req.method + ' ' + req.url, collectionName: thisOrCollection, conditions: conditions, data: data, user_id: req.authDetails.id ? req.authDetails.id : null}).save(err => {
new ChangelogModel({
action: req.method + ' ' + req.url,
collectionName: thisOrCollection,
conditions: conditions,
data: data,
user_id: req.authDetails.id ? req.authDetails.id : null
}).save(err => {
if (err) console.error(err);
});
}

View File

@ -6,11 +6,11 @@ const globals = {
'admin'
],
status: { // document statuses
deleted: -1,
new: 0,
validated: 10,
}
status: [ // document statuses
'deleted',
'new',
'validated',
]
};
export default globals;

View File

@ -10,49 +10,52 @@ export default class Mail{
static mailPass: string;
static init() {
this.mailPass = Array(64).map(() => Math.floor(Math.random() * 10)).join('');
this.uri = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.uri;
this.auth.username = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.username;
this.auth.password = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.password;
axios({ // get registered mail addresses
method: 'get',
url: this.uri + '/management/userDomainMapping',
auth: this.auth
}).then(res => {
return new Promise(async (resolve, reject) => {
try {
if (res.data.addresses.indexOf(this.address) < 0) { // mail address not registered
if (res.data.addresses.length) { // delete wrong registered mail address
await axios({
method: 'delete',
url: this.uri + '/management/mailAddresses/' + res.data.addresses[0],
if (process.env.NODE_ENV === 'production') { // only send mails in production
this.mailPass = Array(64).fill(0).map(() => Math.floor(Math.random() * 10)).join('');
this.uri = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.uri;
this.auth.username = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.username;
this.auth.password = JSON.parse(process.env.VCAP_SERVICES).Mail[0].credentials.password;
axios({ // get registered mail addresses
method: 'get',
url: this.uri + '/management/userDomainMapping',
auth: this.auth
}).then(res => {
return new Promise(async (resolve, reject) => {
try {
if (res.data.addresses.indexOf(this.address) < 0) { // mail address not registered
if (res.data.addresses.length) { // delete wrong registered mail address
await axios({
method: 'delete',
url: this.uri + '/management/mailAddresses/' + res.data.addresses[0],
auth: this.auth
});
}
await axios({ // register right mail address
method: 'post',
url: this.uri + '/management/mailAddresses/' + this.address,
auth: this.auth
});
}
await axios({ // register right mail address
method: 'post',
url: this.uri + '/management/mailAddresses/' + this.address,
auth: this.auth
});
resolve();
}
resolve();
}
catch (e) {
reject(e);
}
catch (e) {
reject(e);
}
});
}).then(() => {
return axios({ // set new mail password
method: 'put',
url: this.uri + '/management/mailAddresses/' + this.address + '/password/' + this.mailPass,
auth: this.auth
});
}).then(() => { // init done successfully
console.info('Mail service established successfully');
this.send('lukas.veit@bosch.com', 'Mail Service started', new Date().toString());
}).catch(err => { // anywhere an error occurred
console.error(`Mail init error: ${err.request.method} ${err.request.path}: ${err.response.status}`,
err.response.data);
});
}).then(() => {
return axios({ // set new mail password
method: 'put',
url: this.uri + '/management/mailAddresses/' + this.address + '/password/' + this.mailPass,
auth: this.auth
});
}).then(() => { // init done successfully
this.send('lukas.veit@bosch.com', 'Mail Service started', new Date().toString());
}).catch(err => { // anywhere an error occurred
console.error(`Mail init error: ${err.request.method} ${err.request.path}: ${err.response.status}`,
err.response.data);
});
}
}
static send (mailAddress, subject, content, f: (x?) => void = () => {}) { // callback, executed empty or with error

View File

@ -6,6 +6,7 @@ import helmet from 'helmet';
import cors from 'cors';
import api from './api';
import db from './db';
import Mail from './helpers/mail';
// TODO: check header, also in UI
@ -17,9 +18,11 @@ console.info(process.env.NODE_ENV === 'production' ?
// mongodb connection
db.connect();
// mail service
Mail.init();
// create Express app
const app = express();
app.disable('x-powered-by');
// get port from environment, defaults to 3000
const port = process.env.PORT || 3000;

View File

@ -9,7 +9,7 @@ const MaterialSchema = new mongoose.Schema({
group_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialGroupsModel},
properties: mongoose.Schema.Types.Mixed,
numbers: [String],
status: Number
status: String
}, {minimize: false});
// changelog query helper

View File

@ -9,7 +9,7 @@ const MeasurementSchema = new mongoose.Schema({
sample_id: {type: mongoose.Schema.Types.ObjectId, ref: SampleModel},
values: mongoose.Schema.Types.Mixed,
measurement_template: {type: mongoose.Schema.Types.ObjectId, ref: MeasurementTemplateModel},
status: Number
status: String
}, {minimize: false});
// changelog query helper

View File

@ -14,7 +14,7 @@ const SampleSchema = new mongoose.Schema({
material_id: {type: mongoose.Schema.Types.ObjectId, ref: MaterialModel},
note_id: {type: mongoose.Schema.Types.ObjectId, ref: NoteModel},
user_id: {type: mongoose.Schema.Types.ObjectId, ref: UserModel},
status: Number
status: String
}, {minimize: false});
// changelog query helper

View File

@ -23,7 +23,7 @@ describe('/material', () => {
}).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 === globals.status.validated).length);
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
should(res.body).matchEach(material => {
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
should(material).have.property('_id').be.type('string');
@ -45,7 +45,7 @@ describe('/material', () => {
}).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 === globals.status.validated).length);
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'validated').length);
should(res.body).matchEach(material => {
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
should(material).have.property('_id').be.type('string');
@ -67,7 +67,7 @@ describe('/material', () => {
}).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 === globals.status.new).length);
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status === 'new').length);
should(res.body).matchEach(material => {
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
should(material).have.property('_id').be.type('string');
@ -109,7 +109,7 @@ describe('/material', () => {
if (err) return done(err);
const json = require('../test/db.json');
let asyncCounter = res.body.length;
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.new).length);
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ==='new').length);
should(res.body).matchEach(material => {
should(material).have.only.keys('_id', 'name', 'supplier', 'group', 'properties', 'numbers');
should(material).have.property('_id').be.type('string');
@ -119,7 +119,7 @@ describe('/material', () => {
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);
should(data).have.property('status','new');
if (--asyncCounter === 0) {
done();
}
@ -137,7 +137,7 @@ describe('/material', () => {
if (err) return done(err);
const json = require('../test/db.json');
let asyncCounter = res.body.length;
should(res.body).have.lengthOf(json.collections.materials.filter(e => e.status ===globals.status.deleted).length);
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');
should(material).have.property('_id').be.type('string');
@ -147,7 +147,7 @@ describe('/material', () => {
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);
should(data).have.property('status','deleted');
if (--asyncCounter === 0) {
done();
}
@ -273,7 +273,7 @@ describe('/material', () => {
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);
should(data).have.property('status','validated');
MaterialGroupModel.find({name: 'PA46'}).lean().exec((err, data) => {
if (err) return done(err);
should(data).have.lengthOf(1);
@ -300,7 +300,7 @@ describe('/material', () => {
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);
should(data).have.property('status','validated');
done();
});
});
@ -317,7 +317,7 @@ describe('/material', () => {
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);
should(data).have.property('status','validated');
done();
});
});
@ -337,7 +337,7 @@ describe('/material', () => {
data._id = data._id.toString();
data.group_id = data.group_id.toString();
data.supplier_id = data.supplier_id.toString();
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});
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: 'new', __v: 0});
MaterialGroupModel.find({name: 'PA6/6T'}).lean().exec((err, data) => {
if (err) return done(err);
should(data).have.lengthOf(1);
@ -364,7 +364,7 @@ describe('/material', () => {
dataAdd: {
group_id: '900000000000000000000002',
supplier_id: '110000000000000000000002',
status: 0
status: 'new'
},
dataIgn: ['supplier', 'group']
}
@ -541,7 +541,7 @@ describe('/material', () => {
data.group_id = data.group_id.toString();
data.supplier_id = data.supplier_id.toString();
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}
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: 'deleted', __v: 0}
);
done();
});
@ -555,7 +555,7 @@ describe('/material', () => {
httpStatus: 200,
log: {
collection: 'materials',
dataAdd: { status: -1}
dataAdd: { status: 'deleted'}
}
});
});
@ -622,7 +622,7 @@ describe('/material', () => {
should(res.body).be.eql({status: 'OK'});
MaterialModel.findById('100000000000000000000008').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
done();
});
});
@ -637,7 +637,7 @@ describe('/material', () => {
log: {
collection: 'materials',
dataAdd: {
status: 0
status: 'new'
}
}
});
@ -692,7 +692,7 @@ describe('/material', () => {
should(res.body).be.eql({status: 'OK'});
MaterialModel.findById('100000000000000000000007').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -707,7 +707,7 @@ describe('/material', () => {
log: {
collection: 'materials',
dataAdd: {
status: 10
status: 'validated'
}
}
});
@ -790,7 +790,7 @@ describe('/material', () => {
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]).have.property('status','new');
should(materialData[0].numbers).have.lengthOf(0);
MaterialGroupModel.findById(materialData[0].group_id).lean().exec((err, data) => {
if (err) return done(err);
@ -813,7 +813,7 @@ describe('/material', () => {
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},
dataAdd: {status: 'new'},
dataIgn: ['group_id', 'supplier_id', 'group', 'supplier']
}
});

View File

@ -28,14 +28,14 @@ router.get('/materials', (req, res, next) => {
if (filters.hasOwnProperty('status')) {
if(filters.status === 'all') {
conditions = {$or: [{status: globals.status.validated}, {status: globals.status.new}]}
conditions = {$or: [{status: 'validated'}, {status: 'new'}]}
}
else {
conditions = {status: globals.status[filters.status]};
conditions = {status: filters.status};
}
}
else { // default
conditions = {status: globals.status.validated};
conditions = {status: 'validated'};
}
MaterialModel.find(conditions).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
@ -49,7 +49,7 @@ router.get('/materials', (req, res, next) => {
router.get('/materials/:state(new|deleted)', (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
MaterialModel.find({status: globals.status[req.params.state]}).populate('group_id').populate('supplier_id')
MaterialModel.find({status: req.params.state}).populate('group_id').populate('supplier_id')
.lean().exec((err, data) => {
if (err) return next(err);
@ -69,7 +69,7 @@ router.get('/material/' + IdValidate.parameter(), (req, res, next) => {
}
// deleted materials only available for dev/admin
if (data.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
if (data.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return;
res.json(MaterialValidate.output(data));
});
});
@ -84,7 +84,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
if (!materialData) {
return res.status(404).json({status: 'Not found'});
}
if (materialData.status === globals.status.deleted) {
if (materialData.status === 'deleted') {
return res.status(403).json({status: 'Forbidden'});
}
if (material.hasOwnProperty('name') && material.name !== materialData.name) {
@ -105,7 +105,7 @@ router.put('/material/' + IdValidate.parameter(), (req, res, next) => {
// check for changes
if (!_.isEqual(_.pick(IdValidate.stringify(materialData), _.keys(material)), IdValidate.stringify(material))) {
material.status = globals.status.new; // set status to new
material.status = 'new'; // set status to new
}
await MaterialModel.findByIdAndUpdate(req.params.id, material, {new: true})
@ -125,7 +125,7 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
if (data.length) {
return res.status(400).json({status: 'Material still in use'});
}
MaterialModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted})
MaterialModel.findByIdAndUpdate(req.params.id, {status:'deleted'})
.log(req).populate('group_id').populate('supplier_id').lean().exec((err, data) => {
if (err) return next(err);
if (data) {
@ -141,13 +141,13 @@ router.delete('/material/' + IdValidate.parameter(), (req, res, next) => {
router.put('/material/restore/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.new, req, res, next);
setStatus('new', req, res, next);
});
router.put('/material/validate/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.validated, req, res, next);
setStatus('validated', req, res, next);
});
router.post('/material/new', async (req, res, next) => {
@ -163,7 +163,7 @@ router.post('/material/new', async (req, res, next) => {
if (!material) return;
if (!await propertiesCheck(material.properties, 'new', res, next)) return;
material.status = globals.status.new; // set status to new
material.status = 'new'; // set status to new
await new MaterialModel(material).save(async (err, data) => {
if (err) return next(err);
db.log(req, 'materials', {_id: data._id}, data.toObject());

View File

@ -104,7 +104,7 @@ describe('/measurement', () => {
should(res.body).be.eql({_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[3997.12558,98.00555],[3995.08519,98.03253],[3993.04480,98.02657]], device: 'Alpha I'}, measurement_template: '300000000000000000000001'});
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -121,7 +121,7 @@ describe('/measurement', () => {
should(res.body).be.eql({_id: '800000000000000000000002', sample_id: '400000000000000000000002', values: {'weight %': 0.5, 'standard deviation': 0.2}, measurement_template: '300000000000000000000002'});
MeasurementModel.findById('800000000000000000000002').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -140,7 +140,7 @@ describe('/measurement', () => {
should(data).have.only.keys('_id', 'sample_id', 'values', 'measurement_template', 'status', '__v');
should(data.sample_id.toString()).be.eql('400000000000000000000001');
should(data.measurement_template.toString()).be.eql('300000000000000000000001');
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
should(data).have.property('values');
should(data.values).have.property('dpt', [[1,2],[3,4],[5,6]]);
done();
@ -159,7 +159,7 @@ describe('/measurement', () => {
dataAdd: {
measurement_template: '300000000000000000000001',
sample_id: '400000000000000000000001',
status: 0
status: 'new'
}
}
});
@ -328,7 +328,7 @@ describe('/measurement', () => {
should(res.body).be.eql({status: 'OK'});
MeasurementModel.findById('800000000000000000000001').lean().exec((err, data) => {
if (err) return done(err);
should(data).have.property('status',globals.status.deleted);
should(data).have.property('status','deleted');
done();
});
});
@ -342,7 +342,7 @@ describe('/measurement', () => {
log: {
collection: 'measurements',
dataAdd: {
status: -1
status: 'deleted'
}
}
});
@ -418,7 +418,7 @@ describe('/measurement', () => {
should(res.body).be.eql({status: 'OK'});
MeasurementModel.findById('800000000000000000000004').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
done();
});
});
@ -433,7 +433,7 @@ describe('/measurement', () => {
log: {
collection: 'measurements',
dataAdd: {
status: 0
status: 'new'
}
}
});
@ -488,7 +488,7 @@ describe('/measurement', () => {
should(res.body).be.eql({status: 'OK'});
MeasurementModel.findById('800000000000000000000003').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -503,7 +503,7 @@ describe('/measurement', () => {
log: {
collection: 'measurements',
dataAdd: {
status: 10
status: 'validated'
}
}
});
@ -579,7 +579,7 @@ describe('/measurement', () => {
should(data).have.only.keys('_id', 'sample_id', 'values', 'measurement_template', 'status', '__v');
should(data.sample_id.toString()).be.eql('400000000000000000000001');
should(data.measurement_template.toString()).be.eql('300000000000000000000002');
should(data).have.property('status', 0);
should(data).have.property('status', 'new');
should(data).have.property('values');
should(data.values).have.property('weight %', 0.8);
should(data.values).have.property('standard deviation', 0.1);
@ -597,7 +597,7 @@ describe('/measurement', () => {
log: {
collection: 'measurements',
dataAdd: {
status: 0
status: 'new'
}
}
});

View File

@ -23,7 +23,7 @@ router.get('/measurement/' + IdValidate.parameter(), (req, res, next) => {
return res.status(404).json({status: 'Not found'});
}
// deleted measurements only available for dev/admin
if (data.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
if (data.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return;
res.json(MeasurementValidate.output(data, req));
});
@ -40,7 +40,7 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
if (!data) {
return res.status(404).json({status: 'Not found'});
}
if (data.status === globals.status.deleted) {
if (data.status === 'deleted') {
return res.status(403).json({status: 'Forbidden'});
}
@ -53,7 +53,7 @@ router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => {
if (measurement.values) { // fill not changed values from database
measurement.values = _.assign({}, data.values, measurement.values);
if (!_.isEqual(measurement.values, data.values)) {
measurement.status = globals.status.new; // set status to new
measurement.status = 'new'; // set status to new
}
}
@ -74,7 +74,7 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
return res.status(404).json({status: 'Not found'});
}
if (!await sampleIdCheck(data, req, res, next)) return;
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted})
await MeasurementModel.findByIdAndUpdate(req.params.id, {status:'deleted'})
.log(req).lean().exec(err => {
if (err) return next(err);
return res.json({status: 'OK'});
@ -85,13 +85,13 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.new, req, res, next);
setStatus('new', req, res, next);
});
router.put('/measurement/validate/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
setStatus(globals.status.validated, req, res, next);
setStatus('validated', req, res, next);
});
router.post('/measurement/new', async (req, res, next) => {
@ -104,7 +104,7 @@ router.post('/measurement/new', async (req, res, next) => {
measurement.values = await templateCheck(measurement, 'new', res, next);
if (!measurement.values) return;
measurement.status = 0;
measurement.status = 'new';
await new MeasurementModel(measurement).save((err, data) => {
if (err) return next(err);
db.log(req, 'measurements', {_id: data._id}, data.toObject());

View File

@ -4,7 +4,6 @@ import NoteModel from '../models/note';
import NoteFieldModel from '../models/note_field';
import MeasurementModel from '../models/measurement';
import TestHelper from "../test/helper";
import globals from '../globals';
import mongoose from 'mongoose';
@ -31,7 +30,7 @@ describe('/sample', () => {
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.validated).length);
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ==='validated').length);
should(res.body).matchEach(sample => {
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(sample).have.property('_id').be.type('string');
@ -49,6 +48,22 @@ describe('/sample', () => {
done();
});
});
it('returns deleted samples for admin', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status[]=deleted&fields[]=number&fields=status',
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.samples.filter(e => e.status ==='deleted').length);
should(res.body).matchEach(sample => {
should(sample).have.property('status', 'deleted').be.type('string');
});
done();
});
});
it('works with an API key', done => {
TestHelper.request(server, done, {
method: 'get',
@ -58,7 +73,7 @@ describe('/sample', () => {
}).end((err, res) => {
if (err) return done(err);
const json = require('../test/db.json');
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.validated).length);
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ==='validated').length);
should(res.body).matchEach(sample => {
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(sample).have.property('_id').be.type('string');
@ -79,13 +94,13 @@ describe('/sample', () => {
it('allows filtering by state', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=new',
url: '/samples?status[]=new',
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.samples.filter(e => e.status ===globals.status.new).length);
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ==='new').length);
should(res.body).matchEach(sample => {
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(sample).have.property('_id').be.type('string');
@ -105,7 +120,7 @@ describe('/sample', () => {
it('uses the given page size', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&page-size=3',
url: '/samples?status[]=new&status[]=validated&page-size=3',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -117,7 +132,7 @@ describe('/sample', () => {
it('returns results starting from first-id', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&from-id=400000000000000000000002',
url: '/samples?status[]=new&status[]=validated&from-id=400000000000000000000002',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -130,7 +145,7 @@ describe('/sample', () => {
it('returns the right page number', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&to-page=2&page-size=2',
url: '/samples?status[]=new&status[]=validated&to-page=2&page-size=2',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -142,7 +157,7 @@ describe('/sample', () => {
it('works with negative page numbers', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&to-page=-1&page-size=2&from-id=400000000000000000000004',
url: '/samples?status[]=new&status[]=validated&to-page=-1&page-size=2&from-id=400000000000000000000004',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -155,7 +170,7 @@ describe('/sample', () => {
it('returns an empty array for a page number out of range', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&to-page=100&page-size=2',
url: '/samples?status[]=new&status[]=validated&to-page=100&page-size=2',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -168,7 +183,7 @@ describe('/sample', () => {
it('returns an empty array for a page number out of negative range', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&to-page=-100&page-size=3&from-id=400000000000000000000004',
url: '/samples?status[]=new&status[]=validated&to-page=-100&page-size=3&from-id=400000000000000000000004',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -181,7 +196,7 @@ describe('/sample', () => {
it('sorts the samples ascending', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=color-asc',
url: '/samples?status[]=new&status[]=validated&sort=color-asc',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -194,7 +209,7 @@ describe('/sample', () => {
it('sorts the samples descending', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=number-desc',
url: '/samples?status[]=new&status[]=validated&sort=number-desc',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -208,7 +223,7 @@ describe('/sample', () => {
it('sorts the samples correctly in combination with paging', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=color-asc&page-size=2&from-id=400000000000000000000006',
url: '/samples?status[]=new&status[]=validated&sort=color-asc&page-size=2&from-id=400000000000000000000006',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -221,7 +236,7 @@ describe('/sample', () => {
it('sorts the samples correctly in combination with going pages backward', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=color-desc&page-size=2&from-id=400000000000000000000004&to-page=-1',
url: '/samples?status[]=new&status[]=validated&sort=color-desc&page-size=2&from-id=400000000000000000000004&to-page=-1',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -234,7 +249,7 @@ describe('/sample', () => {
it('sorts the samples correctly for material keys', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=material.name-desc',
url: '/samples?status[]=new&status[]=validated&sort=material.name-desc',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -245,10 +260,23 @@ describe('/sample', () => {
done();
});
});
it('adds the status if specified', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=status',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
if (err) return done(err);
should(res.body.find(e => e.number === '1')).have.property('status', 'validated');
should(res.body.find(e => e.number === 'Rng36')).have.property('status', 'new');
done();
});
});
it('adds the specified measurements', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=measurements.kf',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.kf',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -261,7 +289,7 @@ 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.dpt',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.spectrum.dpt',
auth: {basic: 'admin'},
httpStatus: 200
}).end((err, res) => {
@ -275,7 +303,7 @@ describe('/sample', () => {
it('filters a sample property', done => { // TODO: implement filters
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=type&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22type%22%2C%22values%22%3A%5B%22part%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=type&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22type%22%2C%22values%22%3A%5B%22part%22%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -291,7 +319,7 @@ describe('/sample', () => {
it('filters a material property', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.name&filters[]=%7B%22mode%22%3A%22in%22%2C%22field%22%3A%22material.name%22%2C%22values%22%3A%5B%22Schulamid%2066%20GF%2025%20H%22%2C%22Stanyl%20TW%20200%20F8%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.name&filters[]=%7B%22mode%22%3A%22in%22%2C%22field%22%3A%22material.name%22%2C%22values%22%3A%5B%22Schulamid%2066%20GF%2025%20H%22%2C%22Stanyl%20TW%20200%20F8%22%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -307,7 +335,7 @@ describe('/sample', () => {
it('filters by measurement value', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.name&fields[]=measurements.kf.weight%20%25&filters[]=%7B%22mode%22%3A%22gt%22%2C%22field%22%3A%22measurements.kf.weight%20%25%22%2C%22values%22%3A%5B0.5%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.name&fields[]=measurements.kf.weight%20%25&filters[]=%7B%22mode%22%3A%22gt%22%2C%22field%22%3A%22measurements.kf.weight%20%25%22%2C%22values%22%3A%5B0.5%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -323,7 +351,7 @@ describe('/sample', () => {
it('filters by measurement value not in the fields', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.name&filters[]=%7B%22mode%22%3A%22gt%22%2C%22field%22%3A%22measurements.kf.weight%20%25%22%2C%22values%22%3A%5B0.5%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.name&filters[]=%7B%22mode%22%3A%22gt%22%2C%22field%22%3A%22measurements.kf.weight%20%25%22%2C%22values%22%3A%5B0.5%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -337,7 +365,7 @@ describe('/sample', () => {
it('filters by a measurement properties property', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.name&fields[]=material.properties.glass_fiber&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.properties.glass_fiber%22%2C%22values%22%3A%5B%2225%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.name&fields[]=material.properties.glass_fiber&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.properties.glass_fiber%22%2C%22values%22%3A%5B%2225%22%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -352,7 +380,7 @@ describe('/sample', () => {
it('filters and sorts by a measurement properties property', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&sort=material.properties.glass_fiber-desc&fields[]=number&fields[]=material.name&fields[]=material.properties.glass_fiber&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.properties.glass_fiber%22%2C%22values%22%3A%5B%2225%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&sort=material.properties.glass_fiber-desc&fields[]=number&fields[]=material.name&fields[]=material.properties.glass_fiber&filters[]=%7B%22mode%22%3A%22eq%22%2C%22field%22%3A%22material.properties.glass_fiber%22%2C%22values%22%3A%5B%2225%22%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -369,7 +397,7 @@ describe('/sample', () => {
it('filters multiple properties', done => {
TestHelper.request(server, done, {
method: 'get',
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',
url: '/samples?status[]=new&status[]=validated&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) => {
@ -382,7 +410,7 @@ describe('/sample', () => {
it('rejects returning spectral data for a write user', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=measurements.spectrum.dpt',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.spectrum.dpt',
auth: {basic: 'janedoe'},
httpStatus: 403
});
@ -390,7 +418,7 @@ describe('/sample', () => {
it('rejects an invalid JSON string as a filters parameter', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.glass_fiber&fields[]=batch&filters[]=xx',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.glass_fiber&fields[]=batch&filters[]=xx',
auth: {basic: 'janedoe'},
httpStatus: 400,
res: {status: 'Invalid body format', details: 'Invalid JSON string for filter parameter'}
@ -399,7 +427,7 @@ describe('/sample', () => {
it('rejects an invalid filter mode', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=batch&filters[]=%7B%22mode%22%3A%22xx%22%2C%22field%22%3A%22batch%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=batch&filters[]=%7B%22mode%22%3A%22xx%22%2C%22field%22%3A%22batch%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
auth: {basic: 'janedoe'},
httpStatus: 400,
res: {status: 'Invalid body format', details: '"filters[0].mode" must be one of [eq, ne, lt, lte, gt, gte, in, nin, stringin]'}
@ -408,7 +436,7 @@ describe('/sample', () => {
it('rejects an filter field not existing', 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%22xx%22%2C%22values%22%3A%5B%221704-005%22%5D%7D',
url: '/samples?status[]=new&status[]=validated&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: 'Invalid JSON string for filter parameter'}
@ -417,7 +445,7 @@ describe('/sample', () => {
it('rejects unknown measurement names', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=measurements.xx',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.xx',
auth: {basic: 'janedoe'},
httpStatus: 400,
res: {status: 'Invalid body format', details: 'Measurement key not found'}
@ -426,7 +454,7 @@ describe('/sample', () => {
it('returns a correct csv file if specified', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&page-size=2&csv=true',
url: '/samples?status[]=new&status[]=validated&page-size=2&csv=true',
contentType: /text\/csv/,
auth: {basic: 'janedoe'},
httpStatus: 200
@ -441,7 +469,7 @@ 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.supplier',
url: '/samples?status[]=new&status[]=validated&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', supplier: 'Schulmann'}}]
@ -450,7 +478,7 @@ describe('/sample', () => {
it('returns specified material properties fields', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&fields[]=number&fields[]=material.properties.glass_fiber&fields[]=material.name',
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=material.properties.glass_fiber&fields[]=material.name',
auth: {basic: 'janedoe'},
httpStatus: 200
}).end((err, res) => {
@ -478,7 +506,7 @@ describe('/sample', () => {
it('rejects an invalid fields parameter', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&page-size=1&fields=number',
url: '/samples?status[]=new&status[]=validated&page-size=1&fields=number',
auth: {basic: 'janedoe'},
httpStatus: 400,
res: {status: 'Invalid body format', details: '"fields" must be an array'}
@ -487,7 +515,7 @@ describe('/sample', () => {
it('rejects an unknown field name', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=all&page-size=1&fields[]=xx',
url: '/samples?status[]=new&status[]=validated&page-size=1&fields[]=xx',
auth: {basic: 'janedoe'},
httpStatus: 400,
res: {status: 'Invalid body format', details: 'Invalid field name'}
@ -523,10 +551,10 @@ describe('/sample', () => {
it('rejects an invalid state name', done => {
TestHelper.request(server, done, {
method: 'get',
url: '/samples?status=xxx',
url: '/samples?status[]=xxx',
auth: {basic: 'janedoe'},
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 => {
@ -549,9 +577,9 @@ describe('/sample', () => {
if (err) return done(err);
const json = require('../test/db.json');
let asyncCounter = res.body.length;
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ===globals.status.new).length);
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status ==='new').length);
should(res.body).matchEach(sample => {
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(sample).have.property('_id').be.type('string');
should(sample).have.property('number').be.type('string');
should(sample).have.property('type').be.type('string');
@ -565,8 +593,9 @@ describe('/sample', () => {
should(sample).have.property('note_id');
should(sample).have.property('user_id').be.type('string');
should(sample).have.property('added').be.type('string');
should(sample).have.property('status').be.type('string');
SampleModel.findById(sample._id).lean().exec((err, data) => {
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
if (--asyncCounter === 0) {
done();
}
@ -584,9 +613,9 @@ describe('/sample', () => {
if (err) return done(err);
const json = require('../test/db.json');
let asyncCounter = res.body.length;
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === -1).length);
should(res.body).have.lengthOf(json.collections.samples.filter(e => e.status === 'deleted').length);
should(res.body).matchEach(sample => {
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(sample).have.only.keys('_id', 'number', 'type', 'color', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(sample).have.property('_id').be.type('string');
should(sample).have.property('number').be.type('string');
should(sample).have.property('type').be.type('string');
@ -600,8 +629,9 @@ describe('/sample', () => {
should(sample).have.property('note_id');
should(sample).have.property('user_id').be.type('string');
should(sample).have.property('added').be.type('string');
should(sample).have.property('status').be.type('string');
SampleModel.findById(sample._id).lean().exec((err, data) => {
should(data).have.property('status',globals.status.deleted);
should(data).have.property('status','deleted');
if (--asyncCounter === 0) {
done();
}
@ -677,7 +707,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', 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'}
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'}], status: 'new', user: 'admin'}
});
});
it('works with an API key', done => {
@ -686,7 +716,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', 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'}
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'}], status: 'new', user: 'admin'}
});
});
it ('filters out spectral data for a write user', done => {
@ -695,7 +725,7 @@ describe('/sample', () => {
url: '/sample/400000000000000000000001',
auth: {basic: 'janedoe'},
httpStatus: 200,
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}], status: 'validated'}
});
});
it ('returns spectral data for an admin user', done => {
@ -704,7 +734,7 @@ describe('/sample', () => {
url: '/sample/400000000000000000000001',
auth: {basic: 'admin'},
httpStatus: 200,
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}], status: 'validated'}
});
});
it('returns a deleted sample for a dev/admin user', done => {
@ -713,7 +743,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', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['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: [], status: 'deleted', user: 'admin'}
});
});
it('returns 403 for a write user when requesting a deleted sample', done => {
@ -757,7 +787,7 @@ describe('/sample', () => {
auth: {basic: 'janedoe'},
httpStatus: 200,
req: {},
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'}
});
});
it('keeps unchanged properties', done => {
@ -769,7 +799,7 @@ describe('/sample', () => {
req: {type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', notes: {}}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'});
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'});
SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
if (err) return done (err);
should(data).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
@ -781,7 +811,7 @@ describe('/sample', () => {
should(data).have.property('condition', {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'});
should(data.material_id.toString()).be.eql('100000000000000000000004');
should(data.user_id.toString()).be.eql('000000000000000000000002');
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
should(data).have.property('note_id', null);
done();
});
@ -796,10 +826,10 @@ describe('/sample', () => {
req: {type: 'granulate'}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'});
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'});
SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
if (err) return done (err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -813,10 +843,10 @@ describe('/sample', () => {
req: {condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'});
should(res.body).be.eql({_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'});
SampleModel.findById('400000000000000000000001').lean().exec((err, data: any) => {
if (err) return done (err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -830,7 +860,7 @@ describe('/sample', () => {
req: {notes: {comment: 'Stoff gesperrt', sample_references: []}}
}).end((err, res) => {
if (err) return done(err);
should(res.body).be.eql({_id: '400000000000000000000002', number: '21', type: 'granulate', color: 'natural', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', note_id: '500000000000000000000001', user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'});
should(res.body).be.eql({_id: '400000000000000000000002', number: '21', type: 'granulate', color: 'natural', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', note_id: '500000000000000000000001', user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'});
SampleModel.findById('400000000000000000000002').lean().exec((err, data: any) => {
if (err) return done (err);
should(data).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', '__v');
@ -844,7 +874,7 @@ describe('/sample', () => {
should(data.condition.condition_template.toString()).be.eql('200000000000000000000001');
should(data.material_id.toString()).be.eql('100000000000000000000001');
should(data.user_id.toString()).be.eql('000000000000000000000002');
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
should(data.note_id.toString()).be.eql('500000000000000000000001');
done();
});
@ -870,7 +900,7 @@ describe('/sample', () => {
should(data).have.property('condition', {condition_template: '200000000000000000000003'});
should(data.material_id.toString()).be.eql('100000000000000000000002');
should(data.user_id.toString()).be.eql('000000000000000000000002');
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
should(data).have.property('note_id');
NoteModel.findById(data.note_id).lean().exec((err, data: any) => {
if (err) return done (err);
@ -895,7 +925,7 @@ describe('/sample', () => {
log: {
collection: 'samples',
dataAdd: {
status: 0
status: 'new'
},
dataIgn: ['notes', 'note_id']
}
@ -1097,7 +1127,7 @@ describe('/sample', () => {
auth: {basic: 'janedoe'},
httpStatus: 200,
req: {condition: {}},
res: {_id: '400000000000000000000006', number: 'Rng36', type: 'granulate', color: 'black', batch: '', condition: {}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'}
res: {_id: '400000000000000000000006', number: 'Rng36', type: 'granulate', color: 'black', batch: '', condition: {}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'new', added: '2004-01-10T13:37:04.000Z'}
});
});
it('rejects an old version of a condition template', done => {
@ -1117,7 +1147,7 @@ describe('/sample', () => {
auth: {basic: 'admin'},
httpStatus: 200,
req: {condition: {p1: 36, condition_template: '200000000000000000000004'}},
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'}
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', status: 'new', added: '2004-01-10T13:37:04.000Z'}
});
});
it('rejects changing back to an empty condition', done => {
@ -1164,7 +1194,7 @@ describe('/sample', () => {
auth: {basic: 'admin'},
httpStatus: 200,
req: {},
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {condition_template: '200000000000000000000001', material: 'copper', weeks: 3}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', added: '2004-01-10T13:37:04.000Z'}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {condition_template: '200000000000000000000001', material: 'copper', weeks: 3}, material_id: '100000000000000000000004', note_id: null, user_id: '000000000000000000000002', status: 'validated', added: '2004-01-10T13:37:04.000Z'}
});
});
it('rejects requests from a read user', done => {
@ -1218,7 +1248,7 @@ describe('/sample', () => {
should(data.condition.condition_template.toString()).be.eql('200000000000000000000001');
should(data.material_id.toString()).be.eql('100000000000000000000004');
should(data.user_id.toString()).be.eql('000000000000000000000002');
should(data).have.property('status',globals.status.deleted);
should(data).have.property('status','deleted');
should(data).have.property('note_id', null);
done();
});
@ -1233,7 +1263,7 @@ describe('/sample', () => {
log: {
collection: 'samples',
skip: 1,
dataAdd: {status: -1}
dataAdd: {status: 'deleted'}
}
});
});
@ -1307,7 +1337,7 @@ describe('/sample', () => {
should(res.body).be.eql({status: 'OK'});
SampleModel.findById('400000000000000000000001').lean().exec((err, data) => {
if (err) return done(err);
should(data).have.property('status',globals.status.deleted);
should(data).have.property('status','deleted');
done();
});
});
@ -1324,7 +1354,7 @@ describe('/sample', () => {
MeasurementModel.find({sample_id: mongoose.Types.ObjectId('400000000000000000000001')}).lean().exec((err, data: any) => {
if (err) return done(err);
should(data).matchEach(sample => {
should(sample).have.property('status', -1);
should(sample).have.property('status', 'deleted');
});
done();
});
@ -1386,7 +1416,7 @@ describe('/sample', () => {
url: '/sample/number/33',
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', 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'}
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'}], status: 'new', user: 'admin'}
});
});
it('works with an API key', done => {
@ -1395,7 +1425,7 @@ describe('/sample', () => {
url: '/sample/number/33',
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', 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'}
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'}], status: 'new', user: 'admin'}
});
});
it('returns a deleted sample for a dev/admin user', done => {
@ -1404,7 +1434,7 @@ describe('/sample', () => {
url: '/sample/number/Rng33',
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', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 33, carbon_fiber: 0}, numbers: ['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: [], status: 'deleted', user: 'admin'}
});
});
it ('filters out spectral data for a write user', done => {
@ -1413,7 +1443,7 @@ describe('/sample', () => {
url: '/sample/number/1',
auth: {basic: 'janedoe'},
httpStatus: 200,
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {device: 'Alpha II'}, measurement_template: '300000000000000000000001'}], status: 'validated'}
});
});
it ('returns spectral data for an admin user', done => {
@ -1422,7 +1452,7 @@ describe('/sample', () => {
url: '/sample/number/1',
auth: {basic: 'admin'},
httpStatus: 200,
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}]}
res: {_id: '400000000000000000000001', number: '1', type: 'granulate', color: 'black', batch: '', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material: {numbers: ['5513933405'], _id: '100000000000000000000004', name: 'Schulamid 66 GF 25 H', properties: {material_template: '130000000000000000000003', mineral: 0, glass_fiber: 25, carbon_fiber: 0}, group: 'PA66', supplier: 'Schulmann'}, user: 'janedoe', notes: {}, measurements: [{_id: '800000000000000000000001', sample_id: '400000000000000000000001', values: {dpt: [[ 3997.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]],device: 'Alpha I'}, measurement_template: '300000000000000000000001'}, {_id: '800000000000000000000007', sample_id: '400000000000000000000001', values: {dpt: [[ 3996.12558, 98.00555 ], [ 3995.08519, 98.03253 ], [ 3993.0448, 98.02657 ]], device: 'Alpha II'}, measurement_template: '300000000000000000000001'}], status: 'validated'}
});
});
it('returns 403 for a write user when requesting a deleted sample', done => {
@ -1471,7 +1501,7 @@ describe('/sample', () => {
should(res.body).be.eql({status: 'OK'});
SampleModel.findById('400000000000000000000005').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.new);
should(data).have.property('status','new');
done();
});
});
@ -1488,7 +1518,7 @@ describe('/sample', () => {
dataAdd: {
group_id: '900000000000000000000002',
supplier_id: '110000000000000000000002',
status: 0
status: 'new'
},
dataIgn: ['group_id', 'supplier_id']
}
@ -1544,7 +1574,7 @@ describe('/sample', () => {
should(res.body).be.eql({status: 'OK'});
SampleModel.findById('400000000000000000000003').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -1561,7 +1591,7 @@ describe('/sample', () => {
dataAdd: {
group_id: '900000000000000000000002',
supplier_id: '110000000000000000000002',
status: 10
status: 'validated'
},
dataIgn: ['group_id', 'supplier_id']
}
@ -1579,7 +1609,7 @@ describe('/sample', () => {
should(res.body).be.eql({status: 'OK'});
SampleModel.findById('400000000000000000000006').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -1596,7 +1626,7 @@ describe('/sample', () => {
should(res.body).be.eql({status: 'OK'});
SampleModel.findById('400000000000000000000004').lean().exec((err, data: any) => {
if (err) return done(err);
should(data).have.property('status',globals.status.validated);
should(data).have.property('status','validated');
done();
});
});
@ -1648,7 +1678,7 @@ describe('/sample', () => {
req: {color: 'black', type: 'granulate', batch: '1560237365', condition: {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'}, material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
}).end((err, res) => {
if (err) return done (err);
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(res.body).have.property('_id').be.type('string');
should(res.body).have.property('number', 'Rng37');
should(res.body).have.property('color', 'black');
@ -1658,6 +1688,7 @@ describe('/sample', () => {
should(res.body).have.property('material_id', '100000000000000000000001');
should(res.body).have.property('note_id').be.type('string');
should(res.body).have.property('user_id', '000000000000000000000002');
should(res.body).have.property('status', 'new');
should(res.body).have.property('added').be.type('string');
should(new Date().getTime() - new Date(res.body.added).getTime()).be.below(1000);
done();
@ -1684,7 +1715,7 @@ describe('/sample', () => {
should(data[0]).have.property('condition', {material: 'copper', weeks: 3, condition_template: '200000000000000000000001'});
should(data[0].material_id.toString()).be.eql('100000000000000000000001');
should(data[0].user_id.toString()).be.eql('000000000000000000000002');
should(data[0]).have.property('status',globals.status.new);
should(data[0]).have.property('status','new');
should(data[0]).have.property('note_id');
NoteModel.findById(data[0].note_id).lean().exec((err, data: any) => {
if (err) return done (err);
@ -1711,7 +1742,7 @@ describe('/sample', () => {
dataAdd: {
number: 'Rng37',
user_id: '000000000000000000000002',
status: 0
status: 'new'
},
dataIgn: ['notes', 'note_id']
}
@ -1763,7 +1794,7 @@ describe('/sample', () => {
req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
}).end((err, res) => {
if (err) return done (err);
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(res.body).have.property('_id').be.type('string');
should(res.body).have.property('number', 'Fe1');
should(res.body).have.property('color', 'black');
@ -1772,6 +1803,7 @@ describe('/sample', () => {
should(res.body).have.property('material_id', '100000000000000000000001');
should(res.body).have.property('note_id').be.type('string');
should(res.body).have.property('user_id', '000000000000000000000004');
should(res.body).have.property('status', 'new');
should(res.body).have.property('added').be.type('string');
should(new Date().getTime() - new Date(res.body.added).getTime()).be.below(1500);
done();
@ -1786,7 +1818,7 @@ describe('/sample', () => {
req: {color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}}
}).end((err, res) => {
if (err) return done (err);
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(res.body).have.property('_id').be.type('string');
should(res.body).have.property('number', 'Rng37');
should(res.body).have.property('color', 'black');
@ -1796,6 +1828,7 @@ describe('/sample', () => {
should(res.body).have.property('material_id', '100000000000000000000001');
should(res.body).have.property('note_id').be.type('string');
should(res.body).have.property('user_id', '000000000000000000000002');
should(res.body).have.property('status', 'new');
should(res.body).have.property('added').be.type('string');
should(new Date().getTime() - new Date(res.body.added).getTime()).be.below(1000);
done();
@ -1830,7 +1863,7 @@ describe('/sample', () => {
req: {number: 'Rng34', color: 'black', type: 'granulate', batch: '1560237365', material_id: '100000000000000000000001', notes: {comment: 'Testcomment', sample_references: [{sample_id: '400000000000000000000003', relation: 'part to this sample'}]}},
}).end((err, res) => {
if (err) return done (err);
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'added');
should(res.body).have.only.keys('_id', 'number', 'color', 'type', 'batch', 'condition', 'material_id', 'note_id', 'user_id', 'status', 'added');
should(res.body).have.property('_id').be.type('string');
should(res.body).have.property('number', 'Rng34');
should(res.body).have.property('color', 'black');
@ -1840,6 +1873,7 @@ describe('/sample', () => {
should(res.body).have.property('material_id', '100000000000000000000001');
should(res.body).have.property('note_id').be.type('string');
should(res.body).have.property('user_id', '000000000000000000000003');
should(res.body).have.property('status', 'new');
should(res.body).have.property('added').be.type('string');
should(new Date().getTime() - new Date(res.body.added).getTime()).be.below(1000);
done();

View File

@ -14,7 +14,6 @@ import IdValidate from './validate/id';
import mongoose from 'mongoose';
import ConditionTemplateModel from '../models/condition_template';
import ParametersValidate from './validate/parameters';
import globals from '../globals';
import db from '../db';
import csv from '../helpers/csv';
@ -32,7 +31,7 @@ const router = express.Router();
router.get('/samples', async (req, res, next) => {
if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
const {error, value: filters} = SampleValidate.query(req.query);
const {error, value: filters} = SampleValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
if (error) return res400(error, res);
// spectral data not allowed for read/write users
@ -431,7 +430,7 @@ router.get('/samples', async (req, res, next) => {
router.get('/samples/:state(new|deleted)', (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
SampleModel.find({status: globals.status[req.params.state]}).lean().exec((err, data) => {
SampleModel.find({status: req.params.state}).lean().exec((err, data) => {
if (err) return next(err);
// validate all and filter null values from validation errors
res.json(_.compact(data.map(e => SampleValidate.output(e))));
@ -461,7 +460,6 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return;
const {error, value: sample} = SampleValidate.input(req.body, 'change');
console.log(error);
if (error) return res400(error, res);
SampleModel.findById(req.params.id).lean().exec(async (err, sampleData: any) => { // check if id exists
@ -469,7 +467,7 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
if (!sampleData) {
return res.status(404).json({status: 'Not found'});
}
if (sampleData.status === globals.status.deleted) {
if (sampleData.status === 'deleted') {
return res.status(403).json({status: 'Forbidden'});
}
@ -520,7 +518,7 @@ router.put('/sample/' + IdValidate.parameter(), (req, res, next) => {
// check for changes
if (!_.isEqual(_.pick(IdValidate.stringify(sampleData), _.keys(sample)), _.omit(sample, ['notes']))) {
sample.status = globals.status.new;
sample.status = 'new';
}
await SampleModel.findByIdAndUpdate(req.params.id, sample, {new: true}).log(req).lean().exec((err, data: any) => {
@ -544,11 +542,11 @@ router.delete('/sample/' + IdValidate.parameter(), (req, res, next) => {
if (sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['dev', 'admin'], 'basic')) return;
// set sample status
await SampleModel.findByIdAndUpdate(req.params.id, {status:globals.status.deleted}).log(req).lean().exec(err => {
await SampleModel.findByIdAndUpdate(req.params.id, {status:'deleted'}).log(req).lean().exec(err => {
if (err) return next(err);
// set status of associated measurements also to deleted
MeasurementModel.updateMany({sample_id: mongoose.Types.ObjectId(req.params.id)}, {status: -1})
MeasurementModel.updateMany({sample_id: mongoose.Types.ObjectId(req.params.id)}, {status: 'deleted'})
.log(req).lean().exec(err => {
if (err) return next(err);
@ -582,7 +580,7 @@ router.get('/sample/number/:number', (req, res, next) => {
router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.new}).log(req).lean().exec((err, data) => {
SampleModel.findByIdAndUpdate(req.params.id, {status: 'new'}).log(req).lean().exec((err, data) => {
if (err) return next(err);
if (!data) {
@ -595,7 +593,7 @@ router.put('/sample/restore/' + IdValidate.parameter(), (req, res, next) => {
router.put('/sample/validate/' + IdValidate.parameter(), (req, res, next) => {
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
SampleModel.findByIdAndUpdate(req.params.id, {status: globals.status.validated}).log(req).lean().exec((err, data) => {
SampleModel.findByIdAndUpdate(req.params.id, {status: 'validated'}).log(req).lean().exec((err, data) => {
if (err) return next(err);
if (!data) {
return res.status(404).json({status: 'Not found'});
@ -628,7 +626,7 @@ router.post('/sample/new', async (req, res, next) => {
if (!await conditionCheck(sample.condition, 'change', res, next)) return;
}
sample.status = globals.status.new; // set status to new
sample.status = 'new'; // set status to new
if (sample.hasOwnProperty('number')) {
if (!await numberCheck(sample, res, next)) return;
}
@ -825,17 +823,7 @@ function sortQuery(filters, sortKeys, sortStartValue) { // sortKeys = ['primary
}
function statusQuery(filters, field) {
if (filters.hasOwnProperty('status')) {
if(filters.status === 'all') {
return {$or: [{[field]: globals.status.validated}, {[field]: globals.status.new}]};
}
else {
return {[field]: globals.status[filters.status]};
}
}
else { // default
return {[field]: globals.status.validated};
}
return {$or: filters.status.map(e => ({[field]: e}))};
}
function addFilterQueries (queryPtr, filters) { // returns array of match queries from given filters
@ -888,13 +876,13 @@ async function sampleReturn (sampleData, req, res, next) {
sampleData = sampleData.toObject();
// deleted samples only available for dev/admin
if (sampleData.status === globals.status.deleted && !req.auth(res, ['dev', 'admin'], 'all')) return;
if (sampleData.status === 'deleted' && !req.auth(res, ['dev', 'admin'], 'all')) return;
sampleData.material = sampleData.material_id; // map data to right keys
sampleData.material.group = sampleData.material.group_id.name;
sampleData.material.supplier = sampleData.material.supplier_id.name;
sampleData.user = sampleData.user_id.name;
sampleData.notes = sampleData.note_id ? sampleData.note_id : {};
MeasurementModel.find({sample_id: sampleData._id, status: {$ne: globals.status.deleted}})
MeasurementModel.find({sample_id: sampleData._id, status: {$ne: 'deleted'}})
.lean().exec((err, data) => {
sampleData.measurements = data;
if (['dev', 'admin'].indexOf(req.authDetails.level) < 0) { // strip dpt values if not dev or admin

View File

@ -303,8 +303,8 @@ describe('/user', () => {
url: '/user',
auth: {basic: 'admin'},
httpStatus: 400,
req: {pass: 'password'},
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|}~'}
req: {pass: 'pass'},
res: {status: 'Invalid body format', details: '"pass" length must be at least 8 characters long'}
});
});
it('rejects requests from non-admins for another user', done => {
@ -585,8 +585,8 @@ describe('/user', () => {
url: '/user/new',
auth: {basic: 'admin'},
httpStatus: 400,
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'password', level: 'read', location: 'Rng', devices: ['Alpha II']},
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|}~'}
req: {email: 'john.doe@bosch.com', name: 'johndoe', pass: 'pass', level: 'read', location: 'Rng', devices: ['Alpha II']},
res: {status: 'Invalid body format', details: '"pass" length must be at least 8 characters long'}
});
});
it('rejects requests from non-admins', done => {

View File

@ -4,6 +4,7 @@ import IdValidate from './id';
import UserValidate from './user';
import MaterialValidate from './material';
import MeasurementValidate from './measurement';
import globals from '../../globals';
export default class SampleValidate {
private static sample = {
@ -49,7 +50,10 @@ export default class SampleValidate {
added: Joi.date()
.iso()
.min('1970-01-01T00:00:00.000Z')
.min('1970-01-01T00:00:00.000Z'),
status: Joi.string()
.valid(...globals.status)
};
private static sortKeys = [
@ -59,6 +63,7 @@ export default class SampleValidate {
'type',
'batch',
'added',
'status',
'material.name',
'material.supplier',
'material.group',
@ -137,7 +142,8 @@ export default class SampleValidate {
note_id: IdValidate.get().allow(null),
notes: this.sample.notes,
user_id: IdValidate.get(),
added: this.sample.added
added: this.sample.added,
status: this.sample.status
};
}
else if(param === 'details') {
@ -151,7 +157,8 @@ export default class SampleValidate {
material: MaterialValidate.outputV(),
measurements: Joi.array().items(MeasurementValidate.outputV()),
notes: this.sample.notes,
user: UserValidate.username()
user: UserValidate.username(),
status: this.sample.status
}
}
else {
@ -164,7 +171,7 @@ export default class SampleValidate {
return error !== undefined? null : value;
}
static query (data) {
static query (data, dev = false) {
if (data.filters && data.filters.length) {
const filterValidation = Joi.array().items(Joi.string()).validate(data.filters);
if (filterValidation.error) return filterValidation;
@ -208,8 +215,12 @@ export default class SampleValidate {
return {error: {details: [{message: 'Invalid JSON string for filter parameter'}]}, value: null}
}
}
const acceptedStatuses = ['validated', 'new'];
if (dev) { // dev and admin can also access deleted samples
acceptedStatuses.push('deleted')
}
return Joi.object({
status: Joi.string().valid('validated', 'new', 'all'),
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default(['validated']),
'from-id': IdValidate.get(),
'to-page': Joi.number().integer(),
'page-size': Joi.number().integer().min(1),

View File

@ -17,9 +17,8 @@ export default class UserValidate { // validate input for user
.max(128),
pass: Joi.string()
.pattern(/^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!"#%&'()*+,-.\/:;<=>?@[\]^_`{|}~])(?=\S+$)[a-zA-Z0-9!"#%&'()*+,\-.\/:;<=>?@[\]^_`{|}~]{8,}$/)
.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: !"\\#%&\'()*+,-.\\/:;<=>?@[]^_`\\{|}~'}),
.min(8)
.max(128),
level: Joi.string()
.valid(...globals.levels),
@ -82,7 +81,6 @@ export default class UserValidate { // validate input for user
location: this.user.location,
devices: this.user.devices
}).validate(data, {stripUnknown: true});
console.log(data);
return error !== undefined? null : value;
}

View File

@ -15,7 +15,7 @@
"material_id": {"$oid":"100000000000000000000004"},
"note_id": null,
"user_id": {"$oid":"000000000000000000000002"},
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -32,7 +32,7 @@
"material_id": {"$oid":"100000000000000000000001"},
"note_id": {"$oid":"500000000000000000000001"},
"user_id": {"$oid":"000000000000000000000002"},
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -49,7 +49,7 @@
"material_id": {"$oid":"100000000000000000000005"},
"note_id": {"$oid":"500000000000000000000002"},
"user_id": {"$oid":"000000000000000000000003"},
"status": 0,
"status": "new",
"__v": 0
},
{
@ -65,7 +65,7 @@
"material_id": {"$oid":"100000000000000000000005"},
"note_id": {"$oid":"500000000000000000000003"},
"user_id": {"$oid":"000000000000000000000003"},
"status": 0,
"status": "new",
"__v": 0
},
{
@ -80,7 +80,7 @@
"material_id": {"$oid":"100000000000000000000005"},
"note_id": null,
"user_id": {"$oid":"000000000000000000000003"},
"status": -1,
"status": "deleted",
"__v": 0
},
{
@ -93,7 +93,7 @@
"material_id": {"$oid":"100000000000000000000004"},
"note_id": null,
"user_id": {"$oid":"000000000000000000000002"},
"status": 0,
"status": "new",
"__v": 0
},
{
@ -106,7 +106,7 @@
"material_id": {"$oid":"100000000000000000000009"},
"note_id": null,
"user_id": {"$oid":"000000000000000000000002"},
"status": 0,
"status": "new",
"__v": 0
}
],
@ -173,7 +173,7 @@
"5514263423",
"5514263422"
],
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -191,7 +191,7 @@
"5514212901",
"5514612901"
],
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -207,7 +207,7 @@
},
"numbers": [
],
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -224,7 +224,7 @@
"numbers": [
"5513933405"
],
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -241,7 +241,7 @@
"numbers": [
"5514262406"
],
"status": 10,
"status": "validated",
"__v": 0
},
{
@ -258,7 +258,7 @@
"numbers": [
"1000000000"
],
"status": -1,
"status": "deleted",
"__v": 0
},
{
@ -274,7 +274,7 @@
},
"numbers": [
],
"status": 0,
"status": "new",
"__v": 0
},
{
@ -291,7 +291,7 @@
"numbers": [
"5513943509"
],
"status": -1,
"status": "deleted",
"__v": 0
},
{
@ -306,7 +306,7 @@
"numbers": [
"5513943509"
],
"status": 0,
"status": "new",
"__v": 0
},
{
@ -321,7 +321,7 @@
"numbers": [
"5513943509"
],
"status": 0,
"status": "new",
"__v": 0
}
],
@ -406,7 +406,7 @@
],
"device": "Alpha I"
},
"status": 10,
"status": "validated",
"measurement_template": {"$oid":"300000000000000000000001"},
"__v": 0
},
@ -417,7 +417,7 @@
"weight %": 0.5,
"standard deviation": 0.2
},
"status": 10,
"status": "validated",
"measurement_template": {"$oid":"300000000000000000000002"},
"__v": 0
},
@ -427,7 +427,7 @@
"values": {
"val1": 1
},
"status": 0,
"status": "new",
"measurement_template": {"$oid":"300000000000000000000003"},
"__v": 0
},
@ -437,7 +437,7 @@
"values": {
"val1": 1
},
"status": -1,
"status": "deleted",
"measurement_template": {"$oid":"300000000000000000000003"},
"__v": 0
},
@ -448,7 +448,7 @@
"weight %": 0.5,
"standard deviation":null
},
"status": 10,
"status": "validated",
"measurement_template": {"$oid":"300000000000000000000002"},
"__v": 0
},
@ -459,7 +459,7 @@
"weight %": 0.6,
"standard deviation":null
},
"status": 0,
"status": "new",
"measurement_template": {"$oid":"300000000000000000000002"},
"__v": 0
},
@ -474,7 +474,7 @@
],
"device": "Alpha II"
},
"status": 10,
"status": "validated",
"measurement_template": {"$oid":"300000000000000000000001"},
"__v": 0
}