@5minds/processcube_engine
Version:
The ProcessCube Engine. Stores and executes BPMNs.
357 lines • 21.1 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.FlowNodeInstanceServiceProxyConfiguration = exports.FlowNodeInstanceService = void 0;
const inversify_1 = require("inversify");
const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk");
const EventAggregatorSettings_1 = require("../../Contracts/InternalMessages/EventAggregatorSettings");
const IocRegistrations_1 = require("../../Contracts/IocRegistrations");
const index_1 = require("../../Core/index");
const Configurator_1 = __importDefault(require("../../Tools/Configurator"));
const index_2 = require("../../Tools/DatabaseAdaptersSequelize/index");
const EventAggregator_1 = __importDefault(require("../../Tools/EventAggregator"));
const index_3 = require("../../Tools/Iam/index");
const MonitoringManager_1 = require("../../Tools/MonitoringManager");
let FlowNodeInstanceService = class FlowNodeInstanceService {
coreAccess;
iamService;
identityService;
flowNodeInstanceAdapter;
logger;
userTaskAdapter;
config;
constructor(coreAccess, iamService, identityService, flowNodeInstanceAdapter, userTaskAdapter) {
this.coreAccess = coreAccess;
this.iamService = iamService;
this.identityService = identityService;
this.flowNodeInstanceAdapter = flowNodeInstanceAdapter;
this.logger = new processcube_engine_sdk_1.Logger('api:flow_node_instance_service');
this.userTaskAdapter = userTaskAdapter;
this.config = Configurator_1.default.application();
}
async query(identity, query, offset, limit, sortSettings, includeCount) {
if (!limit || limit <= 0) {
limit = this.config.defaultResponseLimit;
}
const isAdminOrObserver = this.iamService.checkIfUserIsSuperAdmin(identity) || this.iamService.checkIfUserIsObserver(identity);
if (isAdminOrObserver) {
return this.flowNodeInstanceAdapter.query(query, offset, limit, sortSettings, false, includeCount ?? true);
}
return this.enhanceAndExecuteQuery(identity, query, offset, limit, sortSettings, includeCount ?? true);
}
async finishUntypedTask(identity, taskInstanceId) {
this.logger.trace('Finish Untyped Task called', { flowNodeInstanceId: taskInstanceId });
this.logger.trace('Checking if Untyped Task exists', { flowNodeInstanceId: taskInstanceId });
const results = await this.flowNodeInstanceAdapter.query({
flowNodeInstanceId: taskInstanceId,
flowNodeType: processcube_engine_sdk_1.BpmnType.untypedTask,
state: processcube_engine_sdk_1.FlowNodeInstanceState.suspended,
});
if (results.flowNodeInstances.length === 0) {
throw new processcube_engine_sdk_1.NotFoundError(`UntypedTaskInstance \`${taskInstanceId}\` not found!`);
}
const flowNodeInstance = results.flowNodeInstances[0];
this.logger.trace('Checking if user is allowed to finish Untyped Task', { flowNodeInstanceId: taskInstanceId });
if (flowNodeInstance.flowNodeLane) {
this.ensureHasClaim(identity, flowNodeInstance.flowNodeLane);
}
this.logger.trace('Finishing Untyped Task', { flowNodeInstanceId: taskInstanceId });
await this.coreAccess.finishUntypedTask(identity, taskInstanceId);
this.logger.info('Finished Untyped Task', { flowNodeInstanceId: taskInstanceId });
}
async finishManualTask(identity, manualTaskInstanceId) {
this.logger.trace('Finish Manual Task called', { flowNodeInstanceId: manualTaskInstanceId });
this.logger.trace('Checking if Manual Task exists', { flowNodeInstanceId: manualTaskInstanceId });
const results = await this.flowNodeInstanceAdapter.query({
flowNodeInstanceId: manualTaskInstanceId,
flowNodeType: processcube_engine_sdk_1.BpmnType.manualTask,
state: processcube_engine_sdk_1.FlowNodeInstanceState.suspended,
});
if (results.flowNodeInstances.length === 0) {
throw new processcube_engine_sdk_1.NotFoundError(`ManualTask \`${manualTaskInstanceId}\` not found!`);
}
const flowNodeInstance = results.flowNodeInstances[0];
this.logger.trace('Checking if user is allowed to finish Manual Task', { flowNodeInstanceId: manualTaskInstanceId });
if (flowNodeInstance.flowNodeLane) {
this.ensureHasClaim(identity, flowNodeInstance.flowNodeLane);
}
this.logger.trace('Finishing Manual Task', { flowNodeInstanceId: manualTaskInstanceId });
await this.coreAccess.finishManualTask(identity, manualTaskInstanceId);
this.logger.info('Finished Manual Task', { flowNodeInstanceId: manualTaskInstanceId });
}
async finishUserTask(identity, userTaskInstanceId, userTaskResult = {}) {
this.logger.trace('Finish User Task called', { flowNodeInstanceId: userTaskInstanceId });
this.logger.trace('Checking if User Task exists', { flowNodeInstanceId: userTaskInstanceId });
const userTaskInstance = await this.loadSuspendedUserTaskInstance(userTaskInstanceId);
this.logger.trace('Checking if user is allowed to finish User Task', { flowNodeInstanceId: userTaskInstanceId });
await this.ensureUserCanAccessUserTask(identity, userTaskInstance);
this.logger.trace('Validating User Task result', { flowNodeInstanceId: userTaskInstanceId });
this.validateUserTaskResults(userTaskResult);
this.logger.trace('Finishing User Task', { flowNodeInstanceId: userTaskInstanceId });
await this.coreAccess.finishUserTask(identity, userTaskInstanceId, userTaskResult);
this.logger.info('Finished User Task', { flowNodeInstanceId: userTaskInstanceId });
}
async triggerMessageEvent(identity, messageName, options) {
const functionReporter = MonitoringManager_1.MonitoringManager.getNewFunctionReporter('FlowNodeInstanceService.triggerMessageEvent', {
messageName,
processInstanceIdSet: options?.processInstanceId != undefined,
messageChannelSet: options?.messageChannel != undefined,
});
this.ensureHasClaim(identity, processcube_engine_sdk_1.claims.canTriggerMessages);
this.logger.trace('Triggering Message Event', {
messageName: messageName,
processInstanceId: options?.processInstanceId,
});
await this.coreAccess.triggerMessageEvent(identity, messageName, options);
this.logger.info('Triggered Message Event', {
messageName: messageName,
processInstanceId: options?.processInstanceId,
});
functionReporter.finish();
}
async triggerSignalEvent(identity, signalName, options) {
const functionReporter = MonitoringManager_1.MonitoringManager.getNewFunctionReporter('FlowNodeInstanceService.triggerSignalEvent', {
signalName,
processInstanceIdSet: options?.processInstanceId != undefined,
signalChannelSet: options?.signalChannel != undefined,
});
this.ensureHasClaim(identity, processcube_engine_sdk_1.claims.canTriggerSignals);
this.logger.trace('Triggering Signal Event', {
signalName: signalName,
processInstanceId: options?.processInstanceId,
});
await this.coreAccess.triggerSignalEvent(identity, signalName, options);
this.logger.info('Triggered Signal Event', {
signalName: signalName,
processInstanceId: options?.processInstanceId,
});
functionReporter.finish();
}
async triggerTimerEvent(identity, flowNodeInstanceId) {
this.logger.trace('Checking if active Timer Event exists', { flowNodeInstanceId: flowNodeInstanceId });
const results = await this.flowNodeInstanceAdapter.query({
flowNodeInstanceId: flowNodeInstanceId,
flowNodeType: [processcube_engine_sdk_1.BpmnType.startEvent, processcube_engine_sdk_1.BpmnType.intermediateCatchEvent, processcube_engine_sdk_1.BpmnType.boundaryEvent],
state: [processcube_engine_sdk_1.FlowNodeInstanceState.running, processcube_engine_sdk_1.FlowNodeInstanceState.suspended],
eventType: processcube_engine_sdk_1.EventType.timerEvent,
});
if (results.flowNodeInstances.length === 0) {
throw new processcube_engine_sdk_1.NotFoundError(`Timer Event \`${flowNodeInstanceId}\` not found!`);
}
if (results.flowNodeInstances[0].flowNodeLane) {
this.ensureHasClaim(identity, results.flowNodeInstances[0].flowNodeLane);
}
this.logger.trace('Triggering Timer Event', {
flowNodeInstanceId: flowNodeInstanceId,
});
const event = EventAggregatorSettings_1.eventAggregatorSettings.messagePaths.triggerTimerEvent.replace(EventAggregatorSettings_1.eventAggregatorSettings.messageParams.flowNodeInstanceId, flowNodeInstanceId);
EventAggregator_1.default.publish(event);
this.logger.trace('Triggered Timer Event', {
flowNodeInstanceId: flowNodeInstanceId,
});
}
async reserveUserTaskInstance(identity, flowNodeInstanceId, actualOwnerId) {
this.logger.trace('Reserve User Task called', {
flowNodeInstanceId: flowNodeInstanceId,
actualOwnerId: actualOwnerId,
});
this.logger.trace('Checking if User Task exists', {
flowNodeInstanceId: flowNodeInstanceId,
actualOwnerId: actualOwnerId,
});
const userTaskInstance = await this.loadSuspendedUserTaskInstance(flowNodeInstanceId);
this.logger.trace('Checking if User Task is reservable by the requesting user', {
flowNodeInstanceId: flowNodeInstanceId,
actualOwnerId: actualOwnerId,
});
await this.ensureUserCanAccessUserTask(identity, userTaskInstance);
const requestingUserIsRegularUser = !this.iamService.checkIfUserIsSuperAdmin(identity);
if (requestingUserIsRegularUser && actualOwnerId != identity.userId) {
throw new processcube_engine_sdk_1.ForbiddenError('You cannot create UserTask reservations for other users.');
}
const actualOwnerIsNotAssigned = userTaskInstance.assignedUserIds &&
!userTaskInstance.assignedUserIds.some((userId) => userId && (userId === actualOwnerId || userId === identity.userId || userId === identity.userName || userId === identity.userEmail));
if (actualOwnerIsNotAssigned) {
throw new processcube_engine_sdk_1.ForbiddenError('You cannot create UserTask reservations for users who are not assigned.');
}
this.logger.trace(`Reserving User Task \`${flowNodeInstanceId}\` for user \`${actualOwnerId}\``, {
flowNodeInstanceId: flowNodeInstanceId,
actualOwnerId: actualOwnerId,
});
await this.userTaskAdapter.reserveUserTaskInstance(identity, flowNodeInstanceId, actualOwnerId);
await this.sendUserTaskReservedNotification(userTaskInstance);
this.logger.info(`Reserved User Task \`${flowNodeInstanceId}\` for user \`${actualOwnerId}\``, {
flowNodeInstanceId: flowNodeInstanceId,
actualOwnerId: actualOwnerId,
});
}
async cancelUserTaskInstanceReservation(identity, flowNodeInstanceId) {
this.logger.trace('Cancel User Task reservation called', { flowNodeInstanceId: flowNodeInstanceId });
this.logger.trace('Checking if User Task exists and is reservable by the requesting user', { flowNodeInstanceId: flowNodeInstanceId });
const userTaskInstance = await this.loadSuspendedUserTaskInstance(flowNodeInstanceId);
await this.ensureUserCanAccessUserTask(identity, userTaskInstance);
this.logger.trace('Cancelling Reservation for User Task', { flowNodeInstanceId: flowNodeInstanceId });
await this.userTaskAdapter.cancelUserTaskInstanceReservation(identity, flowNodeInstanceId);
await this.sendUserTaskReservationCanceledNotification(userTaskInstance);
this.logger.info('Cancelling Reservation for User Task', { flowNodeInstanceId: flowNodeInstanceId });
}
async enhanceAndExecuteQuery(identity, query, offset, limit, sortSettings, includeCount) {
const enhancedQuery = {
...query,
requestingUserEmail: identity.userEmail,
requestingUserId: identity.userId,
requestingUserName: identity.userName,
};
const allowedLanes = this.identityService.getAvailableLaneClaims(identity);
if (typeof query.flowNodeLane === 'string' && !allowedLanes.includes(query.flowNodeLane)) {
delete enhancedQuery.flowNodeLane;
return {
totalCount: 0,
flowNodeInstances: [],
};
}
if (Array.isArray(query.flowNodeLane)) {
const accessibleLanesFromQuery = query.flowNodeLane.filter((flowNodeLane) => allowedLanes.includes(flowNodeLane));
if (accessibleLanesFromQuery.length === 0) {
return {
totalCount: 0,
flowNodeInstances: [],
};
}
enhancedQuery.flowNodeLane = accessibleLanesFromQuery;
}
else {
enhancedQuery.flowNodeLane = query.flowNodeLane !== undefined ? query.flowNodeLane : allowedLanes;
}
return this.flowNodeInstanceAdapter.query(enhancedQuery, offset, limit, sortSettings, false, includeCount);
}
async loadSuspendedUserTaskInstance(flowNodeInstanceId) {
const query = {
flowNodeInstanceId: flowNodeInstanceId,
flowNodeType: processcube_engine_sdk_1.BpmnType.userTask,
state: processcube_engine_sdk_1.FlowNodeInstanceState.suspended,
};
const result = await this.flowNodeInstanceAdapter.query(query);
const userTaskInstance = result.flowNodeInstances[0];
if (!userTaskInstance) {
throw new processcube_engine_sdk_1.NotFoundError(`UserTask instance with id \`${flowNodeInstanceId}\` not found.`);
}
return userTaskInstance;
}
async ensureUserCanAccessUserTask(identity, userTaskInstance) {
if (userTaskInstance.flowNodeLane) {
this.ensureHasClaim(identity, userTaskInstance.flowNodeLane);
}
const userTaskIsAssignedForOtherUsers = await this.checkIfTaskIsAssignedToOtherUsers(identity, userTaskInstance);
if (userTaskIsAssignedForOtherUsers) {
throw new processcube_engine_sdk_1.NotFoundError(`UserTask \`${userTaskInstance.flowNodeInstanceId}\` not found!`);
}
const userTaskIsReservedForAnotherUser = await this.checkIfTaskIsReservedForAnotherUser(identity, userTaskInstance);
if (userTaskIsReservedForAnotherUser) {
const userTaskIsLockedError = new processcube_engine_sdk_1.ForbiddenError('The UserTask is reserved for another user.');
userTaskIsLockedError.additionalInformation = {
userTask: userTaskInstance,
requestingUserId: identity.userId,
};
throw userTaskIsLockedError;
}
}
async sendUserTaskReservedNotification(userTaskInstance) {
const notificationPayload = {
correlationId: userTaskInstance.correlationId,
processDefinitionId: userTaskInstance.processDefinitionId,
processModelId: userTaskInstance.processModelId,
embeddedProcessModelId: userTaskInstance.embeddedProcessModelId,
processInstanceId: userTaskInstance.processInstanceId,
parentProcessInstanceId: userTaskInstance.parentProcessInstanceId,
flowNodeId: userTaskInstance.flowNodeId,
flowNodeName: userTaskInstance.flowNodeName,
flowNodeInstanceId: userTaskInstance.flowNodeInstanceId,
ownerId: userTaskInstance.ownerId,
currentToken: userTaskInstance.startToken ?? {},
};
EventAggregator_1.default.publish(EventAggregatorSettings_1.eventAggregatorSettings.messagePaths.userTaskReserved, notificationPayload);
}
async sendUserTaskReservationCanceledNotification(userTaskInstance) {
const notificationPayload = {
correlationId: userTaskInstance.correlationId,
processDefinitionId: userTaskInstance.processDefinitionId,
processModelId: userTaskInstance.processModelId,
embeddedProcessModelId: userTaskInstance.embeddedProcessModelId,
processInstanceId: userTaskInstance.processInstanceId,
parentProcessInstanceId: userTaskInstance.parentProcessInstanceId,
flowNodeId: userTaskInstance.flowNodeId,
flowNodeName: userTaskInstance.flowNodeName,
flowNodeInstanceId: userTaskInstance.flowNodeInstanceId,
ownerId: userTaskInstance.ownerId,
currentToken: userTaskInstance.startToken ?? {},
};
EventAggregator_1.default.publish(EventAggregatorSettings_1.eventAggregatorSettings.messagePaths.userTaskReservationCanceled, notificationPayload);
}
async checkIfTaskIsAssignedToOtherUsers(identity, userTaskInstance) {
const isSuperAdmin = this.iamService.checkIfUserIsSuperAdmin(identity);
if (isSuperAdmin) {
return false;
}
if (!userTaskInstance.assignedUserIds) {
return false;
}
const userTaskIsAssignedToOtherUsers = !userTaskInstance.assignedUserIds.some((userId) => userId && (userId === identity.userId || userId === identity.userName || userId === identity.userEmail));
return userTaskIsAssignedToOtherUsers;
}
async checkIfTaskIsReservedForAnotherUser(identity, userTaskInstance) {
if (userTaskInstance.flowNodeType !== processcube_engine_sdk_1.BpmnType.userTask) {
return false;
}
const requestingUserIsRegularUser = !this.iamService.checkIfUserIsSuperAdmin(identity);
const userTaskIsReservedByAnotherUser = userTaskInstance.actualOwnerId && userTaskInstance.actualOwnerId != identity.userId;
return userTaskIsReservedByAnotherUser && requestingUserIsRegularUser;
}
ensureHasClaim(identity, claimName) {
const isSuperAdmin = this.iamService.checkIfUserIsSuperAdmin(identity);
if (isSuperAdmin) {
return;
}
this.iamService.ensureHasClaim(identity, claimName);
}
validateUserTaskResults(result) {
const resultSetIsNotAnObject = typeof result !== 'object';
if (resultSetIsNotAnObject) {
throw new processcube_engine_sdk_1.BadRequestError("The UserTask's result set is not an object.");
}
}
};
exports.FlowNodeInstanceService = FlowNodeInstanceService;
exports.FlowNodeInstanceService = FlowNodeInstanceService = __decorate([
(0, inversify_1.injectable)(),
__param(0, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.core.services.CoreAccess)),
__param(1, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.IamService)),
__param(2, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.IdentityService)),
__param(3, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.FlowNodeInstanceDatabaseAdapter)),
__param(4, (0, inversify_1.inject)(IocRegistrations_1.IocRegistrationKeys.internal.UserTaskInstanceDatabaseAdapter)),
__metadata("design:paramtypes", [index_1.CoreAccessService,
index_3.IamService,
index_3.IdentityService,
index_2.FlowNodeInstanceDatabaseAdapter,
index_2.UserTaskInstanceDatabaseAdapter])
], FlowNodeInstanceService);
exports.FlowNodeInstanceServiceProxyConfiguration = {
proxyKey: IocRegistrations_1.IocRegistrationKeys.api.services.FlowNodeInstanceServiceProxy,
targetKey: IocRegistrations_1.IocRegistrationKeys.api.services.FlowNodeInstanceService,
target: FlowNodeInstanceService,
};
//# sourceMappingURL=FlowNodeInstanceService.js.map