UNPKG

jsm-core

Version:
501 lines (500 loc) 21.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExcecutionScenario = exports.BaseService = void 0; /** * @description This is the base service class * @generator Jsm * @author dr. Salmi <reevosolutions@gmail.com> * @since 05-03-2024 07:06:13 */ const joi_1 = __importDefault(require("joi")); const jsm_exceptions_1 = __importDefault(require("jsm-exceptions")); const jsm_logger_1 = __importStar(require("jsm-logger")); const jsm_treeify_1 = __importDefault(require("jsm-treeify")); const jsm_utilities_1 = require("jsm-utilities"); const mongodb_1 = require("mongodb"); // import { initJouryCMSSdk } from "../utilities/data/sdk"; const jsm_logger_2 = require("jsm-logger"); const jsm_utilities_2 = require("jsm-utilities"); const say_1 = __importDefault(require("say")); const typedi_1 = __importDefault(require("typedi")); const context_1 = require("../../../context"); const auth_manager_1 = require("../../managers/auth-manager"); /** * This is the base service class */ class BaseService { constructor() { this.logger = (0, jsm_logger_1.default)(jsm_logger_1.LoggerContext.SERVICE, this.constructor.name); } /** * This method is used to log errors * @param {Function} method * @param {Error} error * @param {Jsm.Core.Security.AuthData} authData * @param {string} related_to * @param {any} scenario */ logError(method, error, authData, related_to, scenario) { if (error instanceof joi_1.default.ValidationError) { error = new jsm_exceptions_1.default.ValidationException("Validation Error", error); } if (process.env.NODE_ENV !== "production") { // console.log('Error in BaseService.logError:', // error instanceof exceptions.JsmException, // error instanceof exceptions.BadRequestException, // error instanceof exceptions.InternalServerError, // ); if (error && error instanceof mongodb_1.MongoServerError && error.code === 11000) { if ((0, context_1.getRegistry)().getConfig('logging.log_duplicate_errors') || method.name !== "create") this.logger.error(`DUPLICATE Error in ${this.constructor.name}.${method.name}`, error); } else { this.logger.error(`Error in ${this.constructor.name}.${method.name}: ${error.message}`, error); scenario && console.log((0, jsm_treeify_1.default)(scenario)); if (error.message) say_1.default.stop(); // say.speak( // `Service: ${config.currentService.name}, ${(error as any).message}`, // "Karen", // 1, // (err: string) => { // if (err) { // // this.logger.error("Error reading text:", err); // } // } // ); } } this.logger.save.error({ name: method.name.toSnakeCase(), related_to, payload: Object.assign({ error: (0, jsm_utilities_1.errorToObject)(error), scenario }, ((authData === null || authData === void 0 ? void 0 : authData.req) ? (0, jsm_utilities_1.extractRequestSignificantData)(authData === null || authData === void 0 ? void 0 : authData.req()) : {})), }); return; } /** * @description This method is used to log execution results * @param {Function} method * @param {Object} result * @param {Jsm.Core.Security.AuthData} auth_data * @param {any} scenario */ logExecutionResult(method_1, result_1, auth_data_1, scenario_1) { return __awaiter(this, arguments, void 0, function* (method, result, auth_data, scenario, is_error = false) { try { if (process.env.NODE_ENV !== "production") { if (is_error) this.logger.error(`${this.constructor.name}.${method.name}`, `Error scenario:`); else this.logger.success(`${this.constructor.name}.${method.name}`, `Successfull scenario:`); console.log((0, jsm_treeify_1.default)(scenario)); } } catch (error) { this.logger.error(`Error in ${this.constructor.name}.logExecutionResult:`, error); } }); } getPaginationOptions(count, page) { if (typeof count === "string") count = parseInt(count); // this.logger.debug(this.getPaginationOptions.name, count, typeof count); if (count === -1 || !count) return { skip: 0, take: 0 }; const skip = ((page || 1) - 1) * count; const take = count; return { skip, take }; } /** * * @param {"asc" | "desc"} sort * - @default "desc" * @param {string} sort_by * - @default * - "created_at" if prefer_update_date = false * - "updated_at" if prefer_update_date = true * @param {boolean} prefer_update_date * - @default false * @returns */ getSortOptions(sort, sort_by, prefer_update_date) { const sortOptions = {}; sortOptions[sort_by ? sort_by : prefer_update_date ? "updated_at" : "created_at"] = sort === "asc" ? 1 : -1; return sortOptions; } getSelectFields(q, fields) { if (!fields) return q; if (typeof fields === "string" && fields.includes(",")) fields = fields.split(",").map((f) => f.trim()); else if (typeof fields === "string") fields = fields.split(",").map((f) => f.trim()); else if (!Array.isArray(fields)) return q; return q.select(fields.join(" ")); } analyzeMongodbQuery(q) { return __awaiter(this, void 0, void 0, function* () { this.logger.info("ANALYZE_MONGODB_QUERY", q.explain()); }); } get sdk() { if (this._sdk) return this._sdk; this._sdk = (0, context_1.getRegistry)().sdk; return this._sdk; } flattenUpdateObject(updateObj) { function groupNestedProperties(updateObject) { const groupedObject = {}; for (const key in updateObject) { const dotCount = (0, jsm_utilities_2.countCharacterOccurrenceInString)(key, "."); // If the property has three dots, we group it under the first part if (dotCount === 3) { const firstPart = key.split(".").slice(0, 3).join("."); if (!groupedObject[firstPart]) { groupedObject[firstPart] = {}; } // Add the property to the corresponding grouped object const secondPart = key.split(".").slice(3).join("."); groupedObject[firstPart][secondPart] = updateObject[key]; } // If the property has two dots, we group it under the first part else if (dotCount === 2) { const firstPart = key.split(".").slice(0, 2).join("."); if (!groupedObject[firstPart]) { groupedObject[firstPart] = {}; } // Add the property to the corresponding grouped object const secondPart = key.split(".").slice(2).join("."); groupedObject[firstPart][secondPart] = updateObject[key]; } else { // If no two dots, just copy the property as it is groupedObject[key] = updateObject[key]; } } return groupedObject; } const flattenObjectKeys = (obj, prefix = "") => Object.keys(obj).reduce((acc, k) => { const pre = prefix.length ? prefix + "." : ""; if (obj[k] instanceof Object && !Array.isArray(obj[k]) && obj[k] !== null) { acc = Object.assign(Object.assign({}, acc), flattenObjectKeys(obj[k], pre + k)); } else { acc[pre + k] = obj[k]; } return acc; }, {}); // return flattenObjectKeys(updateObj); return groupNestedProperties(groupNestedProperties(flattenObjectKeys(updateObj))); } /** * @description This method is used to get the internal authentication data * @author dr. Salmi <reevosolutions@gmail.com> * @since 23-05-2024 06:40:43 */ get internalAuthData() { const authData = { current: { service: { name: (0, context_1.getRegistry)().getConfig('currentService.name'), is_external: false, }, }, }; return authData; } /** * Update : generateSdkRequestConfigFromAuthData * @description used to port the authentication credentials between the services * @author dr. Salmi <reevosolutions@gmail.com> * @since 23-05-2024 06:39:42 */ generateSdkRequestConfigFromAuthData(authData, setInternalAuthData = true) { var _a, _b, _c, _d, _e; if (!authData) return undefined; const authManager = typedi_1.default.get(auth_manager_1.AuthManager); let token = (_a = authData.current) === null || _a === void 0 ? void 0 : _a.token; if (((_b = authData.current) === null || _b === void 0 ? void 0 : _b.user) && !((_c = authData.current) === null || _c === void 0 ? void 0 : _c.token)) { token = authManager.generateToken({ role: authData.current.user.role, _id: authData.current.user._id, tracking_id: authData.current.user.tracking_id, space: "default", }, "default", false, (0, context_1.getRegistry)().getConfig('security.jwt')); } const config = Object.assign({ token, app: (_e = (_d = authData.current) === null || _d === void 0 ? void 0 : _d.app) === null || _e === void 0 ? void 0 : _e._id }, (setInternalAuthData ? this.internalAuthData : {})); return config; } dispatchEvent(eventName, payload) { if (this["eventDispatcher"] && this["eventDispatcher"].dispatch) { this["eventDispatcher"].dispatch(eventName, payload); } else this.logger.warn("EventDispatcher is not available"); } initScenario(logger, method, args, authData) { return new ExcecutionScenario(this.constructor.name, logger, method.name, args || {}, authData || null); } calculateTimePeriod(timePeriod) { // Initialize time period boundaries const now = new Date(); let startDate; let endDate; let granularity = "day"; let timezone; let preset; if (timePeriod) { granularity = timePeriod.granularity || "day"; timezone = timePeriod.timezone; preset = timePeriod.preset; if (timePeriod.preset === "custom") { // Use provided start and end dates for custom preset startDate = new Date(timePeriod.start); endDate = new Date(timePeriod.end); } else { // Calculate dates based on preset const today = new Date(); today.setHours(0, 0, 0, 0); // Start of today at midnight switch (timePeriod.preset) { case "today": startDate = new Date(today); endDate = new Date(today); endDate.setHours(23, 59, 59, 999); // End of today break; case "yesterday": startDate = new Date(today); startDate.setDate(today.getDate() - 1); // Yesterday at midnight endDate = new Date(startDate); endDate.setHours(23, 59, 59, 999); // End of yesterday break; case "last_7_days": startDate = new Date(today); startDate.setDate(today.getDate() - 6); // 7 days ago (including today) endDate = new Date(today); endDate.setHours(23, 59, 59, 999); // End of today break; case "last_30_days": startDate = new Date(today); startDate.setDate(today.getDate() - 29); // 30 days ago (including today) endDate = new Date(today); endDate.setHours(23, 59, 59, 999); // End of today break; case "last_90_days": startDate = new Date(today); startDate.setDate(today.getDate() - 89); // 90 days ago (including today) endDate = new Date(today); endDate.setHours(23, 59, 59, 999); // End of today break; case "last_year": startDate = new Date(today); startDate.setFullYear(today.getFullYear() - 1); // 1 year ago endDate = new Date(today); endDate.setHours(23, 59, 59, 999); // End of today break; default: // Fallback to last 30 days startDate = new Date(today); startDate.setDate(today.getDate() - 29); endDate = new Date(today); endDate.setHours(23, 59, 59, 999); break; } } } else { // Default to last 30 days if no timePeriod provided const today = new Date(); today.setHours(0, 0, 0, 0); startDate = new Date(today); startDate.setDate(today.getDate() - 29); endDate = new Date(today); endDate.setHours(23, 59, 59, 999); granularity = "day"; } return { now, startDate, endDate, granularity, timezone, preset, }; } } exports.BaseService = BaseService; class ExcecutionScenario { constructor(_class, logger, method, args = {}, authData = null) { this.execution = {}; this._class = _class; this.logger = logger; this.method = method; this.args = args; this.authData = authData; this.timer = (0, jsm_utilities_2.initTimer)(); } set(key, value) { if (typeof key === "object") { Object.keys(key).forEach((k) => this.set(k, key[k])); } else this.execution[key] = value; return this; } get(key) { return this.execution[key]; } progress(logger, progress, message) { logger.debug((0, jsm_logger_2.generateProgressBar)(progress), message || this.method); } /** * @description This method is used to log execution results * @param {Function} method * @param {Object} result * @param {Jsm.Core.Security.AuthData} auth_data * @param {any} scenario */ log() { return __awaiter(this, arguments, void 0, function* (purpose = "success") { try { if ((0, context_1.getRegistry)().getConfig('isDev') || (0, context_1.getRegistry)().getConfig('dev.debugProduction')) { if (purpose === "error") this.logger.error(`${this._class}.${this.method}`, `Error scenario:`); else if (purpose === "warn") this.logger.warn(`${this._class}.${this.method}`, `Warning scenario:`); else this.logger.success(`${this._class}.${this.method}`, `Successfull scenario in ${this.timer.timeString}`); console.log((0, jsm_treeify_1.default)({ args: this.args, execution: this.execution, execution_time: this.timer.timeString, })); } } catch (error) { this.logger.error(`Error in ${this._class}.logExecutionResult:`, error); } }); } end() { return __awaiter(this, arguments, void 0, function* (purpose = "success") { return yield this.log(purpose); }); } step(logger, data) { return __awaiter(this, void 0, void 0, function* () { try { if ((0, context_1.getRegistry)().getConfig('isDev')) { logger.value(`${this._class}.${this.method}.step at: ${this.timer.timeString}`, data); } } catch (error) { logger.error(`Error in ${this._class}.logExecutionResult:`, error); } }); } /** * This method is used to log errors * @param {Function} method * @param {Error} error * @param {Jsm.Core.Security.AuthData} authData * @param {string} related_to * @param {any} scenario */ error(error) { var _a, _b; if (error instanceof joi_1.default.ValidationError) { error = new jsm_exceptions_1.default.ValidationException("Validation Error", error); } if ((0, context_1.getRegistry)().getConfig('isDev')) { // console.log('Error in BaseService.logError:', // error instanceof exceptions.JsmException, // error instanceof exceptions.BadRequestException, // error instanceof exceptions.InternalServerError, // ); if (error instanceof mongodb_1.MongoServerError && error.code === 11000) { if ((0, context_1.getRegistry)().getConfig('logging.log_duplicate_errors') || this.method !== "create") this.logger.error(`DUPLICATE Error in ${this._class}.${this.method}`, error); } else { this.logger.error(`Error in ${this._class}.${this.method}: ${error.message}`, error); console.log((0, jsm_treeify_1.default)({ args: this.args, execution: this.execution })); if (error.message) say_1.default.stop(); // FIXME: Uncomment this // say.speak( // `Service: ${config.currentService.name}, ${(error as any).message}`, // "Karen", // 1, // (err: string) => { // if (err) { // // this.logger.error("Error reading text:", err); // } // } // ); } } this.logger.save.error({ name: this.method.toSnakeCase(), payload: Object.assign({ error: (0, jsm_utilities_1.errorToObject)(error), scenario: this.execution }, (((_a = this.authData) === null || _a === void 0 ? void 0 : _a.req) ? (0, jsm_utilities_1.extractRequestSignificantData)((_b = this.authData) === null || _b === void 0 ? void 0 : _b.req()) : {})), }); return; } } exports.ExcecutionScenario = ExcecutionScenario;