2014-05-12 20:08:19 +02:00
|
|
|
'use strict';
|
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
const _ = require('lodash')
|
2016-06-07 11:58:29 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
const Strings = require('../utils/strings')
|
|
|
|
const Logger = require('../logger')
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
// TODO: sanitize input for further processing as specified by constraints (correct types, trimming, etc.)
|
2014-05-12 20:08:19 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
function isValidBoolean(value) {
|
|
|
|
return _.isBoolean(value) || value === 'true' || value === 'false';
|
|
|
|
}
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
function isValidNumber(constraint, value) {
|
|
|
|
if (_.isString(value)) {
|
|
|
|
value = Strings.parseInt(value);
|
|
|
|
}
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
if (!_.isNumber(value)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
if (_.isNaN(value) || !_.isFinite(value)) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-07 00:21:26 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
if (_.isNumber(constraint.min) && value < constraint.min) {
|
|
|
|
return false;
|
2016-06-07 10:50:15 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
if (_.isNumber(constraint.max) && value > constraint.max) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-06-07 11:58:29 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isValidEnum(constraint, value) {
|
|
|
|
if (!_.isString(value)) {
|
|
|
|
return false;
|
2016-06-07 11:58:29 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
return _.indexOf(constraint.allowed, value) >= 0;
|
|
|
|
}
|
2016-05-24 14:42:25 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
function isValidString(constraint, value) {
|
|
|
|
if (!_.isString(value)) {
|
|
|
|
return false;
|
2016-06-07 10:50:15 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
const trimmed = value.trim();
|
|
|
|
return (trimmed === '' && constraint.optional) || trimmed.match(constraint.regex);
|
|
|
|
}
|
2014-05-12 20:08:19 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
function isValid(constraint, acceptUndefined, value) {
|
|
|
|
if (value === undefined) {
|
|
|
|
return acceptUndefined || constraint.optional;
|
|
|
|
}
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
switch (constraint.type) {
|
|
|
|
case 'boolean':
|
|
|
|
return isValidBoolean(value);
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
case 'number':
|
|
|
|
return isValidNumber(constraint, value);
|
2016-06-07 11:58:29 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
case 'enum':
|
|
|
|
return isValidEnum(constraint, value);
|
2016-06-07 10:50:15 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
case 'string':
|
|
|
|
return isValidString(constraint, value);
|
2016-06-07 10:50:15 +02:00
|
|
|
}
|
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
Logger.tag('validation').error('No validation method for constraint type: {}', constraint.type);
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-12 20:08:19 +02:00
|
|
|
|
2018-12-17 22:49:54 +01:00
|
|
|
function areValid(constraints, acceptUndefined, values) {
|
|
|
|
const fields = Object.keys(constraints);
|
|
|
|
for (let i = 0; i < fields.length; i ++) {
|
|
|
|
const field = fields[i];
|
|
|
|
if (!isValid(constraints[field], acceptUndefined, values[field])) {
|
|
|
|
return false;
|
2014-05-12 20:08:19 +02:00
|
|
|
}
|
2018-12-17 22:49:54 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
forConstraint (constraint, acceptUndefined) {
|
|
|
|
return _.partial(isValid, constraint, acceptUndefined);
|
|
|
|
},
|
|
|
|
forConstraints (constraints, acceptUndefined) {
|
|
|
|
return _.partial(areValid, constraints, acceptUndefined);
|
|
|
|
}
|
|
|
|
}
|