2020-04-29 12:10:27 +02:00
import express from 'express' ;
2020-05-12 17:15:36 +02:00
import _ from 'lodash' ;
2020-04-29 12:10:27 +02:00
import MaterialValidate from './validate/material' ;
import MaterialModel from '../models/material'
2020-05-08 09:58:12 +02:00
import SampleModel from '../models/sample' ;
2020-05-29 10:40:17 +02:00
import MaterialGroupModel from '../models/material_groups' ;
import MaterialSupplierModel from '../models/material_suppliers' ;
2020-04-29 12:10:27 +02:00
import IdValidate from './validate/id' ;
2020-05-07 21:55:29 +02:00
import res400 from './validate/res400' ;
2020-05-08 09:58:12 +02:00
import mongoose from 'mongoose' ;
2020-05-27 14:31:17 +02:00
import globals from '../globals' ;
2020-06-05 08:50:06 +02:00
import db from '../db' ;
2020-07-15 13:11:33 +02:00
import MaterialTemplateModel from '../models/material_template' ;
import ParametersValidate from './validate/parameters' ;
2020-04-29 12:10:27 +02:00
2020-05-13 17:28:18 +02:00
2020-04-29 12:10:27 +02:00
const router = express . Router ( ) ;
router . get ( '/materials' , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'all' ) ) return ;
2020-06-17 13:42:14 +02:00
const { error , value : filters } = MaterialValidate . query ( req . query ) ;
if ( error ) return res400 ( error , res ) ;
let conditions ;
if ( filters . hasOwnProperty ( 'status' ) ) {
if ( filters . status === 'all' ) {
conditions = { $or : [ { status : globals.status.validated } , { status : globals.status.new } ] }
}
else {
conditions = { status : globals.status [ filters . status ] } ;
}
}
else { // default
conditions = { status : globals.status.validated } ;
}
MaterialModel . find ( conditions ) . populate ( 'group_id' ) . populate ( 'supplier_id' ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-06 14:39:04 +02:00
if ( err ) return next ( err ) ;
2020-05-29 10:40:17 +02:00
2020-05-12 17:15:36 +02:00
res . json ( _ . compact ( data . map ( e = > MaterialValidate . output ( e ) ) ) ) ; // validate all and filter null values from validation errors
2020-04-29 12:10:27 +02:00
} ) ;
2020-05-18 10:43:26 +02:00
} ) ;
2020-05-28 17:05:23 +02:00
router . get ( '/materials/:state(new|deleted)' , ( req , res , next ) = > {
2020-05-18 10:43:26 +02:00
if ( ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return ;
2020-05-28 17:05:23 +02:00
MaterialModel . find ( { status : globals.status [ req . params . state ] } ) . populate ( 'group_id' ) . populate ( 'supplier_id' ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-18 10:43:26 +02:00
if ( err ) return next ( err ) ;
2020-05-29 10:40:17 +02:00
2020-05-18 10:43:26 +02:00
res . json ( _ . compact ( data . map ( e = > MaterialValidate . output ( e ) ) ) ) ; // validate all and filter null values from validation errors
} ) ;
2020-04-29 12:10:27 +02:00
} ) ;
router . get ( '/material/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'all' ) ) return ;
2020-05-28 17:05:23 +02:00
MaterialModel . findById ( req . params . id ) . populate ( 'group_id' ) . populate ( 'supplier_id' ) . lean ( ) . exec ( ( err , data : any ) = > {
2020-05-06 14:39:04 +02:00
if ( err ) return next ( err ) ;
2020-05-28 14:11:19 +02:00
if ( ! data ) {
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
2020-04-29 12:10:27 +02:00
}
2020-05-28 17:05:23 +02:00
2020-05-28 14:11:19 +02:00
if ( data . status === globals . status . deleted && ! req . auth ( res , [ 'maintain' , 'admin' ] , 'all' ) ) return ; // deleted materials only available for maintain/admin
res . json ( MaterialValidate . output ( data ) ) ;
2020-04-29 12:10:27 +02:00
} ) ;
} ) ;
2020-04-29 16:09:31 +02:00
router . put ( '/material/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
2020-05-29 10:40:17 +02:00
let { error , value : material } = MaterialValidate . input ( req . body , 'change' ) ;
2020-05-07 21:55:29 +02:00
if ( error ) return res400 ( error , res ) ;
2020-04-29 16:09:31 +02:00
2020-05-13 14:18:15 +02:00
MaterialModel . findById ( req . params . id ) . lean ( ) . exec ( async ( err , materialData : any ) = > {
if ( ! materialData ) {
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
2020-05-28 14:11:19 +02:00
if ( materialData . status === globals . status . deleted ) {
return res . status ( 403 ) . json ( { status : 'Forbidden' } ) ;
}
2020-05-13 14:18:15 +02:00
if ( material . hasOwnProperty ( 'name' ) && material . name !== materialData . name ) {
if ( ! await nameCheck ( material , res , next ) ) return ;
}
2020-05-29 10:40:17 +02:00
if ( material . hasOwnProperty ( 'group' ) ) {
2020-06-05 08:50:06 +02:00
material = await groupResolve ( material , req , next ) ;
2020-05-29 10:40:17 +02:00
if ( ! material ) return ;
}
if ( material . hasOwnProperty ( 'supplier' ) ) {
2020-06-05 08:50:06 +02:00
material = await supplierResolve ( material , req , next ) ;
2020-05-29 10:40:17 +02:00
if ( ! material ) return ;
}
2020-07-15 13:11:33 +02:00
if ( material . hasOwnProperty ( 'properties' ) ) {
if ( ! await propertiesCheck ( material . properties , 'change' , res , next , materialData . properties . material_template . toString ( ) !== material . properties . material_template ) ) return ;
}
2020-05-13 14:18:15 +02:00
// check for changes
2020-05-29 10:40:17 +02:00
if ( ! _ . isEqual ( _ . pick ( IdValidate . stringify ( materialData ) , _ . keys ( material ) ) , IdValidate . stringify ( material ) ) ) {
2020-05-27 14:31:17 +02:00
material . status = globals . status . new ; // set status to new
2020-05-13 14:18:15 +02:00
}
2020-04-29 16:09:31 +02:00
2020-06-05 08:50:06 +02:00
await MaterialModel . findByIdAndUpdate ( req . params . id , material , { new : true } ) . log ( req ) . populate ( 'group_id' ) . populate ( 'supplier_id' ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-06 14:39:04 +02:00
if ( err ) return next ( err ) ;
2020-05-13 14:18:15 +02:00
res . json ( MaterialValidate . output ( data ) ) ;
2020-04-29 16:09:31 +02:00
} ) ;
2020-05-13 14:18:15 +02:00
} ) ;
2020-04-29 16:09:31 +02:00
} ) ;
router . delete ( '/material/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
2020-05-08 09:58:12 +02:00
// check if there are still samples referencing this material
SampleModel . find ( { 'material_id' : new mongoose . Types . ObjectId ( req . params . id ) } ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-06 14:39:04 +02:00
if ( err ) return next ( err ) ;
2020-05-08 09:58:12 +02:00
if ( data . length ) {
return res . status ( 400 ) . json ( { status : 'Material still in use' } ) ;
2020-04-29 16:09:31 +02:00
}
2020-06-05 08:50:06 +02:00
MaterialModel . findByIdAndUpdate ( req . params . id , { status :globals.status.deleted } ) . log ( req ) . populate ( 'group_id' ) . populate ( 'supplier_id' ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-08 09:58:12 +02:00
if ( err ) return next ( err ) ;
if ( data ) {
2020-05-08 15:12:36 +02:00
res . json ( { status : 'OK' } ) ;
2020-05-08 09:58:12 +02:00
}
else {
res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
} ) ;
2020-04-29 16:09:31 +02:00
} ) ;
} ) ;
2020-05-28 14:54:52 +02:00
router . put ( '/material/restore/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return ;
2020-05-29 12:54:05 +02:00
setStatus ( globals . status . new , req , res , next ) ;
} ) ;
2020-05-28 14:54:52 +02:00
2020-05-29 12:54:05 +02:00
router . put ( '/material/validate/' + IdValidate . parameter ( ) , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'maintain' , 'admin' ] , 'basic' ) ) return ;
setStatus ( globals . status . validated , req , res , next ) ;
2020-05-28 14:54:52 +02:00
} ) ;
2020-05-29 10:40:17 +02:00
router . post ( '/material/new' , async ( req , res , next ) = > {
2020-04-29 12:10:27 +02:00
if ( ! req . auth ( res , [ 'write' , 'maintain' , 'dev' , 'admin' ] , 'basic' ) ) return ;
2020-05-29 10:40:17 +02:00
let { error , value : material } = MaterialValidate . input ( req . body , 'new' ) ;
2020-05-07 21:55:29 +02:00
if ( error ) return res400 ( error , res ) ;
2020-04-29 12:10:27 +02:00
2020-05-13 14:18:15 +02:00
if ( ! await nameCheck ( material , res , next ) ) return ;
2020-06-05 08:50:06 +02:00
material = await groupResolve ( material , req , next ) ;
2020-05-29 10:40:17 +02:00
if ( ! material ) return ;
2020-06-05 08:50:06 +02:00
material = await supplierResolve ( material , req , next ) ;
2020-05-29 10:40:17 +02:00
if ( ! material ) return ;
2020-07-15 13:11:33 +02:00
if ( ! await propertiesCheck ( material . properties , 'new' , res , next ) ) return ;
2020-04-29 12:10:27 +02:00
2020-05-27 14:31:17 +02:00
material . status = globals . status . new ; // set status to new
2020-05-29 10:40:17 +02:00
await new MaterialModel ( material ) . save ( async ( err , data ) = > {
2020-05-13 14:18:15 +02:00
if ( err ) return next ( err ) ;
2020-06-05 08:50:06 +02:00
db . log ( req , 'materials' , { _id : data._id } , data . toObject ( ) ) ;
2020-05-29 10:40:17 +02:00
await data . populate ( 'group_id' ) . populate ( 'supplier_id' ) . execPopulate ( ) . catch ( err = > next ( err ) ) ;
if ( data instanceof Error ) return ;
2020-05-13 14:18:15 +02:00
res . json ( MaterialValidate . output ( data . toObject ( ) ) ) ;
2020-04-29 16:09:31 +02:00
} ) ;
} ) ;
2020-04-29 12:10:27 +02:00
2020-05-28 17:05:23 +02:00
router . get ( '/material/groups' , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'all' ) ) return ;
2020-05-29 10:40:17 +02:00
MaterialGroupModel . find ( ) . lean ( ) . exec ( ( err , data : any ) = > {
2020-05-28 17:05:23 +02:00
if ( err ) return next ( err ) ;
res . json ( _ . compact ( data . map ( e = > MaterialValidate . outputGroups ( e . name ) ) ) ) ; // validate all and filter null values from validation errors
} ) ;
} ) ;
router . get ( '/material/suppliers' , ( req , res , next ) = > {
if ( ! req . auth ( res , [ 'read' , 'write' , 'maintain' , 'dev' , 'admin' ] , 'all' ) ) return ;
2020-05-29 10:40:17 +02:00
MaterialSupplierModel . find ( ) . lean ( ) . exec ( ( err , data : any ) = > {
2020-05-28 17:05:23 +02:00
if ( err ) return next ( err ) ;
res . json ( _ . compact ( data . map ( e = > MaterialValidate . outputSuppliers ( e . name ) ) ) ) ; // validate all and filter null values from validation errors
} ) ;
} ) ;
2020-04-29 12:10:27 +02:00
2020-05-13 14:18:15 +02:00
module . exports = router ;
async function nameCheck ( material , res , next ) { // check if name was already taken
2020-05-18 14:47:22 +02:00
const materialData = await MaterialModel . findOne ( { name : material.name } ) . lean ( ) . exec ( ) . catch ( err = > next ( err ) ) as any ;
2020-05-14 15:36:47 +02:00
if ( materialData instanceof Error ) return false ;
2020-05-13 14:18:15 +02:00
if ( materialData ) { // could not find material_id
res . status ( 400 ) . json ( { status : 'Material name already taken' } ) ;
return false ;
}
return true ;
2020-05-29 10:40:17 +02:00
}
2020-06-05 08:50:06 +02:00
async function groupResolve ( material , req , next ) {
const groupData = await MaterialGroupModel . findOneAndUpdate ( { name : material.group } , { name : material.group } , { upsert : true , new : true } ) . log ( req ) . lean ( ) . exec ( ) . catch ( err = > next ( err ) ) as any ;
2020-05-29 10:40:17 +02:00
if ( groupData instanceof Error ) return false ;
material . group_id = groupData . _id ;
delete material . group ;
return material ;
}
2020-06-05 08:50:06 +02:00
async function supplierResolve ( material , req , next ) {
const supplierData = await MaterialSupplierModel . findOneAndUpdate ( { name : material.supplier } , { name : material.supplier } , { upsert : true , new : true } ) . log ( req ) . lean ( ) . exec ( ) . catch ( err = > next ( err ) ) as any ;
2020-05-29 10:40:17 +02:00
if ( supplierData instanceof Error ) return false ;
material . supplier_id = supplierData . _id ;
delete material . supplier ;
return material ;
2020-05-29 12:54:05 +02:00
}
2020-07-15 13:11:33 +02:00
async function propertiesCheck ( properties , param , res , next , checkVersion = true ) { // validate material properties, returns false if invalid, otherwise template data
if ( ! properties . material_template || ! IdValidate . valid ( properties . material_template ) ) { // template id not found
res . status ( 400 ) . json ( { status : 'Material template not available' } ) ;
return false ;
}
const materialData = await MaterialTemplateModel . findById ( properties . material_template ) . lean ( ) . exec ( ) . catch ( err = > next ( err ) ) as any ;
if ( materialData instanceof Error ) return false ;
if ( ! materialData ) { // template not found
res . status ( 400 ) . json ( { status : 'Material template not available' } ) ;
return false ;
}
if ( checkVersion ) {
// get all template versions and check if given is latest
const materialVersions = await MaterialTemplateModel . find ( { first_id : materialData.first_id } ) . sort ( { version : - 1 } ) . lean ( ) . exec ( ) . catch ( err = > next ( err ) ) as any ;
if ( materialVersions instanceof Error ) return false ;
if ( properties . material_template !== materialVersions [ 0 ] . _id . toString ( ) ) { // template not latest
res . status ( 400 ) . json ( { status : 'Old template version not allowed' } ) ;
return false ;
}
}
// validate parameters
const { error , value : ignore } = ParametersValidate . input ( _ . omit ( properties , 'material_template' ) , materialData . parameters , param ) ;
if ( error ) { res400 ( error , res ) ; return false ; }
return materialData ;
}
2020-05-29 12:54:05 +02:00
function setStatus ( status , req , res , next ) { // set measurement status
2020-06-05 08:50:06 +02:00
MaterialModel . findByIdAndUpdate ( req . params . id , { status : status } ) . log ( req ) . lean ( ) . exec ( ( err , data ) = > {
2020-05-29 12:54:05 +02:00
if ( err ) return next ( err ) ;
if ( ! data ) {
return res . status ( 404 ) . json ( { status : 'Not found' } ) ;
}
res . json ( { status : 'OK' } ) ;
} ) ;
2020-05-13 14:18:15 +02:00
}