UNPKG

r2inspector

Version:

Sanitization and validation schema for Mongoose models

194 lines (166 loc) 4.78 kB
const is = require('is_js'); const traverse = require('traverse'); const dot = require('dotty'); const _ = require('underscore'); const getOptional = (options, obj) => { let optional; if (is.boolean(options.required)) { optional = !options.required; } else if (is.boolean(options.optional)) { optional = options.optional; } else { optional = true; } Object.assign(obj, { optional }); if (!optional) { Object.assign(obj, { $notEmpty: true }); } }; const getObjectId = (type, options, obj) => { if (type === 'objectid') { Object.assign(obj, { type: 'string', $objectId: true, ref: options.ref, }); } }; const getAllowHtml = (type, field, options, obj) => { if (type === 'string' && !options.allowHtml && !field.enumValidator) { Object.assign(obj, { $cleanHtml: true }); } }; const getPattern = (type, options, obj) => { const match = options.match; const pattern = options.pattern; if (match) { try { new RegExp(match); // eslint-disable-line Object.assign(obj, { pattern: match }); } catch (e) { Object.assign(options, { match: undefined }); } } else if (pattern && type === 'string') { // pattern string alanlarda kullanılabiliyor Object.assign(obj, { pattern }); } }; const getArrOpts = (options, props) => { if (options.arrOpts) { Object.assign(props, options.arrOpts); } if (!options.arrOpts || typeof options.arrOpts.optional === 'undefined') { Object.assign(props, { optional: true }); } }; const getValidators = (type, options, obj) => { const { minLength, maxLength, exactLength, min, max, lt, lte, gt, gte, ne, } = options; if (type === 'string' || type === 'array') { Object.assign(obj, _.pick({ minLength, maxLength, exactLength, }, _.identity)); } // number properties if (type === 'number') { Object.assign(obj, _.pick({ min, max, lt, lte, gt, gte, ne, }, _.identity)); } // equal if (['array', 'string', 'number', 'boolean'].includes(type)) { if (options.enum) { Object.assign(obj, { eq: options.enum }); } else if (options.eq) { Object.assign(obj, { eq: options.eq }); } } // default value if (typeof options.default !== 'undefined') { Object.assign(obj, { def: options.default }); } // settings if (typeof options.settings !== 'undefined') { Object.assign(obj, { settings: options.settings }); } }; const process = (paths, obj) => { _.each(paths, (field, name) => { if (name.startsWith('_')) { return false; } // array of objects if (field.schema) { const arrOpts = { type: 'array', items: { type: 'object', strict: true, properties: {}, }, }; getArrOpts(field.options, arrOpts); Object.assign(obj, { [name]: arrOpts }); return process( field.schema.paths, obj[name].items.properties); } const type = field.instance.toLowerCase(); const props = { type }; let arrType; let options; if (type === 'array') { arrType = field.caster.instance.toLowerCase(); props.type = 'array'; props.items = { type: arrType }; options = Object.assign(field.caster.options, field.options); getArrOpts(options, props); } const getType = arrType || type; const getOpts = options || field.options; const getProps = props.items || props; getOptional(getOpts, getProps); getObjectId(getType, getOpts, getProps); getAllowHtml(getType, field, getOpts, getProps); getPattern(getType, getOpts, getProps); getValidators(getType, getOpts, getProps); if (name.includes('.')) { const nameArr = name.split('.'); if (!obj[nameArr[0]]) { dot.put(obj, nameArr[0], { type: 'object', strict: true, optional: true, properties: {}, }); } dot.put(obj, `${nameArr[0]}.properties.${nameArr[1]}`, getProps); } return Object.assign(obj, { [name]: props }); }); }; module.exports = function Inspector() { return (mongoose, modelName) => { const model = mongoose.model(modelName); if (!model.inspector) { const obj = { type: 'object', strict: true, optional: false, properties: {}, }; process(model.schema.paths, obj.properties); model.inspector = obj; const updateObj = JSON.parse(JSON.stringify(obj)); traverse(updateObj).forEach(function (x) { // eslint-disable-line if (typeof x.optional !== 'undefined') { this.update(Object.assign(x, { optional: true })); } }); model.inspectorUpdate = updateObj; } }; };