UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

298 lines • 16.3 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProcessDefinitionMediator = void 0; const inversify_1 = require("inversify"); const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const IocRegistrations_1 = require("../Contracts/IocRegistrations"); const index_1 = require("./DatabaseAdaptersSequelize/index"); const index_2 = require("./Iam/index"); let ProcessDefinitionMediator = class ProcessDefinitionMediator { bpmnModelParser = new processcube_engine_sdk_1.BpmnModelParser(); definitionsCache = {}; iamService; logger; processDefinitionDatabaseAdapter; constructor(iamService, processDefinitionAdapter) { this.iamService = iamService; this.logger = new processcube_engine_sdk_1.Logger('engine:process_definition_mediator'); this.processDefinitionDatabaseAdapter = processDefinitionAdapter; } async persistProcessDefinitions(identity, xml, overwriteExisting) { if (!Array.isArray(xml) && typeof xml !== 'string') { const invalidDeployRequest = new processcube_engine_sdk_1.BadRequestError('Must provide XMLs as String or String-Array.'); invalidDeployRequest.additionalInformation = { receivedXmlToDeploy: xml, }; throw invalidDeployRequest; } const rawXmlList = Array.isArray(xml) ? xml : [xml]; const undeployableBpmns = []; const bpmnsToDeploy = []; for (const xml of rawXmlList) { const parsedBpmn = await this.parseAndValidateDefinition(xml); const sanitizedBpmns = this.filterInaccessibleProcessModels(parsedBpmn.processes, identity); if (sanitizedBpmns.length === 0) { undeployableBpmns.push(parsedBpmn.id); } else { parsedBpmn.raw = xml; bpmnsToDeploy.push(parsedBpmn); } } if (bpmnsToDeploy.length > 0) { await this.processDefinitionDatabaseAdapter.persistProcessDefinition(identity, bpmnsToDeploy, overwriteExisting); } if (undeployableBpmns.length === 1) { throw new processcube_engine_sdk_1.ForbiddenError(`Cannot deploy Process Definition ${undeployableBpmns[0]}, because you have no access to any of its lanes`); } else if (undeployableBpmns.length > 1) { throw new processcube_engine_sdk_1.ForbiddenError(`Cannot deploy Process Definitions ${undeployableBpmns.join(', ')}, because you have no access to any of their lanes`); } } async getAll(identity, offset, limit, includeCount = true) { const results = await this.processDefinitionDatabaseAdapter.getAllProcessDefinitions(offset, limit, includeCount); const parsedResults = await Promise.all(results.processDefinitions.map(this.parseProcessDefinition.bind(this))); const sanitizedList = this.filterInaccessibleProcessDefinitions(parsedResults, identity); for (const definition of sanitizedList) { const rawDefinition = results.processDefinitions.find((processDefinitionEntry) => processDefinitionEntry.name === definition.id); this.applyFlagsToProcessDefinition(definition, rawDefinition); } return sanitizedList; } async getDefinitionsWithRunningInstances(identity, processModelIds) { const results = await this.processDefinitionDatabaseAdapter.getDefinitionsWithRunningInstances(processModelIds); const parsedResults = await Promise.all(results.processDefinitions.map(this.parseProcessDefinition.bind(this))); const sanitizedList = this.filterInaccessibleProcessDefinitions(parsedResults, identity); for (const definition of sanitizedList) { const rawDefinition = results.processDefinitions.find((processDefinitionEntry) => processDefinitionEntry.name === definition.id); this.applyFlagsToProcessDefinition(definition, rawDefinition); } return sanitizedList; } async getByName(identity, name) { const processDefinitionRaw = await this.processDefinitionDatabaseAdapter.getByName(name); const processDefinition = await this.parseProcessDefinition(processDefinitionRaw); const filteredProcessModels = this.filterInaccessibleProcessModels(processDefinition.processes, identity); if (filteredProcessModels.length === 0) { throw new processcube_engine_sdk_1.ForbiddenError('Access denied.'); } processDefinition.processes = filteredProcessModels; this.applyFlagsToProcessDefinition(processDefinition, processDefinitionRaw); return processDefinition; } async getByHash(identity, hash, includeDeleted = false) { const processDefinitionRaw = await this.processDefinitionDatabaseAdapter.getByHash(hash, includeDeleted); const processDefinition = await this.parseProcessDefinition(processDefinitionRaw); const filteredProcessModels = this.filterInaccessibleProcessModels(processDefinition.processes, identity); if (filteredProcessModels.length === 0) { throw new processcube_engine_sdk_1.ForbiddenError('Access denied.'); } processDefinition.processes = filteredProcessModels; this.applyFlagsToProcessDefinition(processDefinition, processDefinitionRaw); return processDefinition; } async getByProcessModelId(identity, processModelId) { if (!processModelId) { throw new processcube_engine_sdk_1.BadRequestError(`No processModelId provided to ProcessDefinitionMediator.getByProcessModelId!`); } const processDefinitionRaw = await this.processDefinitionDatabaseAdapter.getByProcessModelId(processModelId); const processDefinition = await this.parseProcessDefinition(processDefinitionRaw); const filteredProcessModels = this.filterInaccessibleProcessModels(processDefinition.processes, identity); if (filteredProcessModels.length === 0) { throw new processcube_engine_sdk_1.ForbiddenError('Access denied.'); } processDefinition.processes = filteredProcessModels; this.applyFlagsToProcessDefinition(processDefinition, processDefinitionRaw); return processDefinition; } async deleteById(processDefinitionId, deleteAllRelatedData) { await this.processDefinitionDatabaseAdapter.flagAsDeletedByName(processDefinitionId); if (deleteAllRelatedData) { this.processDefinitionDatabaseAdapter.deleteByName(processDefinitionId); } } async setIsExecutableFlagForProcessModel(processModelId, isExecutable) { await this.processDefinitionDatabaseAdapter.setIsExecutableFlag(processModelId, isExecutable); } applyFlagsToProcessDefinition(definition, rawDefinition) { const flags = this.getFlagsForProcessModels(rawDefinition); const processModelIdsWithExecutableFlag = Object.keys(flags); for (const processModelId of processModelIdsWithExecutableFlag) { const processModel = definition.processes.find((process) => process.id === processModelId); processModel.isExecutable = flags[processModelId]?.executable || false; processModel.isSingleton = flags[processModelId]?.singleton || false; } } getFlagsForProcessModels(definition) { const flags = {}; definition.processModelAssociations.forEach((processModelAssociation) => { if (processModelAssociation.isExecutable != null && processModelAssociation.isExecutable !== undefined) { flags[processModelAssociation.processModelId] = { executable: processModelAssociation.isExecutable, singleton: false, }; } if (processModelAssociation.isSingleton) { flags[processModelAssociation.processModelId] = { executable: flags[processModelAssociation.processModelId]?.executable, singleton: true, }; } }); return flags; } async parseAndValidateDefinition(xml) { let parsedProcessDefinition; try { parsedProcessDefinition = await this.bpmnModelParser.parseXmlToObjectModel(xml); const processModel = parsedProcessDefinition.processes[0]; const processModelHasNoStartEvents = !processModel.flowNodes.some((flowNode) => flowNode.bpmnType === processcube_engine_sdk_1.BpmnType.startEvent); if (processModelHasNoStartEvents) { throw new processcube_engine_sdk_1.UnprocessableEntityError(`The ProcessModel \`${processModel.id}\` contained within the diagram \`${parsedProcessDefinition.id}\` has no StartEvents!`); } const processModelHasNoEndEvents = !processModel.flowNodes.some((flowNode) => flowNode.bpmnType === processcube_engine_sdk_1.BpmnType.endEvent); if (processModelHasNoEndEvents) { throw new processcube_engine_sdk_1.UnprocessableEntityError(`The ProcessModel \`${processModel.id}\` contained within the diagram \`${parsedProcessDefinition.id}\` has no EndEvents!`); } return parsedProcessDefinition; } catch (error) { this.logger.error('Error while parsing and validating definition', { err: error, xml: xml }); throw error; } } async parseProcessDefinition(definitionRaw) { const definitionFromCache = (0, lodash_clonedeep_1.default)(this.definitionsCache[definitionRaw.hash]); if (definitionFromCache) { return definitionFromCache; } const parsedDefinition = await this.bpmnModelParser.parseXmlToObjectModel(definitionRaw.xml); parsedDefinition.hash = definitionRaw.hash; parsedDefinition.raw = definitionRaw.xml; parsedDefinition.deployedAt = definitionRaw.createdAt; parsedDefinition.deployedByUserId = definitionRaw.createdBy; this.definitionsCache[definitionRaw.hash] = (0, lodash_clonedeep_1.default)(parsedDefinition); return parsedDefinition; } filterInaccessibleProcessDefinitions(definitions, identity) { const sanitizedList = []; for (const processDefinition of definitions) { const filteredProcessModels = this.filterInaccessibleProcessModels(processDefinition.processes, identity); if (filteredProcessModels.length === 0) { continue; } processDefinition.processes = filteredProcessModels; sanitizedList.push(processDefinition); } return sanitizedList; } filterInaccessibleProcessModels(processModels, identity) { const filteredProcessModels = []; for (const processModel of processModels) { const filteredProcessModel = this.filterInaccessibleProcessModelElements(identity, processModel); if (filteredProcessModel) { filteredProcessModels.push(filteredProcessModel); } } return filteredProcessModels; } filterInaccessibleProcessModelElements(identity, processModel) { const filteredProcessModel = (0, lodash_clonedeep_1.default)(processModel); const processModelHasNoLanes = !(processModel?.laneSet?.lanes?.length > 0); if (processModelHasNoLanes) { return filteredProcessModel; } filteredProcessModel.laneSet = this.filterOutInaccessibleLanes(filteredProcessModel.laneSet, identity); filteredProcessModel.flowNodes = this.getFlowNodesForLaneSet(filteredProcessModel.laneSet, processModel.flowNodes); const originalProcessModelHasStartEvents = processModel.flowNodes.some((flowNode) => flowNode.bpmnType === processcube_engine_sdk_1.BpmnType.startEvent); const userCannotAccessAnyStartEvents = !filteredProcessModel.flowNodes.some((flowNode) => flowNode.bpmnType === processcube_engine_sdk_1.BpmnType.startEvent); if (userCannotAccessAnyStartEvents && originalProcessModelHasStartEvents) { return undefined; } return filteredProcessModel; } filterOutInaccessibleLanes(laneSet, identity) { if (this.isUserAnAdminOrObserver(identity)) { return laneSet; } const filteredLaneSet = (0, lodash_clonedeep_1.default)(laneSet); filteredLaneSet.lanes = []; const checkIfUserHasLaneClaim = (laneName) => { try { if (!laneName) { return true; } this.iamService.ensureHasClaim(identity, laneName); return true; } catch (error) { return false; } }; for (const lane of laneSet.lanes) { const filteredLane = (0, lodash_clonedeep_1.default)(lane); const userCanNotAccessLane = !checkIfUserHasLaneClaim(lane.name); if (userCanNotAccessLane) { filteredLane.flowNodeReferences = []; delete filteredLane.childLaneSet; } const laneHasChildLanes = filteredLane.childLaneSet != undefined; if (laneHasChildLanes) { filteredLane.childLaneSet = this.filterOutInaccessibleLanes(filteredLane.childLaneSet, identity); } filteredLaneSet.lanes.push(filteredLane); } return filteredLaneSet; } getFlowNodesForLaneSet(laneSet, flowNodes) { const accessibleFlowNodes = []; for (const lane of laneSet.lanes) { const childLaneSetIsEmpty = !(lane?.childLaneSet?.lanes?.length > 0); if (!childLaneSetIsEmpty) { accessibleFlowNodes.push(...this.getFlowNodesForLaneSet(lane.childLaneSet, flowNodes)); } else { for (const flowNodeId of lane.flowNodeReferences) { const matchingFlowNode = flowNodes.find((flowNode) => flowNode.id === flowNodeId); if (matchingFlowNode) { accessibleFlowNodes.push(matchingFlowNode); } } } } return accessibleFlowNodes; } isUserAnAdminOrObserver(identity) { try { return this.iamService.checkIfUserIsSuperAdmin(identity) || this.iamService.checkIfUserIsObserver(identity); } catch (error) { return false; } } }; exports.ProcessDefinitionMediator = ProcessDefinitionMediator; exports.ProcessDefinitionMediator = ProcessDefinitionMediator = __decorate([ (0, inversify_1.injectable)(), __param(0, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.IamService)), __param(1, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.ProcessDefinitionDatabaseAdapter)), __metadata("design:paramtypes", [index_2.IamService, index_1.ProcessDefinitionDatabaseAdapter]) ], ProcessDefinitionMediator); //# sourceMappingURL=ProcessDefinitionMediator.js.map