koa-better-validation
Version:
Koa Better Validation is a more up-to-date 'fork' of koa-validation. You can validate request params, querystring values, bodies, and even files.
712 lines (569 loc) • 22.5 kB
JavaScript
'use strict';
/* eslint eqeqeq: warn */
const v = require('validator');
const moment = require('moment-timezone');
const date_formats = [
moment.ISO_8601,
'DD-MM-YYYY',
'DD.MM.YYYY',
'DD/MM/YYYY',
'D-M-YYYY',
'D.M.YYYY',
'D/M/YYYY',
'YYYY-MM-DD HH:mm:Z',
'YYYY-MM-DD HH:mm:ZZ',
'YYYY-MM-DD HH:mm Z'
];
function valueExists(value) {
return (typeof value !== 'undefined' && value !== null && value.toString().trim());
}
class Rules {
constructor(Validator) {
this.validator = Validator;
}
* accepted(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (value === true || value === 'yes' || value === 'on' || value === 1 || value === '1') {
return true;
} else {
this.validator.addError(field, 'rule', 'accepted', message || 'The value of the field needs to be between 1, yes, or true');
return false;
}
}
* after(field, value, afterDate, message) {
if (!valueExists(value)) {
return true;
}
let mAfterDate;
let mDate;
if (typeof this.validator.validations[field].date_format !== 'undefined') {
mAfterDate = moment(afterDate, date_formats.concat([this.validator.validations[field].date_format]));
mDate = moment(value, this.validator.validations[field].date_format, true);
} else {
mAfterDate = moment(afterDate, date_formats);
mDate = moment(value, date_formats);
}
if (message) {
message = message.replace(':afterDate', afterDate);
}
if (!mAfterDate.isValid()) {
this.validator.addError(field, 'rule', 'after', 'The after date arguement is an invalid date');
return false;
} else if (!mDate.isValid()) {
this.validator.addError(field, 'rule', 'after', 'The value of the field is an invalid date');
return false;
} else if (mAfterDate.valueOf() > mDate.valueOf()) {
this.validator.addError(field, 'rule', 'after', message || 'The provided date does not fall after the date mentioned in the arguement');
return false;
}
return true;
}
* alpha(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isAlpha(value.toString())) {
this.validator.addError(field, 'rule', 'alpha', message || 'The value of the field needs to be alphabetical');
return false;
}
return true;
}
* alphaDash(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!(/^[A-Z0-9_-]+$/i.test(value))) {
this.validator.addError(field, 'rule', 'alphaDash', message || 'The field value can only contain aplhabets, _ and -');
return false;
}
return true;
}
* alphaNumeric(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isAlphanumeric(value)) {
this.validator.addError(field, 'rule', 'alphaNumeric', message || 'The value of the field can only contain letters and numbers');
return false;
}
return true;
}
* before(field, value, beforeDate, message) {
if (!valueExists(value)) {
return true;
}
let mBeforeDate;
let mDate;
if (typeof this.validator.validations[field].date_format !== 'undefined') {
mBeforeDate = moment(beforeDate, date_formats.concat([this.validator.validations[field].date_format]));
mDate = moment(value, this.validator.validations[field].date_format, true);
} else {
mBeforeDate = moment(beforeDate, date_formats);
mDate = moment(value, date_formats);
}
if (message) {
message = message.replace(':beforeDate', beforeDate);
}
if (!mBeforeDate.isValid()) {
this.validator.addError(field, 'rule', 'before', message || 'The before date arguement is an invalid date');
return false;
} else if (!mDate.isValid()) {
this.validator.addError(field, 'rule', 'before', message || 'The value of the field is an invalid date');
return false;
} else if (mBeforeDate.valueOf() < mDate.valueOf()) {
this.validator.addError(field, 'rule', 'before', message || 'The provided date does not come before the date mentioned in the arguement');
return false;
}
return true;
}
* between(field, value, args, message) {
if (!valueExists(value)) {
return true;
}
if (!Array.isArray(args) && args.length !== 2) {
this.validator.addError(field, 'rule', 'between', 'The number of arguements in the field are invalid');
return false;
} else {
if (!v.isInt(args[0]) || !v.isInt(args[1])) {
this.validator.addError(field, 'rule', 'between', 'The rule arguements for the field need to be integers');
return false;
} else if (parseInt(args[0]) >= parseInt(args[1])) {
this.validator.addError(field, 'rule', 'between', 'The rule arguement for the min value cannot be greater than or equal to the max value');
return false;
} else if (value.toString().length < parseInt(args[0]) || value.toString().length > parseInt(args[1])) {
if (message) {
message = message.replace(':minLength', args[0]).replace(':maxLength', args[1]);
}
this.validator.addError(field, 'rule', 'between', 'The size of the field is not within the specified range');
return false;
}
}
return true;
}
* boolean(field, value) {
if (!valueExists(value)) {
return true;
}
if (value === true || value === false || value === 0 || value === '0' ||value === 1 || value === '1') {
return true;
} else {
this.validator.addError(field, 'rule', 'boolean', 'The value of the field needs to be between true, false, 0 and 1');
return false;
}
}
* contains(field, value, inString, message) {
if (!valueExists(value)) {
return true;
}
if (typeof inString !== 'string') {
this.validator.addError(field, 'rule', 'contains', 'The number of arguements provided is invalid. Please provide one single string');
return false;
} else {
if (!v.contains(value, inString)) {
if (message) {
message.replace(':substring', inString);
}
this.validator.addError(field, 'rule', 'contains', message || 'The value of the field can only contain letters and numbers');
return false;
}
}
return true;
}
* date(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!moment(value, date_formats, true).isValid()) {
this.validator.addError(field, 'rule', 'date', message || 'The value provided for the field is an invalid date');
return false;
}
return true;
}
* dateFormat(field, value, format, message) {
if (!valueExists(value)) {
return true;
}
if (!moment(value, format, true).isValid()) {
if (message) {
message.replace(':format', format);
}
this.validator.addError(field, 'rule', 'dateFormat', message || 'The value provided for the field is either invalid or not in the format mentioned');
return false;
}
this.validator.validations[field].date_format = format;
return true;
}
* different(field, value, otherField, message) {
if (!valueExists(value)) {
return true;
}
if (typeof otherField !== 'string') {
this.validator.addError(field, 'rule', 'different', 'The number of arguements provided is invalid. Please provide one single string');
return false;
} else {
otherField = otherField.split('.').filter((e) => {
return e !== '';
});
let otherValue;
const self = this;
otherField.map((item) => {
if (typeof otherValue === 'undefined') {
otherValue = self.validator.fields && self.validator.fields[item];
} else {
otherValue = otherValue[item];
}
});
if (typeof otherValue === 'undefined') {
this.validator.addError(field, 'rule', 'different', message || 'The field you are comparing the value against does not exist');
return false;
} else if (otherValue == value) {
this.validator.addError(field, 'rule', 'different', message || 'The field you are comparing the value against is the same');
return false;
}
}
return true;
}
* digits(field, value, dNumber, message) {
if (!valueExists(value)) {
return true;
}
if (message) {
message = message.replace(':digits', dNumber.toString());
}
if (!v.isInt(dNumber)) {
this.validator.addError(field, 'rule', 'digits', 'The arguement entered is an invalid. Please enter digits');
return false;
} else if (value != dNumber) {
this.validator.addError(field, 'rule', 'digits', message || 'The value does not match with the mentioned number');
return false;
}
return true;
}
* digitsBetween(field, value, args, message) {
if (!valueExists(value)) {
return true;
}
if (!Array.isArray(args) && args.length !== 2) {
this.validator.addError(field, 'rule', 'digitsBetween', 'The number of arguements in the field are invalid');
return false;
} else {
if (!v.isInt(args[0]) || !v.isInt(args[1])) {
this.validator.addError(field, 'rule', 'digitsBetween', 'The rule arguements for the field need to be integers');
return false;
} else if (parseInt(args[0]) >= parseInt(args[1])) {
this.validator.addError(field, 'rule', 'digitsBetween', 'The rule arguement for the min value cannot be greater than or equal to the max value');
return false;
} else if (parseInt(value) < parseInt(args[0]) || parseInt(value) > parseInt(args[1])) {
if (message) {
message = message.replace(':min', args[0]).replace(':max', args[1]);
}
this.validator.addError(field, 'rule', 'digitsBetween', message || 'The digits are not within the specified range');
return false;
}
}
return true;
}
* email(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isEmail(value)) {
this.validator.addError(field, 'rule', 'email', message || 'The value entered is not a valid email');
return false;
}
return true;
}
* equals(field, value, arg, message) {
if (!valueExists(value)) {
return true;
}
if (value != arg) {
this.validator.addError(field, 'rule', 'equals', message || 'The value entered does not match with the arguement');
return false;
}
return true;
}
* in(field, value, args, message) {
if (!valueExists(value)) {
return true;
}
if (!Array.isArray(args)) {
args = [args];
}
let match = false;
for (let i = 0; i < args.length; i++) {
if (value == args[i]) {
match = true;
}
}
if (!match) {
this.validator.addError(field, 'rule', 'in', message || 'The value entered does not exist in the arguements supplied');
return false;
}
return true;
}
* integer(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isInt(value.toString())) {
this.validator.addError(field, 'rule', 'integer', message || 'The value entered is not an integer');
return false;
}
return true;
}
* ip(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isIP(value)) {
this.validator.addError(field, 'rule', 'ip', message || 'The value entered is not an IP Address');
return false;
}
return true;
}
* json(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isJSON(value)) {
this.validator.addError(field, 'rule', 'json', message || 'The value entered is not a JSON string');
return false;
}
return true;
}
* max(field, value, maxNum, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isInt(maxNum)) {
this.validator.addError(field, 'rule', 'max', message || 'The rule arguements for max fields needs to be an integer');
return false;
} else if (parseInt(value) > parseInt(maxNum)) {
if (message) {
message.replace(':max', maxNum);
}
this.validator.addError(field, 'rule', 'max', message || 'The value of the field is greater than the max arguement');
return false;
}
return true;
}
* maxLength(field, value, maxNum, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isInt(maxNum)) {
this.validator.addError(field, 'rule', 'max', message || 'The rule arguements for max fields needs to be an integer');
return false;
} else if (value.toString().length > parseInt(maxNum)) {
if (message) {
message.replace(':maxLength', maxNum);
}
this.validator.addError(field, 'rule', 'maxLength', message || 'The size of the field is greater than the max arguement');
return false;
}
return true;
}
* min(field, value, minNum, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isInt(minNum)) {
this.validator.addError(field, 'rule', 'min', message || 'The rule arguements for min fields needs to be an integer');
return false;
} else if (parseInt(value) < parseInt(minNum)) {
if (message) {
message.replace(':min', minNum);
}
this.validator.addError(field, 'rule', 'min', message || 'The value of the field is lesser than the min arguement');
return false;
}
return true;
}
* minLength(field, value, minNum, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isInt(minNum)) {
this.validator.addError(field, 'rule', 'min', 'The rule arguements for min fields needs to be an integer');
return false;
} else if (value.toString().length < parseInt(minNum)) {
if (message) {
message.replace(':minLength', minNum);
}
this.validator.addError(field, 'rule', 'minLength', message || 'The size of the field is lesser than the min arguement');
return false;
}
return true;
}
* notContains(field, value, inString, message) {
if (!valueExists(value)) {
return true;
}
if (typeof inString !== 'string') {
this.validator.addError(field, 'rule', 'notContains', 'The number of arguements provided is invalid. Please provide one single string');
return false;
} else {
if (v.contains(value, inString)) {
if (message) {
message.replace(':substring', inString);
}
this.validator.addError(field, 'rule', 'notContains', message || 'The value of the field can only contain letters and numbers');
return false;
}
}
return true;
}
* notIn(field, value, args, message) {
if (!valueExists(value)) {
return true;
}
if (!Array.isArray(args)) {
args = [args];
}
let noMatch = true;
for (let i = 0; i < args.length; i++) {
if (value == args[i]) {
noMatch = false;
}
}
if (!noMatch) {
this.validator.addError(field, 'rule', 'notIn', message || 'The value entered exists in the arguements supplied');
return false;
}
return true;
}
* numeric(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isNumeric(value.toString())) {
this.validator.addError(field, 'rule', 'numeric', message || 'The value entered is not numeric');
return false;
}
return true;
}
* regex(field, value, regexp, message) {
if (!valueExists(value)) {
return true;
}
if (!(regexp instanceof RegExp)) {
this.validator.addError(field, 'rule', 'regex', message || 'The regex arguement is not a valid regular expression');
return false;
} else if (!regexp.test(value)) {
if (message) {
message = message.replace(':regexp', regexp);
}
this.validator.addError(field, 'rule', 'regex', message || 'The value provided did not match with the regex format');
return false;
}
return true;
}
* same(field, value, otherField, message) {
if (!valueExists(value)) {
return true;
}
if (typeof otherField !== 'string') {
this.validator.addError(field, 'rule', 'same', message || 'The number of arguements provided is invalid. Please provide one single string');
return false;
} else {
otherField = otherField.split('.').filter((e) => { return e !== ''; });
let otherValue;
const self = this;
otherField.map((item) => {
if (typeof otherValue === 'undefined') {
otherValue = self.validator.fields && self.validator.fields[item];
} else {
otherValue = otherValue[item];
}
});
if (typeof otherValue === 'undefined') {
this.validator.addError(field, 'rule', 'same', message || 'The field you are comparing the value against does not exist');
return false;
} else if (otherValue != value) {
this.validator.addError(field, 'rule', 'same', message || 'The field you are comparing the value against are different');
return false;
}
}
return true;
}
* string(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (typeof value !== 'string') {
this.validator.addError(field, 'rule', 'string', message || 'The value provided is not a string');
return false;
}
return true;
}
* timezone(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!moment.tz.zone(value)) {
this.validator.addError(field, 'rule', 'timezone', message || 'The value provided is not a valid timezone');
return false;
}
return true;
}
* url(field, value, message) {
if (!valueExists(value)) {
return true;
}
if (!v.isURL(value)) {
this.validator.addError(field, 'rule', 'url', message || 'The value provided is not a URL');
return false;
}
return true;
}
* uuid(field, value, version, message) {
if (!valueExists(value)) {
return true;
}
const ver = parseInt(version);
if (!ver && !message) {
message = version;
}
if (!v.isUUID(value, ver || 4)) {
this.validator.addError(field, 'rule', 'uuid', message || `The value provided is not a v${ver || 4} UUID`);
return false;
}
return true;
}
* gt(field, value, number, message) {
if (!valueExists(value)) {
return true;
}
if (isNaN(number)) {
this.validator.addError(field, 'rule', 'gt', message || 'The number specified for gt is invalid');
return false;
}
value = parseInt(value);
number = parseInt(number);
if (value > number) {
return true;
}
this.validator.addError(field, 'rule', 'gt', message || `The value provided is not greater than ${number}`);
return false;
}
* lt(field, value, number, message) {
if (!valueExists(value)) {
return true;
}
if (isNaN(number)) {
this.validator.addError(field, 'rule', 'lt', message || 'The number specified for lt is invalid');
return false;
}
value = parseInt(value);
number = parseInt(number);
if (value < number) {
return true;
}
this.validator.addError(field, 'rule', 'lt', message || `The value provided is not less than ${number}`);
return false;
}
}
module.exports = Rules;