Merge pull request #36 in ~VLE2FE/definma-api from develop to master
* commit '3fbd6ccec37bb7844578a8611c8ee3a3e5523589': updated sample restore and validate added /measurement/sample/{id} route
This commit is contained in:
commit
e5abb4ae69
@ -77,6 +77,40 @@
|
|||||||
500:
|
500:
|
||||||
$ref: 'api.yaml#/components/responses/500'
|
$ref: 'api.yaml#/components/responses/500'
|
||||||
|
|
||||||
|
/measurement/sample/{id}:
|
||||||
|
parameters:
|
||||||
|
- $ref: 'api.yaml#/components/parameters/Id'
|
||||||
|
get:
|
||||||
|
summary: all measurements of the given sample
|
||||||
|
description: 'Auth: basic, levels: dev, admin'
|
||||||
|
tags:
|
||||||
|
- /measurement
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: measurement details
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
allOf:
|
||||||
|
- $ref: 'api.yaml#/components/schemas/Measurement'
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
description: can be deleted/new/validated
|
||||||
|
example: new
|
||||||
|
401:
|
||||||
|
$ref: 'api.yaml#/components/responses/401'
|
||||||
|
403:
|
||||||
|
$ref: 'api.yaml#/components/responses/403'
|
||||||
|
404:
|
||||||
|
$ref: 'api.yaml#/components/responses/404'
|
||||||
|
500:
|
||||||
|
$ref: 'api.yaml#/components/responses/500'
|
||||||
|
|
||||||
/measurement/restore/{id}:
|
/measurement/restore/{id}:
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: 'api.yaml#/components/parameters/Id'
|
- $ref: 'api.yaml#/components/parameters/Id'
|
||||||
|
@ -404,6 +404,60 @@ describe('/measurement', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GET /measurement/sample/{id}', () => {
|
||||||
|
it('returns the right measurements', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/400000000000000000000003',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 200,
|
||||||
|
res: [
|
||||||
|
{_id: '800000000000000000000003', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003', status: 'new'},
|
||||||
|
{_id: '800000000000000000000004', sample_id: '400000000000000000000003', values: {val1: 1}, measurement_template: '300000000000000000000003', status: 'deleted'}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an API key', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/400000000000000000000003',
|
||||||
|
auth: {key: 'admin'},
|
||||||
|
httpStatus: 401
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects a write user', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/400000000000000000000003',
|
||||||
|
auth: {basic: 'janedoe'},
|
||||||
|
httpStatus: 403
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an invalid id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/4000000000h0000000000003',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects an unknown id', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/000000000000000000000003',
|
||||||
|
auth: {basic: 'admin'},
|
||||||
|
httpStatus: 404
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects unauthorized requests', done => {
|
||||||
|
TestHelper.request(server, done, {
|
||||||
|
method: 'get',
|
||||||
|
url: '/measurement/sample/400000000000000000000003',
|
||||||
|
httpStatus: 401
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('PUT /measurement/restore/{id}', () => {
|
describe('PUT /measurement/restore/{id}', () => {
|
||||||
it('sets the status', done => {
|
it('sets the status', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
|
@ -10,6 +10,7 @@ import res400 from './validate/res400';
|
|||||||
import ParametersValidate from './validate/parameters';
|
import ParametersValidate from './validate/parameters';
|
||||||
import db from '../db';
|
import db from '../db';
|
||||||
import globals from '../globals';
|
import globals from '../globals';
|
||||||
|
import mongoose from "mongoose";
|
||||||
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -82,6 +83,19 @@ router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/measurement/sample/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
|
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
|
MeasurementModel.find({sample_id: mongoose.Types.ObjectId(req.params.id)}).lean().exec((err, data: any) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
if (!data.length) {
|
||||||
|
return res.status(404).json({status: 'Not found'});
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(_.compact(data.map(e => MeasurementValidate.output(e, req, true))));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => {
|
router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => {
|
||||||
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
|
if (!req.auth(res, ['dev', 'admin'], 'basic')) return;
|
||||||
|
|
||||||
|
@ -271,7 +271,7 @@ describe('/sample', () => {
|
|||||||
it('adds the specified measurements', done => {
|
it('adds the specified measurements', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.kf',
|
url: '/samples?status[]=new&status[]=validated&fields[]=number&fields[]=measurements.kf.weight%20%25&fields[]=measurements.kf.standard%20deviation',
|
||||||
auth: {basic: 'janedoe'},
|
auth: {basic: 'janedoe'},
|
||||||
httpStatus: 200
|
httpStatus: 200
|
||||||
}).end((err, res) => {
|
}).end((err, res) => {
|
||||||
@ -1525,22 +1525,23 @@ describe('/sample', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('creates a changelog', done => {
|
it('restores associated measurements', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/sample/restore/400000000000000000000005',
|
url: '/sample/restore/400000000000000000000005',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
req: {}
|
||||||
log: {
|
}).end((err, res) => {
|
||||||
collection: 'samples',
|
if (err) return done (err);
|
||||||
dataAdd: {
|
should(res.body).be.eql({status: 'OK'});
|
||||||
group_id: '900000000000000000000002',
|
MeasurementModel.find({sample_id: mongoose.Types.ObjectId('400000000000000000000005')}).lean().exec((err, data: any) => {
|
||||||
supplier_id: '110000000000000000000002',
|
if (err) return done(err);
|
||||||
status: 'new'
|
should(data).matchEach(measurement => {
|
||||||
},
|
should(measurement).have.property('status', 'new')
|
||||||
dataIgn: ['group_id', 'supplier_id']
|
});
|
||||||
}
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('rejects an API key', done => {
|
it('rejects an API key', done => {
|
||||||
@ -1598,22 +1599,23 @@ describe('/sample', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('creates a changelog', done => {
|
it('validates associated measurements', done => {
|
||||||
TestHelper.request(server, done, {
|
TestHelper.request(server, done, {
|
||||||
method: 'put',
|
method: 'put',
|
||||||
url: '/sample/validate/400000000000000000000003',
|
url: '/sample/validate/400000000000000000000003',
|
||||||
auth: {basic: 'admin'},
|
auth: {basic: 'admin'},
|
||||||
httpStatus: 200,
|
httpStatus: 200,
|
||||||
req: {},
|
req: {}
|
||||||
log: {
|
}).end((err, res) => {
|
||||||
collection: 'samples',
|
if (err) return done (err);
|
||||||
dataAdd: {
|
should(res.body).be.eql({status: 'OK'});
|
||||||
group_id: '900000000000000000000002',
|
MeasurementModel.find({sample_id: mongoose.Types.ObjectId('400000000000000000000003')}).lean().exec((err, data: any) => {
|
||||||
supplier_id: '110000000000000000000002',
|
if (err) return done(err);
|
||||||
status: 'validated'
|
should(data).matchEach(measurement => {
|
||||||
},
|
should(measurement).have.property('status', 'validated')
|
||||||
dataIgn: ['group_id', 'supplier_id']
|
});
|
||||||
}
|
done();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('allows validating a sample without condition', done => {
|
it('allows validating a sample without condition', done => {
|
||||||
|
@ -29,6 +29,7 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
|
if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return;
|
||||||
|
|
||||||
const {error, value: filters} = SampleValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
|
const {error, value: filters} = SampleValidate.query(req.query, ['dev', 'admin'].indexOf(req.authDetails.level) >= 0);
|
||||||
|
console.log(error);
|
||||||
if (error) return res400(error, res);
|
if (error) return res400(error, res);
|
||||||
console.log(filters.filters);
|
console.log(filters.filters);
|
||||||
|
|
||||||
@ -221,7 +222,6 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
const measurementFilterFields = _.uniq(sortFilterKeys.filter(e => /measurements\./.test(e))
|
const measurementFilterFields = _.uniq(sortFilterKeys.filter(e => /measurements\./.test(e))
|
||||||
.map(e => e.split('.')[1])); // filter measurement names and remove duplicates from parameters
|
.map(e => e.split('.')[1])); // filter measurement names and remove duplicates from parameters
|
||||||
if (sortFilterKeys.find(e => /measurements\./.test(e))) { // add measurement fields
|
if (sortFilterKeys.find(e => /measurements\./.test(e))) { // add measurement fields
|
||||||
console.log(measurementFilterFields);
|
|
||||||
const measurementTemplates = await MeasurementTemplateModel.find({name: {$in: measurementFilterFields}})
|
const measurementTemplates = await MeasurementTemplateModel.find({name: {$in: measurementFilterFields}})
|
||||||
.lean().exec().catch(err => {next(err);});
|
.lean().exec().catch(err => {next(err);});
|
||||||
if (measurementTemplates instanceof Error) return;
|
if (measurementTemplates instanceof Error) return;
|
||||||
@ -233,12 +233,7 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
pipeline: [{$match: {$expr: {$and: [
|
pipeline: [{$match: {$expr: {$and: [
|
||||||
{$eq: ['$sample_id', '$$sId']},
|
{$eq: ['$sample_id', '$$sId']},
|
||||||
{$in: ['$measurement_template', measurementTemplates.map(e => mongoose.Types.ObjectId(e._id))]}
|
{$in: ['$measurement_template', measurementTemplates.map(e => mongoose.Types.ObjectId(e._id))]}
|
||||||
]}}},
|
]}}}
|
||||||
{$project: _.merge(
|
|
||||||
filters.fields.filter(e => /measurements\./.test(e))
|
|
||||||
.map(e => 'values.' + e.split('.')[2]).reduce((s, e) => {s[e] = true; return s; }, {}),
|
|
||||||
{measurement_template: true, status: true, sample_id: true}
|
|
||||||
)}
|
|
||||||
],
|
],
|
||||||
as: 'measurements'
|
as: 'measurements'
|
||||||
}});
|
}});
|
||||||
@ -367,6 +362,7 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
projection._id = false;
|
projection._id = false;
|
||||||
}
|
}
|
||||||
queryPtr.push({$project: projection});
|
queryPtr.push({$project: projection});
|
||||||
|
console.log(JSON.stringify(query));
|
||||||
// use streaming when including spectrum files
|
// use streaming when including spectrum files
|
||||||
if (!fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.' + globals.spectrum.dpt) >= 0)) {
|
if (!fieldsToAdd.find(e => e.indexOf(globals.spectrum.spectrum + '.' + globals.spectrum.dpt) >= 0)) {
|
||||||
collection.aggregate(query).allowDiskUse(true).exec((err, data) => {
|
collection.aggregate(query).allowDiskUse(true).exec((err, data) => {
|
||||||
@ -904,6 +900,11 @@ function setStatus (status, req, res, next) {
|
|||||||
if (!data) {
|
if (!data) {
|
||||||
return res.status(404).json({status: 'Not found'});
|
return res.status(404).json({status: 'Not found'});
|
||||||
}
|
}
|
||||||
|
MeasurementModel.updateMany({sample_id: mongoose.Types.ObjectId(req.params.id)}, {status})
|
||||||
|
.log(req).lean().exec(err => {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
res.json({status: 'OK'});
|
res.json({status: 'OK'});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
@ -36,18 +36,23 @@ export default class MeasurementValidate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static output (data, req) { // validate output and strip unwanted properties, returns null if not valid
|
// validate output and strip unwanted properties, returns null if not valid
|
||||||
|
static output (data, req, status = false) {
|
||||||
data = IdValidate.stringify(data);
|
data = IdValidate.stringify(data);
|
||||||
// spectral data not allowed for read/write users
|
// spectral data not allowed for read/write users
|
||||||
if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values[globals.spectrum.dpt]) {
|
if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values[globals.spectrum.dpt]) {
|
||||||
delete data.values[globals.spectrum.dpt];
|
delete data.values[globals.spectrum.dpt];
|
||||||
}
|
}
|
||||||
const {value, error} = Joi.object({
|
const validation: any = {
|
||||||
_id: IdValidate.get(),
|
_id: IdValidate.get(),
|
||||||
sample_id: IdValidate.get(),
|
sample_id: IdValidate.get(),
|
||||||
values: this.measurement.values,
|
values: this.measurement.values,
|
||||||
measurement_template: IdValidate.get()
|
measurement_template: IdValidate.get()
|
||||||
}).validate(data, {stripUnknown: true});
|
};
|
||||||
|
if (status) {
|
||||||
|
validation.status = Joi.string().valid(...Object.values(globals.status));
|
||||||
|
}
|
||||||
|
const {value, error} = Joi.object(validation).validate(data, {stripUnknown: true});
|
||||||
return error !== undefined? null : value;
|
return error !== undefined? null : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,9 +192,11 @@ export default class SampleValidate {
|
|||||||
if (filterValidation.error) return filterValidation;
|
if (filterValidation.error) return filterValidation;
|
||||||
try {
|
try {
|
||||||
for (let i in data.filters) {
|
for (let i in data.filters) {
|
||||||
// data.filters[i] = JSON.parse(decodeURIComponent(data.filters[i]));
|
try {
|
||||||
data.filters[i] = JSON.parse(decodeURIComponent(data.filters[i]));
|
data.filters[i] = decodeURIComponent(data.filters[i]);
|
||||||
console.log(data.filters[i]);
|
}
|
||||||
|
catch (ignore) {}
|
||||||
|
data.filters[i] = JSON.parse(data.filters[i]);
|
||||||
data.filters[i].values = data.filters[i].values.map(e => { // validate filter values
|
data.filters[i].values = data.filters[i].values.map(e => { // validate filter values
|
||||||
if (e === null) { // null values are always allowed
|
if (e === null) { // null values are always allowed
|
||||||
return null;
|
return null;
|
||||||
@ -225,6 +227,7 @@ export default class SampleValidate {
|
|||||||
validator = Joi.object(this.sample);
|
validator = Joi.object(this.sample);
|
||||||
}
|
}
|
||||||
const {value, error} = validator.validate({[field]: e});
|
const {value, error} = validator.validate({[field]: e});
|
||||||
|
console.log(error);
|
||||||
if (error) throw error; // reject invalid values
|
if (error) throw error; // reject invalid values
|
||||||
return value[field];
|
return value[field];
|
||||||
});
|
});
|
||||||
|
@ -477,6 +477,21 @@
|
|||||||
"status": "validated",
|
"status": "validated",
|
||||||
"measurement_template": {"$oid":"300000000000000000000001"},
|
"measurement_template": {"$oid":"300000000000000000000001"},
|
||||||
"__v": 0
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": {"$oid":"800000000000000000000008"},
|
||||||
|
"sample_id": {"$oid":"400000000000000000000005"},
|
||||||
|
"values": {
|
||||||
|
"dpt": [
|
||||||
|
[3996.12558,98.00555],
|
||||||
|
[3995.08519,98.03253],
|
||||||
|
[3993.04480,98.02657]
|
||||||
|
],
|
||||||
|
"device": "Alpha II"
|
||||||
|
},
|
||||||
|
"status": "deleted",
|
||||||
|
"measurement_template": {"$oid":"300000000000000000000001"},
|
||||||
|
"__v": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"condition_templates": [
|
"condition_templates": [
|
||||||
|
Reference in New Issue
Block a user