UNPKG

@aarconada/urserver

Version:

Basic Server definitions to develope REST API with a node + express Server

1,065 lines (1,041 loc) 47.2 kB
/** * Created by ubuntu on 8/11/18. */ 'use strict'; const server = require('./server')(); const _ = require('lodash'); const promise = require('bluebird'); const definedWorkflows = []; class workflowedge { constructor({id, name, fromNode, toNode, canTransitCallback, description, relatedEndpoint}) { this.id = id; this.name = name; this.description = description; this.fromNode = fromNode; this.toNode = toNode; this.canTransitCallback = canTransitCallback ? canTransitCallback : this.defaultCanTransitCallback; this.relatedEndpoint = relatedEndpoint; } defaultCanTransitCallback(workflowInstance, transaction, req) { return new promise((resolve, reject) => { server.debug('Checking if workflow ' + workflowInstance.parentWorkflow.name + ' with id ' + workflowInstance.id + ' in node ' + this.fromNode.name + ' can transit to node ' + this.toNode.name); resolve(true); }); } getInfo(full) { return { id: this.id, name: this.name, description: this.description, fromNode: full === true ? this.fromNode.getInfo(false) : this.fromNode.id, toNode: full === true ? this.toNode.getInfo(false) : this.toNode.id, relatedEndpoint: this.relatedEndpoint } } } class workflownode { constructor({id, name, description, onTransitToCallback, onNodeCallback, onTransitFromCallback, parent, initialNode, endNode}) { this.id = id; this.name = name; this.description = description; this.parent = parent; this.initialNode = initialNode; this.endNode = endNode; this.onTransitToCallback = onTransitToCallback ? onTransitToCallback : this.defaultOnTransitToCallback; this.onNodeCallback = onNodeCallback ? onNodeCallback : this.defaultOnNodeCallback; this.onTransitFromCallback = onTransitFromCallback ? onTransitFromCallback : this.defaultOnTransitFromCallback; this.edges = []; } defaultOnTransitToCallback(workflowInstance, transaction, req) { return new promise((resolve, reject) => { server.debug('Workflow ' + this.parent.name + ' with id ' + workflowInstance.id + ' transiting to node ' + this.name + ' (' + this.id + ')'); resolve(); }); } defaultOnTransitFromCallback(workflowInstance, transaction, req) { return new promise((resolve, reject) => { server.debug('Workflow ' + this.parent.name + ' with id ' + workflowInstance.id + ' transiting from node ' + this.name + ' (' + this.id + ')'); resolve(); }); } defaultOnNodeCallback(workflowInstance, transaction, req) { return new promise((resolve, reject) => { server.debug('Workflow ' + this.parent.name + ' with id ' + workflowInstance.id + ' on node ' + this.name + ' (' + this.id + ')'); resolve(); }); } addTransitionTo({id, name, toNode, canTransitCallback, description, relatedEndpoint}) { if(!this.parent.existsEdge(this, toNode)) { const newEdge = new workflowedge({id: id, name: name, fromNode: this, toNode: toNode, canTransitCallback: canTransitCallback, description: description, relatedEndpoint: relatedEndpoint}); this.edges.push(newEdge); return newEdge; } else { return null; } } addTransitionFrom({id, name, fromNode, canTransitCallback, description, relatedEndpoint}) { if(!this.parent.existsEdge(fromNode, this)) { const newEdge = new workflowedge({id: id, name: name, fromNode: fromNode, toNode: this, canTransitCallback: canTransitCallback, description: description, relatedEndpoint: relatedEndpoint}); this.edges.push(newEdge); return newEdge; } else { return null; } } hasEdge(toNode) { return this.edges.filter(currentEdge => currentEdge.toNode === toNode).length > 0; } getEdge(toNode) { if(this.hasEdge(toNode)) return this.edges.find(currentEdge => currentEdge.toNode === toNode); else return null; } getInfo(full) { var edgesInfo = []; this.edges.forEach(currentEdge => { edgesInfo.push(currentEdge.getInfo(false)); }); return { id: this.id, name: this.name, description: this.description, initialNode: this.initialNode, endNode: this.endNode, edges: edgesInfo } } } class workflowtransition{ constructor({id, workflowInstance, fromNode, toNode, moment, who}) { this.id = id || null; this.fromNode = fromNode; this.toNode = toNode; this.moment = moment || new Date(); this.workflowInstance = workflowInstance; this.who = who || null; } persist(transaction, req) { return new promise((resolve, reject) => { if (this.workflowInstance.parentWorkflow.persistOnDatabase === true) { const transitionDatabaseModelValues = { fromNodeId: this.fromNode.id, toNodeId: this.toNode.id, relatedWorkflowId: this.workflowInstance.id, who: this.who, moment: this.moment }; server.authentication.setAuthenticatedUserId(req, transitionDatabaseModelValues); if(this.id === null) { this.workflowInstance.parentWorkflow.transitionDatabaseModel.create(transitionDatabaseModelValues, { transaction: transaction || null }).then(persistedTransitionInstance => { if (persistedTransitionInstance === null) { server.debug('The transition cant be persisted'); reject(server.defaultResponses.workflow_transition_cant_be_persisted); return; } this.id = persistedTransitionInstance.id; resolve(persistedTransitionInstance); }).catch(err => { server.debug('Error during transition persist', err); reject(err); return; }); } else { this.workflowInstance.parentWorkflow.transitionDatabaseModel.update(transitionDatabaseModelValues, { where: {id: this.id}, transaction: transaction || null }).then(persistedTransitionInstance => { if (persistedTransitionInstance === null) { server.debug('The transition cant be persisted'); reject(server.defaultResponses.workflow_transition_cant_be_persisted); return; } resolve(persistedTransitionInstance); }).catch(err => { server.debug('Error during wrokflow instance persist', err); reject(err); return; }); } } }); } getInfo(full) { return { id: this.id, fromNode: full === true ? this.fromNode.getInfo(false) : this.fromNode.id, toNode: full === true ? this.toNode.getInfo(false) : this.toNode.id, moment: this.moment, workflowinstance: full === true ? this.workflowInstance.getInfo() : this.workflowInstance.id, who: this.who } } } class workflowstate{ constructor({id, workflowInstance, node, who, startMoment, endMoment}) { this.id = id || null; this.node = node; this.who = who || null; this.startMoment = startMoment; this.workflowInstance = workflowInstance; this.endMoment = endMoment || null; } persist(transaction, req, statePreffix) { return new promise((resolve, reject) => { if (this.workflowInstance.parentWorkflow.persistOnDatabase === true) { const stateDatabaseModelValues = { nodeId: this.node.id, naodeName: this.node.name, relatedWorkflowId: this.workflowInstance.id, who: this.who, startMoment: this.startMoment, endMoment: this.endMoment }; server.authentication.setAuthenticatedUserId(req, stateDatabaseModelValues, statePreffix); if(this.id === null) { this.workflowInstance.parentWorkflow.stateDatabaseModel.create(stateDatabaseModelValues, { transaction: transaction || null }).then(persistedStateInstance => { if (persistedStateInstance === null) { server.debug('The state cant be persisted'); reject(server.defaultResponses.workflow_state_cant_be_persisted); return; } this.id = persistedStateInstance.id; resolve(persistedStateInstance); }).catch(err => { server.debug('Error during state persist', err); reject(err); return; }); } else { this.workflowInstance.parentWorkflow.stateDatabaseModel.update(stateDatabaseModelValues, { where: {id: this.id}, transaction: transaction || null }).then(persistedStateInstance => { if (persistedStateInstance === null) { server.debug('The state cant be persisted'); reject(server.defaultResponses.workflow_state_cant_be_persisted); return; } resolve(persistedStateInstance); }).catch(err => { server.debug('Error during state persist', err); reject(err); return; }); } } }); } getInfo(full) { return { id: this.id, node: full === true ? this.node.getInfo(false) : this.node.id, nodeName: this.node.name, who: this.who, workflowinstance: full === true ? this.workflowInstance.getInfo() : this.workflowInstance.id, startMoment: this.startMoment, endMoment: this.endMoment } } } class workflowinstance{ constructor({id, parentWorkflow, currentNode, transitions, states, currentState, startMoment, endMoment, relatedModelId, who}) { this.id = id; this.parentWorkflow = parentWorkflow; this.currentNode = currentNode || parentWorkflow.initialNode; this.transitions = transitions || []; this.states = states || []; this.relatedModelId = relatedModelId || null; this.who = who || null; this.startMoment = startMoment || new Date(); this.endMoment = endMoment || null; this.currentState = currentState || null; } get finished() { return this.currentNode.endNode; } availableTransitions() { return this.currentNode.edges; } transit(toNode, who, transaction, req) { return new promise((resolve, reject) => { if (this.finished) { server.debug('The workflow has been finished'); reject(server.defaultResponses.workflow_instance_finished); return; } if (this.currentNode.hasEdge(toNode)) { const transitionEdge = this.currentNode.getEdge(toNode); if (transitionEdge !== null) { transitionEdge.canTransitCallback(this, transaction, req) .then(result => { if(result === false) { reject(server.defaultResponses.workflow_cant_transit_to_node); return; } this.currentNode.onTransitFromCallback(this, transaction, req) .then(result => { this.currentNode = transitionEdge.toNode; this.currentNode.onTransitToCallback(this, transaction, req) .then(result => { const newTransition = new workflowtransition({ workflowInstance: this, fromNode: transitionEdge.fromNode, toNode: transitionEdge.toNode, who: who }); newTransition.persist(transaction, req) .then(persistedTransition => { this.transitions.push(newTransition); this.currentNode.onNodeCallback(this, transaction, req) .then(result => { if (this.finished) { this.endMoment = new Date(); } this.updateState(transaction, req) .then(newState => { this.persist(transaction, req) .then(persistedWorkflow => { resolve(newTransition); }) .catch(err => { reject(err); }) }) .catch(err => { reject(err); }); }) .catch(err => { reject(err); }); }) .catch(err => { server.debug('Error on transition persist ', err); reject(err); }); }) .catch(err => { reject(err); }); }) .catch(err => { reject(err); }); }) .catch(err => { reject(err); }); } else { server.debug('The workflow cant transit to node ' + toNode.name); reject(server.defaultResponses.workflow_cant_transit_to_node); } } else { server.debug('The workflow has no edge to node ' + toNode.name); reject(server.defaultResponses.workflow_does_not_exists_edge_to_node); } }); } updateState(transaction, req) { return new promise((resolve, reject) => { if (this.currentState === null) { server.debug('The instance has no state'); this.currentState = new workflowstate({ workflowInstance: this, node: this.currentNode, who: this.who, startMoment: this.startMoment }); this.currentState.persist(transaction, req, "Start") .then(persistedState => { if(persistedState === null) { reject(server.defaultResponses.workflow_state_cant_be_persisted); return; } this.states.push(this.currentState); resolve(persistedState); }) .catch(err => { reject(err); }); } else if (this.currentState.node !== this.currentNode) { server.debug('Finishing current state'); this.currentState.endMoment = new Date(); this.currentState.persist(transaction, req, "End") .then(persistedEndedState => { if (persistedEndedState === null) { reject(server.defaultResponses.workflow_state_cant_be_persisted); return; } if(this.currentNode.endNode) { resolve(this.currentState); return; } else { server.debug('Starting new state'); this.currentState = new workflowstate({ workflowInstance: this, node: this.currentNode, who: this.who, startMoment: new Date() }); this.currentState.persist(transaction, req, "Start") .then(persistedStartedState => { if (persistedStartedState === null) { reject(server.defaultResponses.workflow_state_cant_be_persisted); return; } this.states.push(this.currentState); resolve(persistedStartedState); }) .catch(err => { reject(err); }); } }) .catch(err => { reject(err); }); } else { resolve(this.currentState); } }); } transitByNodeId(nodeId, who, transaction, req) { return new promise((resolve, reject) => { const toNode = this.parentWorkflow.getNodeById(nodeId) if (toNode !== null) { this.transit(toNode, who, transaction, req) .then(result => { resolve(result); }) .catch(err => { reject(err); }) } else { reject(server.defaultResponses.workflow_unknow_node); } }); } transitByNodeName(nodeName, who, transaction, req) { return new promise((resolve, reject) => { const toNode = this.parentWorkflow.getNodeByName(nodeName) if (toNode !== null) { this.transit(toNode, who, transaction, req) .then(result => { resolve(result); }) .catch(err => { reject(err); }) } else { reject(server.defaultResponses.workflow_unknow_node); } }); } loadRelatedModelInstance(transaction, req) { return new promise((resolve, reject) => { if (this.parentWorkflow.relatedModel === null) { server.debug('This workflow has no related model'); reject(server.defaultResponses.workflow_no_related_model); return; } if(this.relatedModelId === null) { server.debug('This workflow has no related model id'); reject(server.defaultResponses.workflow_no_related_model_id); return; } this.parentWorkflow.relatedModel .findByPk(this.relatedModelId, {transaction: transaction || null}) .then(relatedModelInstance => { if(relatedModelInstance === null) { server.debug('The related model instance does not exists'); reject(server.defaultResponses.workflow_instance_does_not_exists); return; } resolve(relatedModelInstance); }) .catch(err => { server.debug('Error during related model instance loading', err); reject(err); }); }); } persist(transaction, req) { return new promise((resolve, reject) => { if (this.parentWorkflow.persistOnDatabase === true) { const workflowDatabaseModelValues = { parentWorkflowId: this.parentWorkflow.id, currentNodeId: this.currentNode.id, relatedModelId: this.relatedModelId, who: this.who, startMoment: this.startMoment, endMoment: this.endMoment, finished: this.finished }; server.authentication.setAuthenticatedUserId(req, workflowDatabaseModelValues); if(this.id === null) { this.parentWorkflow.workflowDatabaseModel.create(workflowDatabaseModelValues, { transaction: transaction || null }).then(persistedWorkflowInstance => { if (persistedWorkflowInstance === null) { server.debug('The workflow cant be persisted'); reject(server.defaultResponses.workflow_instance_cant_be_persisted); return; } this.id = persistedWorkflowInstance.id; resolve(persistedWorkflowInstance); }).catch(err => { server.debug('Error during wrokflow instance persist', err); reject(err); return; }) } else { this.parentWorkflow.workflowDatabaseModel.update(workflowDatabaseModelValues, { where: {id: this.id}, transaction: transaction || null }).then(persistedWorkflowInstance => { if (persistedWorkflowInstance === null) { server.debug('The workflow cant be persisted'); reject(server.defaultResponses.workflow_instance_cant_be_persisted); return; } resolve(persistedWorkflowInstance); }).catch(err => { server.debug('Error during wrokflow instance persist', err); reject(err); return; }) } } }); } getInfo(full) { var transitionsInfo = []; this.transitions.forEach(currentTransition => { transitionsInfo.push(currentTransition.getInfo(false)) }); var statesInfo = []; this.states.forEach(currentState => { statesInfo.push(currentState.getInfo(false)) }); return { id: this.id, parentWorkflow: full === true ? this.parentWorkflow.getInfo(false) : this.parentWorkflow.id, currentNode: this.currentNode.getInfo(false), startMoment: this.startMoment, endMoment: this.endMoment, relatedModelId: this.relatedModelId, states: statesInfo, transitions: transitionsInfo, finished: this.finished, currentState: this.finished ? null : this.currentState.getInfo(false) } } } class workflow { constructor({id, name, description, relatedModel, parent, persistOnDatabase}) { this.id = id; this.name = name; this.description = description; this.relatedModel = relatedModel || null; this.initialNode = null; this.parent = parent; this.endNodes = []; this.nodes = []; this.edges = []; this.instances = []; this.persistOnDatabase = persistOnDatabase || false; this.checkDatabaseModel(); } hasInstanceId(workflowId) { return this.instances.filter(currentInstance => currentInstance.id === workflowId).length > 0; } getInstanceById(workflowId) { if(this.hasInstanceId(workflowId)) { return this.instances.filter(currentInstance => currentInstance.id === workflowId)[0]; } } checkDatabaseModel() { if (this.persistOnDatabase === true) { this.workflowDatabaseModel = server.sequelize.define( { modelname: this.name + "Instance", schema: { parentWorkflowId: {type: server.sequelize.api.INTEGER, allowNull: false}, currentNodeId: {type: server.sequelize.api.INTEGER, allowNull: false}, who: {type: server.sequelize.api.INTEGER, allowNull: true}, startMoment: {type: server.sequelize.api.DATE, allowNull: false}, endMoment: {type: server.sequelize.api.DATE, allowNull: true}, finished: {type: server.sequelize.api.BOOLEAN, allowNull: false} }, configuration: { version: false, paranoid: false, timestamps: false }, POST: { single: { enabled: false }, all: { enabled: false } }, PUT: { single: { enabled: false } , all: { enabled: false } }, DELETE: { single: { enabled: false } , all: { enabled: false } }, GET: { single: { enabled: false } , all: { enabled: false } } } ); server.authentication.modelBelongsToManyAuthenticationMethods(this.workflowDatabaseModel); this.transitionDatabaseModel = server.sequelize.define( { modelname: this.name + "Transition", schema: { fromNodeId: {type: server.sequelize.api.INTEGER, allowNull: false}, toNodeId: {type: server.sequelize.api.INTEGER, allowNull: false}, who: {type: server.sequelize.api.INTEGER, allowNull: true}, moment: {type: server.sequelize.api.DATE, allowNull: false} }, configuration: { version: false, paranoid: false, timestamps: false }, POST: { single: { enabled: false }, all: { enabled: false } }, PUT: { single: { enabled: false } , all: { enabled: false } }, DELETE: { single: { enabled: false } , all: { enabled: false } }, GET: { single: { enabled: false } , all: { enabled: false } } } ); server.authentication.modelBelongsToManyAuthenticationMethods(this.transitionDatabaseModel); this.transitionDatabaseModel.belongsTo(this.workflowDatabaseModel, {foreignKey: 'relatedWorkflowId', as: 'RelatedWorkflow'}); this.workflowDatabaseModel.hasMany(this.transitionDatabaseModel, {foreignKey: 'relatedWorkflowId', as: 'RelatedTransitions'}); this.stateDatabaseModel = server.sequelize.define( { modelname: this.name + "State", schema: { nodeId: {type: server.sequelize.api.INTEGER, allowNull: false}, who: {type: server.sequelize.api.INTEGER, allowNull: true}, startMoment: {type: server.sequelize.api.DATE, allowNull: false}, endMoment: {type: server.sequelize.api.DATE, allowNull: true}, }, configuration: { version: false, paranoid: false, timestamps: false }, POST: { single: { enabled: false }, all: { enabled: false } }, PUT: { single: { enabled: false } , all: { enabled: false } }, DELETE: { single: { enabled: false } , all: { enabled: false } }, GET: { single: { enabled: false } , all: { enabled: false } } } ); server.authentication.modelBelongsToManyAuthenticationMethods(this.stateDatabaseModel, 'Start'); server.authentication.modelBelongsToManyAuthenticationMethods(this.stateDatabaseModel, 'End'); this.stateDatabaseModel.belongsTo(this.workflowDatabaseModel, {foreignKey: 'relatedWorkflowId', as: 'RelatedWorkflow'}); this.workflowDatabaseModel.hasMany(this.stateDatabaseModel, {foreignKey: 'relatedWorkflowId', as: 'RelatedStates'}); if (!_.isNull(this.relatedModel)) { this.workflowDatabaseModel.belongsTo(this.relatedModel, {foreignKey: 'relatedModelId', as: 'RelatedModel'}); this.relatedModel.hasOne(this.workflowDatabaseModel, {foreignKey: 'relatedModelId', as: 'RelatedWorkflow'}) } } } existsEdge(fromNode, toNode) { return this.edges.filter(currentEdge => currentEdge.fromNode === fromNode && currentEdge.toNode === toNode).length > 0; } existsNode(id) { return this.nodes.filter(currentNode => currentNode.id === id).length > 0; } existsNodeName(name) { return this.nodes.filter(currentNode => currentNode.name === name).length > 0; } getNodeById(id) { if(this.existsNode(id)) { return this.nodes.filter(currentNode => currentNode.id === id)[0]; } else { return null; } } getNodeByName(name) { if(this.existsNodeName(name)) { return this.nodes.filter(currentNode => currentNode.name === name)[0]; } else { return null; } } addInitialNode({id, name, description, onTransitToCallback, onTransitFromCallback}) { if(!this.existsNode(id)) { const newNode = new workflownode({ id: (id || (this.nodes.length + 1)), name: (name || ('node_' + this.nodes.length)), description: description, onTransitToCallback: onTransitToCallback, onTransitFromCallback: onTransitFromCallback, parent: this, initialNode: true, endNode: false }); if(newNode !== null) { if(this.initialNode !== null) { this.initialNode.initialNode = false; } this.initialNode = newNode; this.nodes.push(newNode); return newNode; } else { return null; } } } addMiddleNode({id, name, description, onTransitToCallback, onTransitFromCallback}) { if(!this.existsNode(id, name)) { const newNode = new workflownode({ id: (id || (this.nodes.length + 1)), name: (name || ('node_' + this.nodes.length)), description: description, onTransitToCallback: onTransitToCallback, onTransitFromCallback: onTransitFromCallback, parent: this, initialNode:false, endNode: false }); if(newNode !== null) { this.nodes.push(newNode); return newNode; } else { return null; } } } addEndNode({id, name, description, onTransitToCallback, onTransitFromCallback}) { if(!this.existsNode(id, name)) { const newNode = new workflownode({ id: (id || (this.nodes.length + 1)), name: (name || ('node_' + this.nodes.length)), description: description, onTransitToCallback: onTransitToCallback, onTransitFromCallback: onTransitFromCallback, parent: this, initialNode: false, endNode: true}); if(newNode !== null) { this.endNodes.push(newNode); this.nodes.push(newNode); return newNode; } else { return null; } } } addEdge({id, name, fromNode, toNode, canTransitCallback, description, relatedEndpoint}) { const newEdge = fromNode.addTransitionTo({ id: (id || (this.edges.length + 1)), name: (name || ('edge_' + this.edges.length)), toNode: toNode, canTransitCallback: canTransitCallback, description: description, relatedEndpoint: relatedEndpoint }); if(newEdge !== null) { this.edges.push(newEdge); return newEdge; } else { return null; } } createInstance({relatedModelId, who, transaction, req}) { return new promise((resolve, reject) => { const newInstance = new workflowinstance({ id: this.persistOnDatabase ? null : (this.instances.length + 1), parentWorkflow: this, relatedModelId: relatedModelId, who: who }); newInstance.persist(transaction, req) .then(persistedInstance => { newInstance.updateState(transaction, req) .then(persistedState => { this.instances.push(newInstance); newInstance.currentNode.onNodeCallback(this, transaction, req) .then(result => { resolve(newInstance); }) .catch(err => { reject(err); }); }) .catch(err => { server.debug(err); reject(err); return; }); }) .catch(err => { server.debug(err); reject(err); return; }); }); } createInstanceForModelInstance({relatedModelInstance, who, transaction , req}) { return new promise((resolve, reject) => { const newInstance = new workflowinstance({ id: this.persistOnDatabase ? null : (this.instances.length + 1), parentWorkflow: this, relatedModelId: relatedModelInstance.id, who: who }); newInstance.persist(transaction, req) .then(persistedInstance => { newInstance.updateState(transaction, req) .then(persistedState => { relatedModelInstance.setRelatedWorkflow(persistedInstance, {transaction: transaction}) .then(updatedModelInstance => { this.instances.push(newInstance); newInstance.currentNode.onNodeCallback(this, transaction, req) .then(result => { resolve(newInstance); }) .catch(err => { reject(err); }); }) .catch(err => { reject(err); }) }) .catch(err => { server.debug(err); reject(err); return; }); }) .catch(err => { server.debug(err); reject(err); return; }); }); } loadWorkflowByModelInstance(relatedModelInstance, transaction) { return new promise((resolve, reject) => { relatedModelInstance.getRelatedWorkflow({ transaction: transaction || null }) .then(workflowModel => { if(_.isNull(workflowModel)) { reject(server.defaultResponses.workflow_entity_without_instance); return; } if(this.hasInstanceId(workflowModel.id)) { resolve(this.getInstanceById(workflowModel.id)); } else { workflowModel.getRelatedTransitions({transaction: transaction || null}) .then(transitions => { const workflowModelInstance = new workflowinstance({ id: workflowModel.id, parentWorkflow: this, currentNode: this.getNodeById(workflowModel.currentNodeId), transitions: [], states: [], currentState: null, startMoment: workflowModel.startMoment, endMoment: workflowModel.endMoment, relatedModelId: workflowModel.relatedModelId, who: workflowModel.who, loading: true }); transitions.forEach(currentTransition => { const newTransition = new workflowtransition({ id: currentTransition.id, fromNode: this.getNodeById(currentTransition.fromNodeId), toNode: this.getNodeById(currentTransition.toNodeId), moment: currentTransition.moment, workflowInstance: workflowModelInstance, who: currentTransition.who }); workflowModelInstance.transitions.push(newTransition); }); workflowModel.getRelatedStates({transaction: transaction || null}) .then(states => { states.forEach(currentState => { const newState = new workflowstate({ id: currentState.id, node: this.getNodeById(currentState.nodeId), startMoment: currentState.startMoment, endMoment: currentState.endMoment, workflowInstance: workflowModelInstance, who: currentState.who }); server.debug(newState); workflowModelInstance.states.push(newState); if(currentState.endMoment === null) { workflowModelInstance.currentState = newState; } }); resolve(workflowModelInstance); }) .catch(err => { reject(err); return; }) }) .catch(err => { reject(err); return; }) } }) .catch(err => { reject(err); return; }) }); } loadWorkflowByModelId(relatedModelId, transaction) { return new promise((resolve, reject) => { if(!_.isUndefined(this.relatedModel) && !_.isNull(this.relatedModel)) { this.relatedModel.findByPk(relatedModelId, {transaction: transaction || null}) .then(relatedModelInstance => { if(relatedModelInstance === null) { reject(server.defaultResponses.entity_element_not_found); return; } this.loadWorkflowByModelInstance(relatedModelInstance) .then(relatedWorkflow => { resolve(relatedWorkflow); }) .catch(err => { reject(err); return; }) }) } else { reject(server.defaultResponses.workflow_no_related_model); } }); } getInfo(full) { return { id: this.id, name: this.name, relatedModel: this.relatedModel.name, initialNode: this.initialNode.getInfo(false), persistOnDatabase: this.persistOnDatabase } } } module.exports.define = function({id, name, description, relatedModel, persistOnDatabase}) { if (!_.isUndefined(id) && !_.isUndefined(name) ) { var newWorkFlow = new workflow({ id: (id || (definedWorkflows.length + 1)), name: (name || ('workflow_' + definedWorkflows.length)), description: description, relatedModel: relatedModel, persistOnDatabase: persistOnDatabase }); definedWorkflows[name] = newWorkFlow; return newWorkFlow; } else { return null; } }; module.exports.getWorkFlowById = function(id) { return definedWorkflows.find(currentWorkFlow => currentWorkFlow.id === id); }; module.exports.gettWorkFlowByName = function(name) { return definedWorkflows[name]; }; module.exports.definedWorkflows = definedWorkflows;