import { Request, Response, NextFunction } from "express"; import { Logging } from "@hibas123/nodelogging"; import { isBoolean, isString, isNumber, isObject, isDate, isArray, isSymbol, } from "util"; import RequestError, { HttpStatusCode } from "../../helper/request_error"; export enum Types { STRING, NUMBER, BOOLEAN, EMAIL, OBJECT, DATE, ARRAY, ENUM, } function isEmail(value: any): boolean { return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test( value ); } export interface CheckObject { type: Types; query?: boolean; optional?: boolean; /** * Only when Type.ENUM * * values to check before */ values?: string[]; /** * Only when Type.STRING */ notempty?: boolean; // Only STRING } export interface Checks { [index: string]: CheckObject; // | Types } // req: Request, res: Response, next: NextFunction export default function (fields: Checks, noadditional = false) { return (req: Request, res: Response, next: NextFunction) => { let errors: { message: string; field: string }[] = []; function check(data: any, field_name: string, field: CheckObject) { if (data !== undefined && data !== null) { switch (field.type) { case Types.STRING: if (isString(data)) { if (!field.notempty) return; if (data !== "") return; } break; case Types.NUMBER: if (isNumber(data)) return; break; case Types.EMAIL: if (isEmail(data)) return; break; case Types.BOOLEAN: if (isBoolean(data)) return; break; case Types.OBJECT: if (isObject(data)) return; break; case Types.ARRAY: if (isArray(data)) return; break; case Types.DATE: if (isDate(data)) return; break; case Types.ENUM: if (isString(data)) { if (field.values.indexOf(data) >= 0) return; } break; default: Logging.error( `Invalid type to check: ${field.type} ${Types[field.type]}` ); } errors.push({ message: res.__( "Field {{field}} has wrong type. It should be from type {{type}}", { field: field_name, type: Types[field.type].toLowerCase() } ), field: field_name, }); } else { if (!field.optional) errors.push({ message: res.__("Field {{field}} is not defined", { field: field_name, }), field: field_name, }); } } for (let field_name in fields) { let field = fields[field_name]; let data = fields[field_name].query ? req.query[field_name] : req.body[field_name]; check(data, field_name, field); } if (noadditional) { //Checks if the data given has additional parameters let should = Object.keys(fields); should = should.filter((e) => !fields[e].query); //Query parameters should not exist on body let has = Object.keys(req.body); has.every((e) => { if (should.indexOf(e) >= 0) { return true; } else { errors.push({ message: res.__("Field {{field}} should not be there", { field: e, }), field: e, }); return false; } }); } if (errors.length > 0) { let err = new RequestError(errors, HttpStatusCode.BAD_REQUEST, true); next(err); } else next(); }; }