UNPKG

@szegedsw/lib-node

Version:

A little framework published by Szeged Software Zrt. in order to enhance api endpoint security and create reuseable code. Email module, Logging system, and much more. Further improvements are expected.

308 lines 16.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Controller = void 0; const lodash_1 = require("lodash"); const http_codes_1 = require("../config/http-codes"); const request_1 = require("../express/request"); const router_1 = require("../express/router"); const try_1 = require("../functions/try"); const html_generator_1 = require("../html-generator/html-generator"); const ifield_interface_1 = require("../interfaces/ifield.interface"); const logger_1 = require("../logger/logger"); const property_group_result_1 = require("./helper/property-group-result"); const property_validation_result_1 = require("./helper/property-validation-result"); const validator_state_1 = require("./helper/validator-state"); const test_html_1 = require("./html/test.html"); class Controller extends router_1.Routed { constructor() { super(...arguments); Object.defineProperty(this, "errors", { enumerable: true, configurable: true, writable: true, value: {} }); Object.defineProperty(this, "splitter", { enumerable: true, configurable: true, writable: true, value: "#" }); Object.defineProperty(this, "onError", { enumerable: true, configurable: true, writable: true, value: async () => undefined }); } async validator(req, res) { var _a; const input = request_1.requestParams(req); logger_1.Logger.trace(`${req.method} ${req.path} request => ${JSON.stringify(input)}`, false); const model = this[`${req.method.toLowerCase()}Model`]; if (model !== undefined) { // logger.trace("eazy/Controller => model is not empty ", false); if (!Controller.modelValidator(input, model)) { logger_1.Logger.trace(`${req.method} ${req.path} response => ${http_codes_1.HttpCodes.unprocessableEntity}`, false); if (this.isSendHelpMessage) { const helpResponse = await this.createHelpResponse(input, model); res.status(http_codes_1.HttpCodes.unprocessableEntity).send(helpResponse); // .catch((err) => { // Logger.error(err, "html_helpermsg_0", true); // res.status(HttpCodes.internalError).send(err); // }); } else { await try_1._try(res, async () => { throw new Error("unprocessable entity"); }, { "unprocessable entity": ((_a = this.errors) === null || _a === void 0 ? void 0 : _a["unprocessable entity"]) || { code: "unprocessableEntity", body: "Unprocessable entity!", }, }); } return false; } } else { logger_1.Logger.trace(`Controller => no model to use on ${req.method} => ${req.path}`, false); } logger_1.Logger.trace(`${req.method} ${req.path} => Validated!`, false); return true; } static modelValidator(object, model) { return model.groups.some((groupitem) => { const optionalCount = groupitem.filter((item) => item.optional === true).length; const count = Object.keys(object).length; return (count >= groupitem.length - optionalCount && count <= groupitem.length && groupitem.every((field) => { if (Controller.fieldValidator(object, field)) { logger_1.Logger.trace(`Controller => modelValidator => property is valid: '${field.name}'`, false); return true; } logger_1.Logger.trace(`Controller => modelValidator => invalid property: '${field.name}'`, false); return false; }) && Object.keys(object).every((k) => { if (!groupitem.some((i) => i.name === k)) { logger_1.Logger.trace(`Controller => modelValidator => definition not provided: '${k}'`, false); return false; } return true; })); }); } static fieldValidator(object, field) { if (!Object.keys(object).includes(field.name)) { if (field.optional) { logger_1.Logger.trace(`Optional property skipped, because it was not provided: ${field.name}`, false); return true; } logger_1.Logger.trace(`Property is missing: ${field.name}`, false); return false; } logger_1.Logger.trace(`Controller => fieldValidator => property found: ${field.name}`, false); const value = object[field.name]; const checkValidators = (val = value) => { var _a; if (!field.validators) { return true; } return (_a = field.validators) === null || _a === void 0 ? void 0 : _a.every((validator) => { if (validator.validate(field.type === ifield_interface_1.FieldType.string ? String(val).trim() : val)) { return true; } logger_1.Logger.trace(`'${field.name}' validation failed: ${validator.helpMessage}`); return false; }); }; switch (field.type) { case ifield_interface_1.FieldType.date: // eslint-disable-next-line no-case-declarations const date = new Date(Date.parse(value)); if (Number.isNaN(date.getTime())) { logger_1.Logger.trace(`'${field.name}' [Date] is invalid and could not be parsed!`, false); return false; } if (field.min instanceof Date && field.max instanceof Date) { if (field.min <= date && field.max >= date) { return checkValidators(); } logger_1.Logger.trace(`'${field.name}' [Date] is out of defined range!`, false); } else { logger_1.Logger.error(`Inconsistent min/max value defined for field: ${field.name}`); } break; case ifield_interface_1.FieldType.number: if (!Number.isNaN(value)) { if (typeof field.min === "number" && typeof field.max === "number") { if (field.min <= value && field.max >= value) { return checkValidators(); } } else { logger_1.Logger.error(`Inconsistent min/max value defined for field: ${field.name}`); } } break; case ifield_interface_1.FieldType.string: if (value === value.toString()) { if (typeof value === "string") { if ((field.min || 0) <= value.length && (field.max || value.length) >= value.length) { return checkValidators(); } } } break; case ifield_interface_1.FieldType.boolean: if (typeof value === "boolean" || ["TRUE", "FALSE", "0", "1"].includes(String(value).toUpperCase())) { return true; } break; case ifield_interface_1.FieldType.array: if (typeof value === "object" && Array.isArray(value)) { if (field.min === undefined || field.max === undefined) { logger_1.Logger.error(`Inconsistent min/max value defined for field: ${field.name}`); return true; } if (value.length >= field.min && value.length <= field.max) { return checkValidators(JSON.stringify(value)); } } break; case ifield_interface_1.FieldType.object: return checkValidators(); default: return false; } return false; } async createHelpResponse(object, model) { try { const groups = []; if (!model.groups || model.groups.length === 0) { logger_1.Logger.warning(`Model groups are undefined! Please add least 1 group! Model interfaceMsg: ${model.interfaceHelpMessage}`, true); } else { model.groups.forEach((fields) => { const gResult = new property_group_result_1.PropertyGroupResult(); const keys = Object.keys(object); gResult.propertyCountOk = keys.length === fields.length; fields.forEach((field) => { const res = new property_validation_result_1.PropertyValidationResult(); res.name = field.optional ? `${field.name} (optional)` : field.name; res.value = object[field.name]; if (field.type === ifield_interface_1.FieldType.array) { res.value = JSON.stringify(object[field.name]); } res.exists = object[field.name] !== undefined; if (res.exists) { // typecheck switch (field.type) { case ifield_interface_1.FieldType.date: res.typecheck = !Number.isNaN(new Date(Date.parse(object[field.name])).getTime()); break; case ifield_interface_1.FieldType.number: res.typecheck = !Number.isNaN(object[field.name]); break; case ifield_interface_1.FieldType.string: res.typecheck = object[field.name] === object[field.name].toString(); break; case ifield_interface_1.FieldType.boolean: // eslint-disable-next-line no-case-declarations const val = lodash_1.toUpper(object[field.name]); res.typecheck = val === "TRUE" || val === "FALSE" || object[field.name] === 0 || object[field.name] === 1; break; case ifield_interface_1.FieldType.array: res.typecheck = typeof object[field.name] === "object" && Array.isArray(object[field.name]); break; case ifield_interface_1.FieldType.object: res.typecheck = typeof object[field.name] === "object" && !Array.isArray(object[field.name]); break; default: return; } // fill type res.type = field.type.toString(); // if correct type was passed if (res.typecheck) { switch (field.type) { case ifield_interface_1.FieldType.date: if (field.min !== undefined && field.max !== undefined) { res.min = field.min <= new Date(Date.parse(object[field.name])); res.max = field.max >= new Date(Date.parse(object[field.name])); if (field.min instanceof Date && field.max instanceof Date) { res.minVal = field.min.toFormattedString("YYYY/MM/DD hh24:mm"); res.maxVal = field.max.toFormattedString("YYYY/MM/DD hh24:mm"); } } break; case ifield_interface_1.FieldType.number: if (field.min !== undefined && field.max !== undefined) { res.min = field.min <= object[field.name]; res.max = field.max >= object[field.name]; res.minVal = field.min.toString(); res.maxVal = field.max.toString(); } break; case ifield_interface_1.FieldType.string: if (field.min !== undefined && field.max !== undefined) { res.min = field.min <= object[field.name].toString().length; res.max = field.max >= object[field.name].toString().length; res.minVal = field.min.toString(); res.maxVal = field.max.toString(); } break; case ifield_interface_1.FieldType.boolean: res.min = true; res.max = true; break; case ifield_interface_1.FieldType.array: if (field.min !== undefined && field.max !== undefined) { res.min = field.min <= object[field.name].length; res.max = field.max >= object[field.name].length; res.minVal = field.min.toString(); res.maxVal = field.max.toString(); } break; default: return; } } if (!field.validators) { logger_1.Logger.warning(`Field validators is undefined please initialize that! Field name: ${field.name}`, true); } else { // let val = object[field.name]; // if (field.type === FieldType.array) { val = JSON.stringify(object[field.name]); } field.validators.forEach((validator) => { res.validators.push(new validator_state_1.ValidatorState(validator.helpMessage, !!validator.validate(res.value))); }); } } const index = keys.findIndex((prd) => prd === field.name); if (index > -1) { keys.splice(index, 1); } gResult.properties.push(res); }); gResult.additional = keys; groups.push(gResult); }); } const HTML = new html_generator_1.HtmlGenerator(test_html_1.testhtml, { groups }); return await HTML.generate(); } catch (ex) { return new Promise((_resolve, reject) => { logger_1.Logger.error(ex === null || ex === void 0 ? void 0 : ex.stack); reject(ex); }); } } } exports.Controller = Controller; //# sourceMappingURL=controller.class.js.map