import express from 'express'; import _ from 'lodash'; import MeasurementModel from '../models/measurement'; import MeasurementTemplateModel from '../models/measurement_template'; import SampleModel from '../models/sample'; import MeasurementValidate from './validate/measurement'; import IdValidate from './validate/id'; import res400 from './validate/res400'; import ParametersValidate from './validate/parameters'; import globals from '../globals'; import db from '../db'; const router = express.Router(); router.get('/measurement/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['read', 'write', 'dev', 'admin'], 'all')) return; MeasurementModel.findById(req.params.id).lean().exec((err, data: any) => { if (err) return next(err); if (!data) { 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; res.json(MeasurementValidate.output(data, req)); }); }); router.put('/measurement/' + IdValidate.parameter(), async (req, res, next) => { if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return; const {error, value: measurement} = MeasurementValidate.input(req.body, 'change'); if (error) return res400(error, res); const data = await MeasurementModel.findById(req.params.id).lean().exec().catch(err => {next(err);}) as any; if (data instanceof Error) return; if (!data) { return res.status(404).json({status: 'Not found'}); } if (data.status === globals.status.deleted) { return res.status(403).json({status: 'Forbidden'}); } // add properties needed for sampleIdCheck measurement.measurement_template = data.measurement_template; measurement.sample_id = data.sample_id; if (!await sampleIdCheck(measurement, req, res, next)) return; // check for changes 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 } } if (!await templateCheck(measurement, 'change', res, next)) return; await MeasurementModel.findByIdAndUpdate(req.params.id, measurement, {new: true}) .log(req).lean().exec((err, data) => { if (err) return next(err); res.json(MeasurementValidate.output(data, req)); }); }); router.delete('/measurement/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return; MeasurementModel.findById(req.params.id).lean().exec(async (err, data) => { if (err) return next(err); if (!data) { 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}) .log(req).lean().exec(err => { if (err) return next(err); return res.json({status: 'OK'}); }); }); }); router.put('/measurement/restore/' + IdValidate.parameter(), (req, res, next) => { if (!req.auth(res, ['dev', 'admin'], 'basic')) return; setStatus(globals.status.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); }); router.post('/measurement/new', async (req, res, next) => { if (!req.auth(res, ['write', 'dev', 'admin'], 'basic')) return; const {error, value: measurement} = MeasurementValidate.input(req.body, 'new'); if (error) return res400(error, res); if (!await sampleIdCheck(measurement, req, res, next)) return; measurement.values = await templateCheck(measurement, 'new', res, next); if (!measurement.values) return; measurement.status = 0; await new MeasurementModel(measurement).save((err, data) => { if (err) return next(err); db.log(req, 'measurements', {_id: data._id}, data.toObject()); res.json(MeasurementValidate.output(data.toObject(), req)); }); }); module.exports = router; // validate sample_id, returns false if invalid or user has no access for this sample async function sampleIdCheck (measurement, req, res, next) { const sampleData = await SampleModel.findById(measurement.sample_id) .lean().exec().catch(err => {next(err); return false;}) as any; if (!sampleData) { // sample_id not found res.status(400).json({status: 'Sample id not available'}); return false } // sample does not belong to user return !(sampleData.user_id.toString() !== req.authDetails.id && !req.auth(res, ['dev', 'admin'], 'basic')); } // validate measurement_template and values, returns values, true if values are {} or false if invalid, // param for 'new'/'change' async function templateCheck (measurement, param, res, next) { const templateData = await MeasurementTemplateModel.findById(measurement.measurement_template) .lean().exec().catch(err => {next(err); return false;}) as any; if (!templateData) { // template not found res.status(400).json({status: 'Measurement template not available'}); return false } // fill not given values for new measurements if (param === 'new') { // get all template versions and check if given is latest const templateVersions = await MeasurementTemplateModel.find({first_id: templateData.first_id}).sort({version: -1}) .lean().exec().catch(err => next(err)) as any; if (templateVersions instanceof Error) return false; if (measurement.measurement_template !== templateVersions[0]._id.toString()) { // template not latest res.status(400).json({status: 'Old template version not allowed'}); return false; } if (Object.keys(measurement.values).length === 0) { res.status(400).json({status: 'At least one value is required'}); return false } const fillValues = {}; // initialize not given values with null templateData.parameters.forEach(parameter => { fillValues[parameter.name] = null; }); measurement.values = _.assign({}, fillValues, measurement.values); } // validate values const {error, value} = ParametersValidate.input(measurement.values, templateData.parameters, 'null'); if (error) {res400(error, res); return false;} return value || true; } function setStatus (status, req, res, next) { // set measurement status MeasurementModel.findByIdAndUpdate(req.params.id, {status: status}).log(req).lean().exec((err, data) => { if (err) return next(err); if (!data) { return res.status(404).json({status: 'Not found'}); } res.json({status: 'OK'}); }); }