@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
298 lines • 16.3 kB
JavaScript
"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