UNPKG

@minimaltech/node-infra

Version:

Minimal Technology NodeJS Infrastructure - Loopback 4 Framework

213 lines 10.2 kB
"use strict"; 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.GeneratePermissionService = void 0; const helpers_1 = require("../../../helpers"); const union_1 = __importDefault(require("lodash/union")); const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const common_1 = require("../common"); const decorators_1 = require("../decorators"); class GeneratePermissionService { getMethodsClass(controllerPrototype) { return Reflect.ownKeys(controllerPrototype).slice(1); } getAllMethodsClass(controllerPrototype) { let methods = []; let currentPrototype = controllerPrototype; while (currentPrototype && currentPrototype !== Object.prototype) { methods = [...methods, ...this.getMethodsClass(currentPrototype)]; currentPrototype = Reflect.getPrototypeOf(currentPrototype); } return methods; } generateParentPermissions(opts) { return __awaiter(this, void 0, void 0, function* () { var _a; const { controller, permissionRepository } = opts !== null && opts !== void 0 ? opts : {}; const controllerName = controller.name; const permissionSubject = (_a = controllerName.replace(/Controller/g, '')) === null || _a === void 0 ? void 0 : _a.toLowerCase(); const parentPermissions = { name: `All permissions of ${permissionSubject}`, code: `${permissionSubject}.*`, subject: permissionSubject, action: common_1.EnforcerDefinitions.ACTION_EXECUTE, pType: 'p', }; yield permissionRepository.upsertWith(Object.assign({}, parentPermissions), { code: parentPermissions.code }); }); } generatePermissions(opts) { const { methods, permissionSubject, parentId, allPermissionDecoratorData } = opts !== null && opts !== void 0 ? opts : {}; return methods.map(m => { return { name: `Permission ${m} ${permissionSubject}`, code: `${permissionSubject}.${m}`, subject: permissionSubject, action: common_1.EnforcerDefinitions.ACTION_EXECUTE, scope: m.match(/get|find|search|count/gim) ? common_1.EnforcerDefinitions.ACTION_READ : common_1.EnforcerDefinitions.ACTION_WRITE, pType: 'p', parentId, details: allPermissionDecoratorData === null || allPermissionDecoratorData === void 0 ? void 0 : allPermissionDecoratorData[m], }; }); } generatePermissionBaseInherit(opts) { const { methodsChildClass, methodsParentsClass, parentPermission, allPermissionDecoratorData } = opts !== null && opts !== void 0 ? opts : {}; const defaultPermissions = [ 'count', 'create', 'find', 'findOne', 'findById', 'replaceById', 'updateById', 'deleteById', 'updateAll', ]; const permissions = this.generatePermissions({ methods: (0, union_1.default)(defaultPermissions, methodsParentsClass, methodsChildClass), permissionSubject: parentPermission.subject, parentId: parentPermission.id, allPermissionDecoratorData, }); return permissions; } generatePermissionRecords(opts) { const { controller, parentPermission, allPermissionDecoratorData } = opts; const permissionRecords = []; const controllerPrototype = controller.prototype; const methodsChildClass = this.getMethodsClass(controllerPrototype); const parentClass = Reflect.getPrototypeOf(controllerPrototype); const methodsParentsClass = this.getAllMethodsClass(parentClass); permissionRecords.push(...this.generatePermissionBaseInherit({ methodsParentsClass, methodsChildClass, parentPermission, allPermissionDecoratorData, })); return permissionRecords; } updatePermissionByChangeMethodName(permissionSubject, allPermissionDecoratorData, permissionRepository) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; if (!Object.values(allPermissionDecoratorData).length) { return; } const allPermissionDecorators = Object.entries(allPermissionDecoratorData); for (const [key, value] of allPermissionDecorators) { const permissionsFound = yield permissionRepository.find({ where: { subject: permissionSubject, code: { neq: `${permissionSubject}.*`, }, }, }); for (const p of permissionsFound) { if (!((_a = p === null || p === void 0 ? void 0 : p.details) === null || _a === void 0 ? void 0 : _a.idx) || ((_b = p === null || p === void 0 ? void 0 : p.details) === null || _b === void 0 ? void 0 : _b.idx) !== value.idx) { continue; } yield permissionRepository.updateById(p.id, Object.assign(Object.assign({}, p), { code: `${permissionSubject}.${key}`, details: Object.assign({}, value) })); } } }); } startMigration(opts) { return __awaiter(this, void 0, void 0, function* () { var _a; const { permissionRepository, controllers } = opts; const permissions = []; for (const controller of controllers) { const permissionSubject = controller.name.replace(/Controller/g, '').toLowerCase(); const controllerPrototype = controller.prototype; helpers_1.applicationLogger.info('[Migrate Permissions] Migration permissions for: %s', controller.name); yield this.generateParentPermissions({ controller, permissionRepository }); const parentPermission = yield permissionRepository.findOne({ where: { subject: permissionSubject }, }); if (!parentPermission) { continue; } const allPermissionDecoratorData = (_a = (0, decorators_1.getDecoratorData)(controllerPrototype, decorators_1.MetadataDecoratorKeys.PERMISSION)) !== null && _a !== void 0 ? _a : {}; const permissionList = this.generatePermissionRecords({ controller, parentPermission, permissionRepository, allPermissionDecoratorData, }); yield this.updatePermissionByChangeMethodName(permissionSubject, allPermissionDecoratorData, permissionRepository); permissions.push(...permissionList); } for (const p of permissions) { yield permissionRepository.upsertWith(p, { code: p.code }); } }); } /** * Obtain all permission codes for a controller * * @returns {string[]} List of permission codes */ getPermissionCodes(opts) { const { controllers } = opts; const permissionCodes = []; for (const controller of controllers) { const permissionSubject = controller.name.replace(/Controller/g, '').toLowerCase(); permissionCodes.push(`${permissionSubject}.*`); const methods = this.getAllMethodsClass(controller.prototype); for (const method of methods) { permissionCodes.push(`${permissionSubject}.${method}`); } } helpers_1.applicationLogger.info('[getPermissionCodes] Permission codes: %o', permissionCodes); return permissionCodes; } /** * Write all permission codes for a list of controllers to a file * * @param outputPath - Path to write * * @example * const generatePermissionService = new GeneratePermissionService(); * * generatePermissionService.getPermissionCodesAndWriteToFile({ * controllers: [XboxController, PSController, NintendoController], * outputPath: './src/migrations/', * fileName: 'permissionCodes', * fileType: 'ts', * }); */ getPermissionCodesAndWriteToFile(opts) { const { controllers, outputPath = './src/', fileName = 'permission-codes', fileType = 'ts', } = opts; const permissionCodes = this.getPermissionCodes({ controllers }); if (permissionCodes.length === 0) { return; } const fileContent = []; if (fileType === 'ts') { fileContent.push('const permissionCodes: string[] = ['); } fileContent.push(...permissionCodes.map(code => ` '${code}',`)); if (fileType === 'ts') { fileContent.push(' ];'); } const filePath = `${outputPath}/${fileName}.${fileType}`; (0, node_fs_1.writeFileSync)((0, node_path_1.resolve)(filePath), fileContent.join('\n'), 'utf8'); } } exports.GeneratePermissionService = GeneratePermissionService; //# sourceMappingURL=generator.service.js.map