jsm-core
Version:
Core library for JSM project
501 lines (500 loc) • 21.8 kB
JavaScript
"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;