UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

357 lines • 21.1 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.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