2020-05-12 12:15:36 +02:00
import express from 'express' ;
2020-05-12 17:15:36 +02:00
import _ from 'lodash' ;
2020-05-12 12:15:36 +02:00
import MeasurementModel from '../models/measurement' ;
import MeasurementTemplateModel from '../models/measurement_template' ;
2020-05-27 17:03:03 +02:00
import SampleModel from '../models/sample' ;
2020-05-12 12:15:36 +02:00
import MeasurementValidate from './validate/measurement' ;
import IdValidate from './validate/id' ;
import res400 from './validate/res400' ;
import ParametersValidate from './validate/parameters' ;
2020-05-27 14:31:17 +02:00
import globals from '../globals' ;
2020-05-12 12:15:36 +02:00
const router = express . Router ( ) ;
router . get ( '/measurement/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'all' ) ) return ;
2020-05-27 17:03:03 +02:00
MeasurementModel . findById ( req . params . id ) . lean ( ) . exec ( ( err , data : any ) = > {
2020-05-12 12:15:36 +02:00
if ( err ) return next ( err ) ;
if ( ! data ) {
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
2020-05-27 17:03:03 +02:00
if ( data . status === globals . status . deleted && ! req . auth ( res , [ 'maintain' , 'admin' ] , 'all' ) ) return ; // deleted measurements only available for maintain/admin
2020-05-12 12:15:36 +02:00
res . json ( MeasurementValidate . output ( data ) ) ;
} ) ;
} ) ;
2020-05-12 17:15:36 +02:00
router . put ( '/measurement/' + IdValidate . parameter ( ) , async ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'write' , 'maintain' , '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 ;
2020-05-14 15:36:47 +02:00
if ( data instanceof Error ) return ;
2020-05-12 17:15:36 +02:00
if ( ! data ) {
2020-05-28 11:47:51 +02:00
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
2020-05-12 17:15:36 +02:00
}
2020-05-28 13:16:15 +02:00
if ( data . status === globals . status . deleted ) {
return res . status ( 403 ) . json ( { status : 'Forbidden' } ) ;
}
2020-05-18 14:47:22 +02:00
2020-05-27 17:03:03 +02:00
// add properties needed for sampleIdCheck
2020-05-12 17:15:36 +02:00
measurement . measurement_template = data . measurement_template ;
2020-05-27 17:03:03 +02:00
measurement . sample_id = data . sample_id ;
if ( ! await sampleIdCheck ( measurement , req , res , next ) ) return ;
2020-05-18 14:47:22 +02:00
// check for changes
2020-05-27 17:03:03 +02:00
if ( measurement . values ) { // fill not changed values from database
2020-05-13 09:56:44 +02:00
measurement . values = _ . assign ( { } , data . values , measurement . values ) ;
if ( ! _ . isEqual ( measurement . values , data . values ) ) {
2020-05-27 14:31:17 +02:00
measurement . status = globals . status . new ; // set status to new
2020-05-13 09:56:44 +02:00
}
2020-05-12 17:15:36 +02:00
}
2020-05-18 14:47:22 +02:00
2020-05-12 17:15:36 +02:00
if ( ! await templateCheck ( measurement , 'change' , res , next ) ) return ;
await MeasurementModel . findByIdAndUpdate ( req . params . id , measurement , { new : true } ) . lean ( ) . exec ( ( err , data ) = > {
if ( err ) return next ( err ) ;
res . json ( MeasurementValidate . output ( data ) ) ;
} ) ;
} ) ;
2020-05-12 17:37:01 +02:00
router . delete ( '/measurement/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
MeasurementModel . findById ( req . params . id ) . lean ( ) . exec ( async ( err , data ) = > {
if ( err ) return next ( err ) ;
if ( ! data ) {
2020-05-28 11:47:51 +02:00
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
2020-05-12 17:37:01 +02:00
}
2020-05-27 17:03:03 +02:00
if ( ! await sampleIdCheck ( data , req , res , next ) ) return ;
2020-05-27 14:31:17 +02:00
await MeasurementModel . findByIdAndUpdate ( req . params . id , { status :globals.status.deleted } ) . lean ( ) . exec ( err = > {
2020-05-12 17:37:01 +02:00
if ( err ) return next ( err ) ;
2020-05-28 11:47:51 +02:00
return res . json ( { status : 'OK' } ) ;
2020-05-12 17:37:01 +02:00
} ) ;
} ) ;
} ) ;
2020-05-28 15:03:49 +02:00
router . put ( '/measurement/restore/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return ;
2020-05-29 11:28:35 +02:00
setStatus ( globals . status . new , req , res , next ) ;
} ) ;
2020-05-28 15:03:49 +02:00
2020-05-29 11:28:35 +02:00
router . put ( '/measurement/validate/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return ;
setStatus ( globals . status . validated , req , res , next ) ;
2020-05-28 15:03:49 +02:00
} ) ;
2020-05-12 12:15:36 +02:00
router . post ( '/measurement/new' , async ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
const { error , value : measurement } = MeasurementValidate . input ( req . body , 'new' ) ;
if ( error ) return res400 ( error , res ) ;
2020-05-27 17:03:03 +02:00
if ( ! await sampleIdCheck ( measurement , req , res , next ) ) return ;
measurement . values = await templateCheck ( measurement , 'new' , res , next ) ;
if ( ! measurement . values ) return ;
2020-05-12 12:15:36 +02:00
2020-05-12 17:15:36 +02:00
measurement . status = 0 ;
2020-05-12 12:15:36 +02:00
await new MeasurementModel ( measurement ) . save ( ( err , data ) = > {
if ( err ) return next ( err ) ;
res . json ( MeasurementValidate . output ( data . toObject ( ) ) ) ;
} ) ;
} ) ;
module . exports = router ;
2020-05-27 17:03:03 +02:00
async function sampleIdCheck ( measurement , req , res , next ) { // validate sample_id, returns false if invalid or user has no access for this sample
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' } ) ;
2020-05-12 12:15:36 +02:00
return false
2020-05-27 17:03:03 +02:00
}
if ( sampleData . user_id . toString ( ) !== req . authDetails . id && ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return false ; // sample does not belong to user
return true ;
2020-05-12 12:15:36 +02:00
}
2020-05-27 17:03:03 +02:00
async function templateCheck ( measurement , param , res , next ) { // validate measurement_template and values, returns values, true if values are {} or false if invalid, param for 'new'/'change'
2020-05-12 12:15:36 +02:00
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
}
2020-05-27 17:03:03 +02:00
// fill not given values for new measurements
if ( param === 'new' ) {
2020-06-02 10:24:22 +02:00
// 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 ;
}
2020-05-27 17:03:03 +02:00
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 ) ;
}
2020-05-12 12:15:36 +02:00
// validate values
2020-05-27 17:03:03 +02:00
const { error , value } = ParametersValidate . input ( measurement . values , templateData . parameters , 'null' ) ;
2020-05-12 12:15:36 +02:00
if ( error ) { res400 ( error , res ) ; return false ; }
2020-05-27 17:03:03 +02:00
return value || true ;
2020-05-29 11:28:35 +02:00
}
function setStatus ( status , req , res , next ) { // set measurement status
MeasurementModel . findByIdAndUpdate ( req . params . id , { status : status } ) . lean ( ) . exec ( ( err , data ) = > {
if ( err ) return next ( err ) ;
if ( ! data ) {
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
res . json ( { status : 'OK' } ) ;
} ) ;
2020-05-12 12:15:36 +02:00
}