@minimaltech/node-infra
Version:
Minimal Technology NodeJS Infrastructure - Loopback 4 Framework
213 lines • 10.2 kB
JavaScript
;
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