2020-05-07 21:55:29 +02:00
import Joi from '@hapi/joi' ;
2020-05-06 14:39:04 +02:00
import IdValidate from './id' ;
2020-05-27 14:31:17 +02:00
import UserValidate from './user' ;
import MaterialValidate from './material' ;
2020-06-18 08:57:50 +02:00
import MeasurementValidate from './measurement' ;
2020-05-06 14:39:04 +02:00
export default class SampleValidate {
private static sample = {
2020-05-07 21:55:29 +02:00
number : Joi . string ( )
2020-05-06 14:39:04 +02:00
. max ( 128 ) ,
2020-05-07 21:55:29 +02:00
color : Joi.string ( )
2020-07-09 13:48:27 +02:00
. max ( 128 )
. allow ( '' ) ,
2020-05-06 14:39:04 +02:00
2020-05-07 21:55:29 +02:00
type : Joi . string ( )
2020-05-06 14:39:04 +02:00
. max ( 128 ) ,
2020-05-07 21:55:29 +02:00
batch : Joi.string ( )
2020-05-06 14:39:04 +02:00
. max ( 128 )
. allow ( '' ) ,
2020-05-27 14:31:17 +02:00
condition : Joi.object ( ) ,
2020-05-07 21:55:29 +02:00
notes : Joi.object ( {
comment : Joi.string ( )
2020-05-27 14:31:17 +02:00
. max ( 512 )
. allow ( '' ) ,
2020-05-06 14:39:04 +02:00
2020-05-07 21:55:29 +02:00
sample_references : Joi.array ( )
. items ( Joi . object ( {
2020-05-27 14:31:17 +02:00
sample_id : IdValidate.get ( ) ,
2020-05-06 14:39:04 +02:00
2020-05-07 21:55:29 +02:00
relation : Joi.string ( )
2020-05-06 14:39:04 +02:00
. max ( 128 )
} ) ) ,
2020-05-07 21:55:29 +02:00
custom_fields : Joi.object ( )
. pattern ( /.*/ , Joi . alternatives ( )
2020-05-06 14:39:04 +02:00
. try (
2020-05-07 21:55:29 +02:00
Joi . string ( ) . max ( 128 ) ,
Joi . number ( ) ,
Joi . boolean ( ) ,
Joi . date ( )
2020-05-06 14:39:04 +02:00
)
)
2020-06-25 10:44:55 +02:00
} ) ,
added : Joi.date ( )
. iso ( )
. min ( '1970-01-01T00:00:00.000Z' )
2020-05-06 14:39:04 +02:00
} ;
2020-06-29 15:50:24 +02:00
private static sortKeys = [
'_id' ,
'color' ,
'number' ,
'type' ,
'batch' ,
'added' ,
'material.name' ,
'material.supplier' ,
'material.group' ,
2020-07-02 12:18:01 +02:00
'material.number' ,
2020-07-17 10:41:19 +02:00
'material.properties.*' ,
2020-07-02 12:18:01 +02:00
'measurements.(?!spectrum)*'
2020-06-29 15:50:24 +02:00
] ;
private static fieldKeys = [
. . . SampleValidate . sortKeys ,
'condition' ,
2020-07-20 16:31:48 +02:00
'notes' ,
2020-06-29 15:50:24 +02:00
'material_id' ,
2020-06-30 14:16:37 +02:00
'material' ,
2020-06-29 15:50:24 +02:00
'note_id' ,
'user_id' ,
'material._id' ,
2020-06-30 14:16:37 +02:00
'material.numbers' ,
2020-07-20 16:31:48 +02:00
'measurements.spectrum.dpt' ,
2020-06-29 15:50:24 +02:00
] ;
2020-05-18 14:47:22 +02:00
static input ( data , param ) { // validate input, set param to 'new' to make all attributes required
2020-05-06 14:39:04 +02:00
if ( param === 'new' ) {
2020-05-07 21:55:29 +02:00
return Joi . object ( {
2020-05-06 14:39:04 +02:00
color : this.sample.color.required ( ) ,
type : this . sample . type . required ( ) ,
batch : this.sample.batch.required ( ) ,
2020-05-27 14:31:17 +02:00
condition : this.sample.condition.required ( ) ,
2020-05-06 14:39:04 +02:00
material_id : IdValidate.get ( ) . required ( ) ,
notes : this.sample.notes.required ( )
} ) . validate ( data ) ;
}
else if ( param === 'change' ) {
2020-05-07 21:55:29 +02:00
return Joi . object ( {
color : this.sample.color ,
type : this . sample . type ,
batch : this.sample.batch ,
2020-05-27 14:31:17 +02:00
condition : this.sample.condition ,
2020-05-07 21:55:29 +02:00
material_id : IdValidate.get ( ) ,
notes : this.sample.notes ,
} ) . validate ( data ) ;
2020-05-06 14:39:04 +02:00
}
2020-06-02 10:24:22 +02:00
else if ( param === 'new-admin' ) {
return Joi . object ( {
2020-06-05 08:50:06 +02:00
number : this . sample . number ,
2020-06-02 10:24:22 +02:00
color : this.sample.color.required ( ) ,
type : this . sample . type . required ( ) ,
batch : this.sample.batch.required ( ) ,
condition : this.sample.condition.required ( ) ,
material_id : IdValidate.get ( ) . required ( ) ,
notes : this.sample.notes.required ( )
} ) . validate ( data ) ;
}
2020-05-06 14:39:04 +02:00
else {
return { error : 'No parameter specified!' , value : { } } ;
}
}
2020-06-30 14:16:37 +02:00
static output ( data , param = 'refs+added' , additionalParams = [ ] ) { // validate output and strip unwanted properties, returns null if not valid
2020-06-29 15:50:24 +02:00
if ( param === 'refs+added' ) {
param = 'refs' ;
data . added = data . _id . getTimestamp ( ) ;
}
2020-05-06 14:39:04 +02:00
data = IdValidate . stringify ( data ) ;
2020-05-27 14:31:17 +02:00
let joiObject ;
if ( param === 'refs' ) {
joiObject = {
_id : IdValidate.get ( ) ,
number : this . sample . number ,
color : this.sample.color ,
type : this . sample . type ,
batch : this.sample.batch ,
condition : this.sample.condition ,
material_id : IdValidate.get ( ) ,
2020-06-30 14:16:37 +02:00
material : MaterialValidate.outputV ( ) . append ( { number : Joi . string ( ) . max ( 128 ) . allow ( '' ) } ) ,
2020-05-27 14:31:17 +02:00
note_id : IdValidate.get ( ) . allow ( null ) ,
2020-07-20 16:31:48 +02:00
notes : this.sample.notes ,
2020-06-25 10:44:55 +02:00
user_id : IdValidate.get ( ) ,
added : this.sample.added
2020-05-27 14:31:17 +02:00
} ;
}
else if ( param === 'details' ) {
joiObject = {
_id : IdValidate.get ( ) ,
number : this . sample . number ,
color : this.sample.color ,
type : this . sample . type ,
batch : this.sample.batch ,
condition : this.sample.condition ,
material : MaterialValidate.outputV ( ) ,
2020-06-18 08:57:50 +02:00
measurements : Joi.array ( ) . items ( MeasurementValidate . outputV ( ) ) ,
2020-05-27 14:31:17 +02:00
notes : this.sample.notes ,
user : UserValidate.username ( )
}
}
else {
return null ;
}
2020-06-30 14:16:37 +02:00
additionalParams . forEach ( param = > {
joiObject [ param ] = Joi . any ( ) ;
} ) ;
2020-05-27 14:31:17 +02:00
const { value , error } = Joi . object ( joiObject ) . validate ( data , { stripUnknown : true } ) ;
2020-05-06 14:39:04 +02:00
return error !== undefined ? null : value ;
}
2020-06-15 12:49:32 +02:00
static query ( data ) {
2020-07-06 09:43:04 +02:00
if ( data . filters && data . filters . length ) {
const filterValidation = Joi . array ( ) . items ( Joi . string ( ) ) . validate ( data . filters ) ;
if ( filterValidation . error ) return filterValidation ;
try {
for ( let i in data . filters ) {
data . filters [ i ] = JSON . parse ( data . filters [ i ] ) ;
2020-07-09 13:48:27 +02:00
data . filters [ i ] . values = data . filters [ i ] . values . map ( e = > { // validate filter values
let validator ;
let field = data . filters [ i ] . field
if ( /material\./ . test ( field ) ) { // select right validation model
2020-07-17 10:41:19 +02:00
validator = MaterialValidate . outputV ( ) . append ( { number : Joi . string ( ) . max ( 128 ) . allow ( '' ) , properties : Joi.alternatives ( ) . try ( Joi . number ( ) , Joi . string ( ) . max ( 128 ) ) } ) ;
field = field . replace ( 'material.' , '' ) . split ( '.' ) [ 0 ] ;
2020-07-09 13:48:27 +02:00
}
else if ( /measurements\./ . test ( field ) ) {
validator = Joi . object ( {
value : Joi.alternatives ( )
. try (
Joi . number ( ) ,
2020-07-14 12:07:43 +02:00
Joi . string ( ) . max ( 128 ) ,
2020-07-09 13:48:27 +02:00
Joi . boolean ( ) ,
Joi . array ( )
)
. allow ( null )
} ) ;
field = 'value' ;
}
else {
validator = Joi . object ( this . sample ) ;
}
const { value , error } = validator . validate ( { [ field ] : e } ) ;
2020-07-10 13:09:15 +02:00
if ( error ) throw error ; // reject invalid values // TODO: return exact error description, handle in frontend filters
2020-07-09 13:48:27 +02:00
return value [ field ] ;
} ) ;
2020-07-06 09:43:04 +02:00
}
}
catch {
return { error : { details : [ { message : 'Invalid JSON string for filter parameter' } ] } , value : null }
}
}
2020-06-15 12:49:32 +02:00
return Joi . object ( {
2020-06-25 10:44:55 +02:00
status : Joi.string ( ) . valid ( 'validated' , 'new' , 'all' ) ,
2020-06-25 11:59:36 +02:00
'from-id' : IdValidate . get ( ) ,
2020-06-25 10:44:55 +02:00
'to-page' : Joi . number ( ) . integer ( ) ,
2020-06-26 09:38:28 +02:00
'page-size' : Joi . number ( ) . integer ( ) . min ( 1 ) ,
2020-07-02 12:18:01 +02:00
sort : Joi.string ( ) . pattern ( new RegExp ( '^(' + this . sortKeys . join ( '|' ) . replace ( /\./g , '\\.' ) . replace ( /\*/g , '.+' ) + ')-(asc|desc)$' , 'm' ) ) . default ( '_id-asc' ) ,
2020-06-29 15:50:24 +02:00
csv : Joi.boolean ( ) . default ( false ) ,
2020-07-15 13:11:33 +02:00
fields : Joi.array ( ) . items ( Joi . string ( ) . pattern ( new RegExp ( '^(' + this . fieldKeys . join ( '|' ) . replace ( /\./g , '\\.' ) . replace ( /\*/g , '.+' ) + ')$' , 'm' ) ) ) . default ( [ '_id' , 'number' , 'type' , 'batch' , 'material_id' , 'color' , 'condition' , 'note_id' , 'user_id' , 'added' ] ) . messages ( { 'string.pattern.base' : 'Invalid field name' } ) ,
2020-07-06 09:43:04 +02:00
filters : Joi.array ( ) . items ( Joi . object ( {
mode : Joi.string ( ) . valid ( 'eq' , 'ne' , 'lt' , 'lte' , 'gt' , 'gte' , 'in' , 'nin' ) ,
2020-07-15 13:11:33 +02:00
field : Joi.string ( ) . pattern ( new RegExp ( '^(' + this . fieldKeys . join ( '|' ) . replace ( /\./g , '\\.' ) . replace ( /\*/g , '.+' ) + ')$' , 'm' ) ) . messages ( { 'string.pattern.base' : 'Invalid filter field name' } ) ,
2020-07-17 10:41:19 +02:00
values : Joi.array ( ) . items ( Joi . alternatives ( ) . try ( Joi . string ( ) . max ( 128 ) , Joi . number ( ) , Joi . boolean ( ) , Joi . date ( ) . iso ( ) , Joi . object ( ) ) ) . min ( 1 )
2020-07-06 09:43:04 +02:00
} ) ) . default ( [ ] )
2020-06-25 10:44:55 +02:00
} ) . with ( 'to-page' , 'page-size' ) . validate ( data ) ;
2020-06-15 12:49:32 +02:00
}
2020-05-06 14:39:04 +02:00
}