123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- var Validator = require("validator")
- , Utils = require("./utils")
- // Backwards compat for people using old validation function
- // We cannot use .extend, since it coerces the first arg to string
- Validator.notNull = function (val) {
- return [null, undefined].indexOf(val) === -1
- }
- // https://github.com/chriso/validator.js/blob/1.5.0/lib/validators.js
- Validator.extend('notEmpty', function(str) {
- return !str.match(/^[\s\t\r\n]*$/);
- })
- Validator.extend('len', function(str, min, max) {
- return this.isLength(str, min, max)
- })
- Validator.extend('isUrl', function(str) {
- return this.isURL(str)
- })
- Validator.extend('isIPv6', function(str) {
- return this.isIP(str, 6)
- })
- Validator.extend('isIPv4', function(str) {
- return this.isIP(str, 4)
- })
- Validator.extend('notIn', function(str, values) {
- return !this.isIn(str, values)
- })
- Validator.extend('regex', function(str, pattern, modifiers) {
- str += '';
- if (Object.prototype.toString.call(pattern).slice(8, -1) !== 'RegExp') {
- pattern = new RegExp(pattern, modifiers);
- }
- return str.match(pattern);
- })
- Validator.extend('notRegex', function(str, pattern, modifiers) {
- return !this.regex(str, pattern, modifiers);
- })
- Validator.extend('isDecimal', function(str) {
- return str !== '' && str.match(/^(?:-?(?:[0-9]+))?(?:\.[0-9]*)?(?:[eE][\+\-]?(?:[0-9]+))?$/);
- })
- Validator.extend('min', function(str, val) {
- var number = parseFloat(str);
- return isNaN(number) || number >= val;
- })
- Validator.extend('max', function(str, val) {
- var number = parseFloat(str);
- return isNaN(number) || number <= val;
- })
- Validator.extend('not', function(str, pattern, modifiers) {
- return this.notRegex(str, pattern, modifiers);
- })
- Validator.extend('contains', function(str, elem) {
- return str.indexOf(elem) >= 0 && !!elem;
- })
- Validator.extend('notContains', function(str, elem) {
- return !this.contains(str, elem);
- })
- Validator.extend('is', function(str, pattern, modifiers) {
- return this.regex(str, pattern, modifiers);
- })
- var DaoValidator = module.exports = function(model, options) {
- options = options || {}
- options.skip = options.skip || []
- this.model = model
- this.options = options
- /**
- * Expose validator.js to allow users to extend
- * @name Validator
- */
- this.Validator = Validator
- }
- DaoValidator.prototype.validate = function() {
- var errors = {}
- errors = Utils._.extend(errors, validateAttributes.call(this))
- errors = Utils._.extend(errors, validateModel.call(this))
- return errors
- }
- DaoValidator.prototype.hookValidate = function() {
- var self = this
- , errors = {}
- return new Utils.CustomEventEmitter(function(emitter) {
- self.model.daoFactory.runHooks('beforeValidate', self.model, function(err) {
- if (!!err) {
- return emitter.emit('error', err)
- }
- errors = Utils._.extend(errors, validateAttributes.call(self))
- errors = Utils._.extend(errors, validateModel.call(self))
- if (Object.keys(errors).length > 0) {
- return emitter.emit('error', errors)
- }
- self.model.daoFactory.runHooks('afterValidate', self.model, function(err) {
- if (!!err) {
- return emitter.emit('error', err)
- }
- emitter.emit('success', self.model)
- })
- })
- }).run()
- }
- // private
- var validateModel = function() {
- var self = this
- , errors = {}
- // for each model validator for this DAO
- Utils._.each(this.model.__options.validate, function(validator, validatorType) {
- try {
- validator.apply(self.model)
- } catch (err) {
- errors[validatorType] = [err.message] // TODO: data structure needs to change for 2.0
- }
- })
- return errors
- }
- var validateAttributes = function() {
- var self = this
- , errors = {}
- Utils._.each(this.model.rawAttributes, function(rawAttribute, field) {
- var value = self.model.dataValues[field]
- , hasAllowedNull = ((rawAttribute === undefined || rawAttribute.allowNull === true) && ((value === null) || (value === undefined)))
- , isSkipped = self.options.skip.length > 0 && self.options.skip.indexOf(field) !== -1
- if (self.model.validators.hasOwnProperty(field) && !hasAllowedNull && !isSkipped) {
- errors = Utils._.merge(errors, validateAttribute.call(self, value, field))
- }
- })
- return errors
- }
- var validateAttribute = function(value, field) {
- var self = this
- , errors = {}
- // for each validator
- Utils._.each(this.model.validators[field], function(details, validatorType) {
- var validator = prepareValidationOfAttribute.call(self, value, details, validatorType)
- try {
- validator.fn.apply(null, validator.args)
- } catch (err) {
- var msg = err.message
- // if we didn't provide a custom error message then augment the default one returned by the validator
- if (!validator.msg && !validator.isCustom) {
- msg += ": " + field
- }
- // each field can have multiple validation errors stored against it
- errors[field] = errors[field] || []
- errors[field].push(msg)
- }
- })
- return errors
- }
- var prepareValidationOfAttribute = function(value, details, validatorType) {
- var isCustomValidator = false // if true then it's a custom validation method
- , validatorFunction = null // the validation function to call
- , validatorArgs = [] // extra arguments to pass to validation function
- , errorMessage = "" // the error message to return if validation fails
- if (typeof details === 'function') {
- // it is a custom validator function?
- isCustomValidator = true
- validatorFunction = Utils._.bind(details, this.model, value)
- } else {
- // it is a validator module function?
- // extract extra arguments for the validator
- validatorArgs = details.hasOwnProperty("args") ? details.args : details
- if (!Array.isArray(validatorArgs)) {
- validatorArgs = [validatorArgs]
- }
- // extract the error msg
- errorMessage = details.hasOwnProperty("msg") ? details.msg : undefined
- // check if Validator knows that kind of validation test
- if (!Utils._.isFunction(Validator[validatorType])) {
- throw new Error("Invalid validator function: " + validatorType)
- }
- validatorFunction = function () {
- if (!Validator[validatorType].apply(null, [value].concat(validatorArgs))) {
- throw new Error(errorMessage || "Validation "+validatorType+" failed")
- }
- }
- }
- return {
- fn: validatorFunction,
- msg: errorMessage,
- args: validatorArgs,
- isCustom: isCustomValidator
- }
- }
|