@aarconada/urserver
Version:
Basic Server definitions to develope REST API with a node + express Server
1,065 lines (1,041 loc) • 47.2 kB
JavaScript
/**
* 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;