Archived
2

Properly indent all source files

This commit is contained in:
2021-01-25 12:57:29 +01:00
parent 0e37956bdb
commit 7c5b6ec605
51 changed files with 9380 additions and 9380 deletions

View File

@ -2,33 +2,33 @@ import Joi from 'joi';
import globals from '../../globals';
export default class HelpValidate {
private static help = {
text: Joi.string()
.allow('')
.max(8192),
private static help = {
text: Joi.string()
.allow('')
.max(8192),
level: Joi.string()
.valid('none', ...Object.values(globals.levels))
}
level: Joi.string()
.valid('none', ...Object.values(globals.levels))
}
static input (data) {
return Joi.object({
text: this.help.text.required(),
level: this.help.level.required()
}).validate(data);
}
static input (data) {
return Joi.object({
text: this.help.text.required(),
level: this.help.level.required()
}).validate(data);
}
static output (data) {
const {value, error} = Joi.object({
text: this.help.text,
level: this.help.level
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static output (data) {
const {value, error} = Joi.object({
text: this.help.text,
level: this.help.level
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static params(data) {
return Joi.object({
key: Joi.string().min(1).max(128)
}).validate(data);
}
}
static params(data) {
return Joi.object({
key: Joi.string().min(1).max(128)
}).validate(data);
}
}

View File

@ -1,33 +1,33 @@
import Joi from 'joi';
export default class IdValidate {
private static id = Joi.string()
.pattern(new RegExp('[0-9a-f]{24}'))
.length(24)
.messages({'string.pattern.base': 'Invalid object id'});
private static id = Joi.string()
.pattern(new RegExp('[0-9a-f]{24}'))
.length(24)
.messages({'string.pattern.base': 'Invalid object id'});
static get () { // return joi validation
return this.id;
}
static get () { // return joi validation
return this.id;
}
static valid (id) { // validate id
return this.id.validate(id).error === undefined;
}
static valid (id) { // validate id
return this.id.validate(id).error === undefined;
}
static parameter () { // :id url parameter
return ':id([0-9a-f]{24})';
}
static parameter () { // :id url parameter
return ':id([0-9a-f]{24})';
}
static stringify (data) { // convert all ObjectID objects to plain strings
Object.keys(data).forEach(key => {
// stringify id
if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') {
data[key] = data[key].toString();
}
else if (typeof data[key] === 'object' && data[key] !== null) { // deeper into recursion
data[key] = this.stringify(data[key]);
}
});
return data;
}
}
static stringify (data) { // convert all ObjectID objects to plain strings
Object.keys(data).forEach(key => {
// stringify id
if (data[key] !== null && data[key].hasOwnProperty('_bsontype') && data[key]._bsontype === 'ObjectID') {
data[key] = data[key].toString();
}
else if (typeof data[key] === 'object' && data[key] !== null) { // deeper into recursion
data[key] = this.stringify(data[key]);
}
});
return data;
}
}

View File

@ -4,99 +4,99 @@ import IdValidate from './id';
import globals from '../../globals';
export default class MaterialValidate { // validate input for material
private static material = {
name: Joi.string()
.max(128),
private static material = {
name: Joi.string()
.max(128),
supplier: Joi.string()
.max(128),
supplier: Joi.string()
.max(128),
group: Joi.string()
.max(128),
group: Joi.string()
.max(128),
properties: Joi.object(),
properties: Joi.object(),
numbers: Joi.array()
.items(
Joi.string()
.max(64)
),
numbers: Joi.array()
.items(
Joi.string()
.max(64)
),
status: Joi.string()
.valid(...Object.values(globals.status))
};
status: Joi.string()
.valid(...Object.values(globals.status))
};
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.material.name.required(),
supplier: this.material.supplier.required(),
group: this.material.group.required(),
properties: this.material.properties.required(),
numbers: this.material.numbers.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.material.name.required(),
supplier: this.material.supplier.required(),
group: this.material.group.required(),
properties: this.material.properties.required(),
numbers: this.material.numbers.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static output (data, status = false) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
data.group = data.group_id.name;
data.supplier = data.supplier_id.name;
const validate: any = {
_id: IdValidate.get(),
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
};
if (status) {
validate.status = this.material.status;
}
const {value, error} = Joi.object(validate).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static output (data, status = false) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
data.group = data.group_id.name;
data.supplier = data.supplier_id.name;
const validate: any = {
_id: IdValidate.get(),
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
};
if (status) {
validate.status = this.material.status;
}
const {value, error} = Joi.object(validate).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputGroups (data) {// validate groups output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.group.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputGroups (data) {// validate groups output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.group.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputSuppliers (data) {// validate suppliers output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.supplier.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputSuppliers (data) {// validate suppliers output and strip unwanted properties, returns null if not valid
const {value, error} = this.material.supplier.validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static outputV() { // return output validator
return Joi.object({
_id: IdValidate.get(),
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
});
}
static outputV() { // return output validator
return Joi.object({
_id: IdValidate.get(),
name: this.material.name,
supplier: this.material.supplier,
group: this.material.group,
properties: this.material.properties,
numbers: this.material.numbers
});
}
static query (data, dev = false) {
const acceptedStatuses = [globals.status.val, globals.status.new];
if (dev) { // dev and admin can also access deleted samples
acceptedStatuses.push(globals.status.del)
}
return Joi.object({
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val])
}).validate(data);
}
}
static query (data, dev = false) {
const acceptedStatuses = [globals.status.val, globals.status.new];
if (dev) { // dev and admin can also access deleted samples
acceptedStatuses.push(globals.status.del)
}
return Joi.object({
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val])
}).validate(data);
}
}

View File

@ -4,64 +4,64 @@ import IdValidate from './id';
import globals from '../../globals';
export default class MeasurementValidate {
private static measurement = {
values: Joi.object()
.pattern(/.*/, Joi.alternatives()
.try(
Joi.string().max(128),
Joi.number(),
Joi.boolean(),
Joi.array().items(Joi.array().items(Joi.number())), // for spectra
Joi.array()
)
.allow(null)
)
};
private static measurement = {
values: Joi.object()
.pattern(/.*/, Joi.alternatives()
.try(
Joi.string().max(128),
Joi.number(),
Joi.boolean(),
Joi.array().items(Joi.array().items(Joi.number())), // for spectra
Joi.array()
)
.allow(null)
)
};
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
sample_id: IdValidate.get().required(),
values: this.measurement.values.required(),
measurement_template: IdValidate.get().required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
values: this.measurement.values
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
sample_id: IdValidate.get().required(),
values: this.measurement.values.required(),
measurement_template: IdValidate.get().required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
values: this.measurement.values
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
// validate output and strip unwanted properties, returns null if not valid
static output (data, req, status = false) {
data = IdValidate.stringify(data);
// spectral data not allowed for read/write users
if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values[globals.spectrum.dpt]) {
delete data.values[globals.spectrum.dpt];
}
const validation: any = {
_id: IdValidate.get(),
sample_id: IdValidate.get(),
values: this.measurement.values,
measurement_template: IdValidate.get()
};
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;
}
// validate output and strip unwanted properties, returns null if not valid
static output (data, req, status = false) {
data = IdValidate.stringify(data);
// spectral data not allowed for read/write users
if (['dev', 'admin'].indexOf(req.authDetails.level) < 0 && data.values[globals.spectrum.dpt]) {
delete data.values[globals.spectrum.dpt];
}
const validation: any = {
_id: IdValidate.get(),
sample_id: IdValidate.get(),
values: this.measurement.values,
measurement_template: IdValidate.get()
};
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;
}
static outputV() { // return output validator
return Joi.object({
_id: IdValidate.get(),
sample_id: IdValidate.get(),
values: this.measurement.values,
measurement_template: IdValidate.get()
});
}
}
static outputV() { // return output validator
return Joi.object({
_id: IdValidate.get(),
sample_id: IdValidate.get(),
values: this.measurement.values,
measurement_template: IdValidate.get()
});
}
}

View File

@ -3,40 +3,40 @@ import IdValidate from './id';
export default class ModelValidate { // validate input for model
private static model = {
group: Joi.string()
.disallow('file')
.max(128),
private static model = {
group: Joi.string()
.disallow('file')
.max(128),
model: Joi.object({
name: Joi.string()
.max(128)
.required(),
model: Joi.object({
name: Joi.string()
.max(128)
.required(),
url: Joi.string()
.uri()
.max(512)
.required()
})
};
url: Joi.string()
.uri()
.max(512)
.required()
})
};
static input (data) { // validate input
return this.model.model.required().validate(data);
}
static input (data) { // validate input
return this.model.model.required().validate(data);
}
static output (data) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
group: this.model.group,
models: Joi.array().items(this.model.model.append({_id: IdValidate.get()}))
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static output (data) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
group: this.model.group,
models: Joi.array().items(this.model.model.append({_id: IdValidate.get()}))
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static fileOutput (data) {
return {
name: data.name,
size: data.data.length
}
}
}
static fileOutput (data) {
return {
name: data.name,
size: data.data.length
}
}
}

View File

@ -1,18 +1,18 @@
import Joi from 'joi';
export default class NoteFieldValidate {
private static note_field = {
name: Joi.string()
.max(128),
private static note_field = {
name: Joi.string()
.max(128),
qty: Joi.number()
};
qty: Joi.number()
};
static output (data) { // validate output and strip unwanted properties, returns null if not valid
const {value, error} = Joi.object({
name: this.note_field.name,
qty: this.note_field.qty
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}
static output (data) { // validate output and strip unwanted properties, returns null if not valid
const {value, error} = Joi.object({
name: this.note_field.name,
qty: this.note_field.qty
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}

View File

@ -1,42 +1,42 @@
import Joi from 'joi';
export default class ParametersValidate {
// data to validate, parameters from template, param: 'new', 'change', 'null'(null values are allowed)
static input (data, parameters, param) {
let joiObject = {};
parameters.forEach(parameter => {
switch (parameter.range.type) {
case 'number': joiObject[parameter.name] = Joi.number();
break;
case 'boolean': joiObject[parameter.name] = Joi.boolean();
break;
case 'array': joiObject[parameter.name] = Joi.array();
break;
case 'string': joiObject[parameter.name] = Joi.string().max(128);
break; // min or max implicitly define the value to be a number
default: if (parameter.range.hasOwnProperty('min') || parameter.range.hasOwnProperty('max')) {
joiObject[parameter.name] = Joi.number();
}
else {
joiObject[parameter.name] = Joi.string().max(128);
}
}
if (parameter.range.hasOwnProperty('min')) {
joiObject[parameter.name] = joiObject[parameter.name].min(parameter.range.min)
}
if (parameter.range.hasOwnProperty('max')) {
joiObject[parameter.name] = joiObject[parameter.name].max(parameter.range.max)
}
if (parameter.range.hasOwnProperty('values')) {
joiObject[parameter.name] = joiObject[parameter.name].valid(...parameter.range.values);
}
if (parameter.range.hasOwnProperty('required') && parameter.range.required) {
joiObject[parameter.name] = joiObject[parameter.name].required();
}
if (param === 'null') {
joiObject[parameter.name] = joiObject[parameter.name].allow(null)
}
});
return Joi.object(joiObject).validate(data);
}
}
// data to validate, parameters from template, param: 'new', 'change', 'null'(null values are allowed)
static input (data, parameters, param) {
let joiObject = {};
parameters.forEach(parameter => {
switch (parameter.range.type) {
case 'number': joiObject[parameter.name] = Joi.number();
break;
case 'boolean': joiObject[parameter.name] = Joi.boolean();
break;
case 'array': joiObject[parameter.name] = Joi.array();
break;
case 'string': joiObject[parameter.name] = Joi.string().max(128);
break; // min or max implicitly define the value to be a number
default: if (parameter.range.hasOwnProperty('min') || parameter.range.hasOwnProperty('max')) {
joiObject[parameter.name] = Joi.number();
}
else {
joiObject[parameter.name] = Joi.string().max(128);
}
}
if (parameter.range.hasOwnProperty('min')) {
joiObject[parameter.name] = joiObject[parameter.name].min(parameter.range.min)
}
if (parameter.range.hasOwnProperty('max')) {
joiObject[parameter.name] = joiObject[parameter.name].max(parameter.range.max)
}
if (parameter.range.hasOwnProperty('values')) {
joiObject[parameter.name] = joiObject[parameter.name].valid(...parameter.range.values);
}
if (parameter.range.hasOwnProperty('required') && parameter.range.required) {
joiObject[parameter.name] = joiObject[parameter.name].required();
}
if (param === 'null') {
joiObject[parameter.name] = joiObject[parameter.name].allow(null)
}
});
return Joi.object(joiObject).validate(data);
}
}

View File

@ -1,5 +1,5 @@
// respond with 400 and include error details from the joi validation
export default function res400 (error, res) {
res.status(400).json({status: 'Invalid body format', details: error.details[0].message});
}
res.status(400).json({status: 'Invalid body format', details: error.details[0].message});
}

View File

@ -2,50 +2,50 @@ import Joi from 'joi';
import IdValidate from './id';
export default class RootValidate { // validate input for root methods
private static changelog = {
timestamp: Joi.date()
.iso()
.min('1970-01-01T00:00:00.000Z'),
private static changelog = {
timestamp: Joi.date()
.iso()
.min('1970-01-01T00:00:00.000Z'),
page: Joi.number()
.integer()
.min(0)
.default(0),
page: Joi.number()
.integer()
.min(0)
.default(0),
pagesize: Joi.number()
.integer()
.min(0)
.default(25),
pagesize: Joi.number()
.integer()
.min(0)
.default(25),
action: Joi.string(),
action: Joi.string(),
collection: Joi.string(),
collection: Joi.string(),
conditions: Joi.object(),
conditions: Joi.object(),
data: Joi.object()
};
data: Joi.object()
};
static changelogParams (data) {
return Joi.object({
id: IdValidate.get(),
page: this.changelog.page,
pagesize: this.changelog.pagesize
}).validate(data);
}
static changelogParams (data) {
return Joi.object({
id: IdValidate.get(),
page: this.changelog.page,
pagesize: this.changelog.pagesize
}).validate(data);
}
static changelogOutput (data) {
data.date = data._id.getTimestamp();
data.collection = data.collection_name;
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
_id: IdValidate.get(),
date: this.changelog.timestamp,
action: this.changelog.action,
collection: this.changelog.collection,
conditions: this.changelog.conditions,
data: this.changelog.data,
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}
static changelogOutput (data) {
data.date = data._id.getTimestamp();
data.collection = data.collection_name;
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
_id: IdValidate.get(),
date: this.changelog.timestamp,
action: this.changelog.action,
collection: this.changelog.collection,
conditions: this.changelog.conditions,
data: this.changelog.data,
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}

View File

@ -8,273 +8,273 @@ import globals from '../../globals';
export default class SampleValidate {
private static sample = {
number: Joi.string()
.max(128),
private static sample = {
number: Joi.string()
.max(128),
color: Joi.string()
.max(128)
.allow(''),
color: Joi.string()
.max(128)
.allow(''),
type: Joi.string()
.valid('as-delivered/raw', 'processed'),
type: Joi.string()
.valid('as-delivered/raw', 'processed'),
batch: Joi.string()
.max(128)
.allow(''),
batch: Joi.string()
.max(128)
.allow(''),
condition: Joi.object(),
condition: Joi.object(),
notes: Joi.object({
comment: Joi.string()
.max(512)
.allow('')
.allow(null),
notes: Joi.object({
comment: Joi.string()
.max(512)
.allow('')
.allow(null),
sample_references: Joi.array()
.items(Joi.object({
sample_id: IdValidate.get(),
sample_references: Joi.array()
.items(Joi.object({
sample_id: IdValidate.get(),
relation: Joi.string()
.max(128)
})),
relation: Joi.string()
.max(128)
})),
custom_fields: Joi.object()
.pattern(/.*/, Joi.alternatives()
.try(
Joi.string().max(128),
Joi.number(),
Joi.boolean(),
Joi.date()
)
)
}),
custom_fields: Joi.object()
.pattern(/.*/, Joi.alternatives()
.try(
Joi.string().max(128),
Joi.number(),
Joi.boolean(),
Joi.date()
)
)
}),
added: Joi.date()
.iso()
.min('1970-01-01T00:00:00.000Z'),
added: Joi.date()
.iso()
.min('1970-01-01T00:00:00.000Z'),
status: Joi.string()
.valid(...Object.values(globals.status))
};
status: Joi.string()
.valid(...Object.values(globals.status))
};
static readonly sampleKeys = [ // keys which can be found in the sample directly
'_id',
'color',
'number',
'type',
'batch',
'added',
'condition',
'material_id',
'note_id',
'user_id'
];
static readonly sampleKeys = [ // keys which can be found in the sample directly
'_id',
'color',
'number',
'type',
'batch',
'added',
'condition',
'material_id',
'note_id',
'user_id'
];
private static sortKeys = [
'_id',
'color',
'number',
'type',
'batch',
'added',
'status',
'notes.comment',
'material.name',
'material.supplier',
'material.group',
'material.properties.*',
'condition.*',
`measurements.(?!${globals.spectrum.spectrum}.${globals.spectrum.dpt})*`
];
private static sortKeys = [
'_id',
'color',
'number',
'type',
'batch',
'added',
'status',
'notes.comment',
'material.name',
'material.supplier',
'material.group',
'material.properties.*',
'condition.*',
`measurements.(?!${globals.spectrum.spectrum}.${globals.spectrum.dpt})*`
];
private static fieldKeys = [
...SampleValidate.sortKeys,
'condition',
'notes',
'material_id',
'material',
'note_id',
'user_id',
'material._id',
'material.numbers',
'measurements',
`measurements.${globals.spectrum.spectrum}.${globals.spectrum.dpt}`,
];
private static fieldKeys = [
...SampleValidate.sortKeys,
'condition',
'notes',
'material_id',
'material',
'note_id',
'user_id',
'material._id',
'material.numbers',
'measurements',
`measurements.${globals.spectrum.spectrum}.${globals.spectrum.dpt}`,
];
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
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);
}
else if (param === 'change') {
return Joi.object({
color: this.sample.color,
type: this.sample.type,
batch: this.sample.batch,
condition: this.sample.condition,
material_id: IdValidate.get(),
notes: this.sample.notes,
}).validate(data);
}
else if (param === 'new-admin') {
return Joi.object({
number: this.sample.number,
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);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
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);
}
else if (param === 'change') {
return Joi.object({
color: this.sample.color,
type: this.sample.type,
batch: this.sample.batch,
condition: this.sample.condition,
material_id: IdValidate.get(),
notes: this.sample.notes,
}).validate(data);
}
else if (param === 'new-admin') {
return Joi.object({
number: this.sample.number,
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);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
// validate output and strip unwanted properties, returns null if not valid
static output (data, param = 'refs+added', additionalParams = []) {
if (param === 'refs+added') {
param = 'refs';
data.added = data._id.getTimestamp();
}
data = IdValidate.stringify(data);
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(),
material: MaterialValidate.outputV().append({number: Joi.string().max(128).allow('')}),
note_id: IdValidate.get().allow(null),
notes: this.sample.notes,
user_id: IdValidate.get(),
added: this.sample.added,
status: this.sample.status
};
}
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(),
measurements: Joi.array().items(MeasurementValidate.outputV()),
notes: this.sample.notes,
user: UserValidate.username(),
status: this.sample.status
}
}
else {
return null;
}
additionalParams.forEach(param => {
joiObject[param] = Joi.any();
});
const {value, error} = Joi.object(joiObject).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
// validate output and strip unwanted properties, returns null if not valid
static output (data, param = 'refs+added', additionalParams = []) {
if (param === 'refs+added') {
param = 'refs';
data.added = data._id.getTimestamp();
}
data = IdValidate.stringify(data);
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(),
material: MaterialValidate.outputV().append({number: Joi.string().max(128).allow('')}),
note_id: IdValidate.get().allow(null),
notes: this.sample.notes,
user_id: IdValidate.get(),
added: this.sample.added,
status: this.sample.status
};
}
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(),
measurements: Joi.array().items(MeasurementValidate.outputV()),
notes: this.sample.notes,
user: UserValidate.username(),
status: this.sample.status
}
}
else {
return null;
}
additionalParams.forEach(param => {
joiObject[param] = Joi.any();
});
const {value, error} = Joi.object(joiObject).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static query (data, dev = false) {
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) {
try {
data.filters[i] = decodeURIComponent(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
if (e === null) { // null values are always allowed
return null;
}
let validator;
let field = data.filters[i].field;
if (/material\./.test(field)) { // select right validation model
validator = MaterialValidate.outputV().append({
number: Joi.string().max(128).allow(''),
properties: Joi.alternatives().try(Joi.number(), Joi.string().max(128).allow(''))
});
field = field.replace('material.', '').split('.')[0];
}
else if (/measurements\./.test(field) || /condition\./.test(field)) {
validator = Joi.object({
value: Joi.alternatives()
.try(
Joi.number(),
Joi.string().max(128).allow(''),
Joi.boolean(),
Joi.array()
)
.allow(null)
});
field = 'value';
}
else if (field === 'measurements') {
validator = Joi.object({
value: Joi.object({}).allow(null).disallow({})
});
field = 'value';
}
else if (field === 'notes.comment') {
field = 'comment';
validator = this.sample.notes
}
else {
validator = Joi.object(this.sample);
}
const {value, error} = validator.validate({[field]: e});
if (error) throw error; // reject invalid values
return value[field];
});
}
}
catch (err) {
return {error: {details: [{message: 'Invalid JSON string for filter parameter'}]}, value: null}
}
}
const acceptedStatuses = [globals.status.val, globals.status.new];
if (dev) { // dev and admin can also access deleted samples
acceptedStatuses.push(globals.status.del)
}
return Joi.object({
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val]),
'from-id': IdValidate.get(),
'to-page': Joi.number().integer(),
'page-size': Joi.number().integer().min(1),
sort: Joi.string().pattern(
new RegExp('^(' + this.sortKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')-(asc|desc)$', 'm')
).default('_id-asc'),
output: Joi.string().valid('json', 'flatten', 'csv').default('json'),
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'}),
filters: Joi.array().items(Joi.object({
mode: Joi.string().valid('eq', 'ne', 'lt', 'lte', 'gt', 'gte', 'in', 'nin', 'stringin'),
field: Joi.string().pattern(
new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')
).messages({'string.pattern.base': 'Invalid filter field name'}),
values: Joi.array().items(Joi.alternatives().try(
Joi.string().max(128).allow(''), Joi.number(), Joi.boolean(), Joi.date().iso(), Joi.object(), null
)).min(1)
})).default([])
}).with('to-page', 'page-size').validate(data);
}
}
static query (data, dev = false) {
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) {
try {
data.filters[i] = decodeURIComponent(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
if (e === null) { // null values are always allowed
return null;
}
let validator;
let field = data.filters[i].field;
if (/material\./.test(field)) { // select right validation model
validator = MaterialValidate.outputV().append({
number: Joi.string().max(128).allow(''),
properties: Joi.alternatives().try(Joi.number(), Joi.string().max(128).allow(''))
});
field = field.replace('material.', '').split('.')[0];
}
else if (/measurements\./.test(field) || /condition\./.test(field)) {
validator = Joi.object({
value: Joi.alternatives()
.try(
Joi.number(),
Joi.string().max(128).allow(''),
Joi.boolean(),
Joi.array()
)
.allow(null)
});
field = 'value';
}
else if (field === 'measurements') {
validator = Joi.object({
value: Joi.object({}).allow(null).disallow({})
});
field = 'value';
}
else if (field === 'notes.comment') {
field = 'comment';
validator = this.sample.notes
}
else {
validator = Joi.object(this.sample);
}
const {value, error} = validator.validate({[field]: e});
if (error) throw error; // reject invalid values
return value[field];
});
}
}
catch (err) {
return {error: {details: [{message: 'Invalid JSON string for filter parameter'}]}, value: null}
}
}
const acceptedStatuses = [globals.status.val, globals.status.new];
if (dev) { // dev and admin can also access deleted samples
acceptedStatuses.push(globals.status.del)
}
return Joi.object({
status: Joi.array().items(Joi.string().valid(...acceptedStatuses)).default([globals.status.val]),
'from-id': IdValidate.get(),
'to-page': Joi.number().integer(),
'page-size': Joi.number().integer().min(1),
sort: Joi.string().pattern(
new RegExp('^(' + this.sortKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')-(asc|desc)$', 'm')
).default('_id-asc'),
output: Joi.string().valid('json', 'flatten', 'csv').default('json'),
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'}),
filters: Joi.array().items(Joi.object({
mode: Joi.string().valid('eq', 'ne', 'lt', 'lte', 'gt', 'gte', 'in', 'nin', 'stringin'),
field: Joi.string().pattern(
new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')
).messages({'string.pattern.base': 'Invalid filter field name'}),
values: Joi.array().items(Joi.alternatives().try(
Joi.string().max(128).allow(''), Joi.number(), Joi.boolean(), Joi.date().iso(), Joi.object(), null
)).min(1)
})).default([])
}).with('to-page', 'page-size').validate(data);
}
}

View File

@ -2,70 +2,70 @@ import Joi from 'joi';
import IdValidate from './id';
export default class TemplateValidate {
private static template = {
name: Joi.string()
.max(128),
private static template = {
name: Joi.string()
.max(128),
version: Joi.number()
.min(1),
version: Joi.number()
.min(1),
parameters: Joi.array()
.items(
Joi.object({
name: Joi.string()
.max(128)
.invalid('condition_template', 'material_template')
.pattern(/^[^.]+$/)
.required()
.messages({'string.pattern.base': 'name must not contain a dot'}),
parameters: Joi.array()
.items(
Joi.object({
name: Joi.string()
.max(128)
.invalid('condition_template', 'material_template')
.pattern(/^[^.]+$/)
.required()
.messages({'string.pattern.base': 'name must not contain a dot'}),
range: Joi.object({
values: Joi.array()
.min(1),
range: Joi.object({
values: Joi.array()
.min(1),
min: Joi.number(),
min: Joi.number(),
max: Joi.number(),
max: Joi.number(),
type: Joi.string()
.valid('string', 'number', 'boolean', 'array'),
type: Joi.string()
.valid('string', 'number', 'boolean', 'array'),
required: Joi.boolean()
})
.oxor('values', 'min')
.oxor('values', 'max')
.required()
})
)
};
required: Joi.boolean()
})
.oxor('values', 'min')
.oxor('values', 'max')
.required()
})
)
};
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.template.name.required(),
parameters: this.template.parameters.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.template.name,
parameters: this.template.parameters
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.template.name.required(),
parameters: this.template.parameters.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.template.name,
parameters: this.template.parameters
}).validate(data);
}
else {
return{error: 'No parameter specified!', value: {}};
}
}
static output (data) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
_id: IdValidate.get(),
name: this.template.name,
version: this.template.version,
first_id: IdValidate.get(),
parameters: this.template.parameters
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}
static output (data) { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const {value, error} = Joi.object({
_id: IdValidate.get(),
name: this.template.name,
version: this.template.version,
first_id: IdValidate.get(),
parameters: this.template.parameters
}).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
}

View File

@ -4,104 +4,104 @@ import globals from '../../globals';
import IdValidate from './id';
export default class UserValidate { // validate input for user
private static user = {
name: Joi.string()
.lowercase()
.pattern(new RegExp('^[a-z0-9-_.]+$'))
.max(128)
.messages({'string.pattern.base': 'name must only contain a-z0-9_.'}),
private static user = {
name: Joi.string()
.lowercase()
.pattern(new RegExp('^[a-z0-9-_.]+$'))
.max(128)
.messages({'string.pattern.base': 'name must only contain a-z0-9_.'}),
email: Joi.string()
.email({minDomainSegments: 2})
.lowercase()
.max(128),
email: Joi.string()
.email({minDomainSegments: 2})
.lowercase()
.max(128),
pass: Joi.string()
.min(8)
.max(128),
pass: Joi.string()
.min(8)
.max(128),
level: Joi.string()
.valid(...Object.values(globals.levels)),
level: Joi.string()
.valid(...Object.values(globals.levels)),
location: Joi.string()
.alphanum()
.max(128),
location: Joi.string()
.alphanum()
.max(128),
devices: Joi.array()
.items(Joi.string()
.allow('')
.max(128)
),
devices: Joi.array()
.items(Joi.string()
.allow('')
.max(128)
),
models: Joi.array()
.items(IdValidate.get()),
models: Joi.array()
.items(IdValidate.get()),
status: Joi.string()
.valid(...Object.values(globals.status))
};
status: Joi.string()
.valid(...Object.values(globals.status))
};
private static specialUsernames: string[] = ['admin', 'user', 'key', 'new', 'passreset']; // names a user cannot take
private static specialUsernames: string[] = ['admin', 'user', 'key', 'new', 'passreset']; // names a user cannot take
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.user.name.required(),
email: this.user.email.required(),
pass: this.user.pass.required(),
level: this.user.level.required(),
location: this.user.location.required(),
devices: this.user.devices.required(),
models: this.user.models.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.user.name,
email: this.user.email,
pass: this.user.pass,
location: this.user.location,
devices: this.user.devices
}).validate(data);
}
else if (param === 'changeadmin') {
return Joi.object({
name: this.user.name,
email: this.user.email,
pass: this.user.pass,
level: this.user.level,
location: this.user.location,
devices: this.user.devices,
models: this.user.models
}).validate(data);
}
else {
return {error: 'No parameter specified!', value: {}};
}
}
static input (data, param) { // validate input, set param to 'new' to make all attributes required
if (param === 'new') {
return Joi.object({
name: this.user.name.required(),
email: this.user.email.required(),
pass: this.user.pass.required(),
level: this.user.level.required(),
location: this.user.location.required(),
devices: this.user.devices.required(),
models: this.user.models.required()
}).validate(data);
}
else if (param === 'change') {
return Joi.object({
name: this.user.name,
email: this.user.email,
pass: this.user.pass,
location: this.user.location,
devices: this.user.devices
}).validate(data);
}
else if (param === 'changeadmin') {
return Joi.object({
name: this.user.name,
email: this.user.email,
pass: this.user.pass,
level: this.user.level,
location: this.user.location,
devices: this.user.devices,
models: this.user.models
}).validate(data);
}
else {
return {error: 'No parameter specified!', value: {}};
}
}
static output (data, param = '') { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const validate: {[key: string]: object} = {
_id: IdValidate.get(),
name: this.user.name,
email: this.user.email,
level: this.user.level,
location: this.user.location,
devices: this.user.devices,
models: this.user.models
}
if (param === 'admin') {
validate.status = this.user.status;
}
const {value, error} = Joi.object(validate).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static output (data, param = '') { // validate output and strip unwanted properties, returns null if not valid
data = IdValidate.stringify(data);
const validate: {[key: string]: object} = {
_id: IdValidate.get(),
name: this.user.name,
email: this.user.email,
level: this.user.level,
location: this.user.location,
devices: this.user.devices,
models: this.user.models
}
if (param === 'admin') {
validate.status = this.user.status;
}
const {value, error} = Joi.object(validate).validate(data, {stripUnknown: true});
return error !== undefined? null : value;
}
static isSpecialName (name) { // true if name belongs to special names
return this.specialUsernames.indexOf(name) > -1;
}
static isSpecialName (name) { // true if name belongs to special names
return this.specialUsernames.indexOf(name) > -1;
}
static username() {
return this.user.name;
}
static username() {
return this.user.name;
}
}