Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use subscriber promises #32

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 60 additions & 134 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,151 +4,62 @@ This module contains a workflow model representation and its related services :
- Backend services
- Frontend services

## Client-side usage
## Client Topics

### Topic Subscriptions

#### wfm:workflows:create

##### Description

Creating a new Workflow

##### Example


```javascript
var parameters = {
workflowToCreate: {
//A Valid JSON Object
},
//Optional topic unique identifier.
topicUid: "uniquetopicid"
}

mediator.publish("wfm:workflows:create", parameters);
```

#### wfm:workflows:read

##### Description

Read a single Workflow

##### Example


```javascript
var parameters = {
id: "workflowId",
//Optional topic unique identifier.
topicUid: "uniquetopicid"
}

mediator.publish("wfm:workflows:read", parameters);
```

#### wfm:workflows:update

##### Description
| Topic | Parameters |
| ----------- | ------------- |
| wfm:workflows:list | ```NONE``` |
| wfm:workflows:read | ```{id: <<id of workflow to read>>}``` |
| wfm:workflows:update | ```{workflowToUpdate: {<<A valid workflow>>}}``` |
| wfm:workflows:create | ```{workflowToCreate: {<<A valid workflow>>}}``` |
| wfm:workflows:remove | ```{id: <<id of workflow to remove>>}``` |

Update a single Workflow

##### Example
#### Step Topics

The following topics allow the updating of the workflow state to progress through a workflow.

```javascript
var parameters = {
workflowToUpdate: {
...
id: "workflowId"
...
},
//Optional topic unique identifier.
topicUid: "uniquetopicid"
}

mediator.publish("wfm:workflows:update", parameters);
```


#### wfm:workflows:remove

##### Description

Remove a single Workflow

##### Example


```javascript
var parameters = {
id: "workflowId",
//Optional topic unique identifier.
topicUid: "uniquetopicid"
{
workflow: {
//The details of the current workflow being progressed
},
workorder: {
//The details of the current workorder being progressed
},
result: {
//The current result object for this workorder being progressed
},
nextStepIndex: 0 //The index of the next step to display
step: {
//The details of the step to display
}
}

mediator.publish("wfm:workflows:remove", parameters);
```

| Topic | Parameters |
| ---- | ----------- |
| *wfm:workflows:step:begin*| `{workorderId: "WORKORDERID", topicUid: "WORKORDERID"}` |
| *wfm:workflows:step:summary*| `{workorderId: "WORKORDERID", topicUid: "WORKORDERID"}` |
| *wfm:workflows:step:previous*| `{workorderId: "WORKORDERID", topicUid: "WORKORDERID"}` |
| *wfm:workflows:step:complete*| `{workorderId: "WORKORDERID", topicUid: "WORKORDERID", submission: {...}, stepCode: "CODEOFCOMPLETEDSTEP"}` |

#### wfm:workflows:list

##### Description

List All Workflows

##### Example


```javascript
var parameters = {
//Optional topic unique identifier.
topicUid: "uniquetopicid"
}

mediator.publish("wfm:workflows:list", parameters);
```


### Published Topics

The following topics are published by this module. Developers are free to implement these topics subscribers, or use a module that already has these subscribers implement (E.g. the [raincatcher-sync](https://github.com/feedhenry-raincatcher/raincatcher-sync) module).


| Topic | Description |
| Topic | Parameters |
| ------------- |:-------------:|
| wfm:sync:workflows:create | Create a new item in the sync `workflows` collection |
| wfm:sync:workflows:update | Update an existing item in the sync `workflows` collection |
| wfm:sync:workflows:list | List all items in the sync `workflows` collection |
| wfm:sync:workflows:remove | Remove an existing item from the sync `workflows` collection |
| wfm:sync:workflows:read | Read a single item from the sync `workflows` collection |
| wfm:sync:workflows:start | Start the sync process for sync `workflows` collection |
| wfm:sync:workflows:stop | Stop the sync process for sync `workflows` collection |
| wfm:sync:workflows:force_sync | Force a sync cycle from client to cloud for sync `workflows` collection |


### Topic Subscriptions

| Topic | Description |
| ------------- |:-------------:|
| done:wfm:sync:workflows:create | A workflow was created in the `workflows` dataset |
| error:wfm:sync:workflows:create | An error occurred when creating an item in the `workflows` dataset. |
| done:wfm:sync:workflows:update | A workflow was updated in the `workflows` dataset |
| error:wfm:sync:workflows:update | An error occurred when updating an item in the `workflows` dataset. |
| done:wfm:sync:workflows:list | A list of the items in the `workflows` dataset completed |
| error:wfm:sync:workflows:list | An error occurred when listing items in the `workflows` dataset. |
| done:wfm:sync:workflows:remove | A workflow was removed from the `workflows` dataset |
| error:wfm:sync:workflows:remove | An error occurred when removing an item in the `workflows` dataset. |
| done:wfm:sync:workflows:read | A item was read correctly from the `workflows` dataset |
| error:wfm:sync:workflows:read | An error occurred when reading an item in the `workflows` dataset. |
| done:wfm:sync:workflows:start | The sync process started for the `workflows` dataset. |
| error:wfm:sync:workflows:start | An error occurred when starting the `workflows` dataset. |
| done:wfm:sync:workflows:stop | The sync process stopped for the `workflows` dataset. |
| error:wfm:sync:workflows:stop | An error occurred when stopping the `workflows` dataset sync process. |
| done:wfm:sync:workflows:force_sync | A force sync process completed for the `workflows` dataset. |
| error:wfm:sync:workflows:force_sync | An error occurred when forcing the sync process for the `workflows` dataset. |

| wfm:sync:workflows:create | ```{itemToCreate: workflowToCreate}``` |
| wfm:sync:workflows:update | ```{itemToUpdate: workflowToUpdate}``` |
| wfm:sync:workflows:list | ```NONE``` |
| wfm:sync:workflows:remove | ```{id: <<ID Of Workflow To Remove>>}``` |
| wfm:sync:workflows:read | ```{id: <<ID Of Workflow To Read>>}``` |

## Usage in an express backend

Expand All @@ -166,19 +77,34 @@ var express = require('express')
...

// setup the wfm workflow sync server
require('fh-wfm-workflow/server')(mediator, app, mbaasExpress);

require('fh-wfm-workflow/lib/cloud')(mediator, app, mbaasExpress);
```

### Server side events
the module broadcasts, and listens for the following events
### Cloud Topics

#### Subscribed Topics

The module subscribes to the following topics

| Topic | Parameters |
| ----------- | ------------- |
| wfm:cloud:workflows:list | ```{filter: {<<filter parameters>>}}``` |
| wfm:cloud:workflows:read | ```<<id of workflow to read>>``` |
| wfm:cloud:workflows:update | ```{<<<workflow to update>>>}``` |
| wfm:cloud:workflows:create | ```{<<<workflow to create>>>}``` |
| wfm:cloud:workflows:delete | ```<<id of workflow to delete>>``` |


#### Published Topics
The module publishes the following topics

| Listens for | Responds with |
| Topic | Parameters |
| ----------- | ------------- |
| `wfm:workflow:list` | `done:wfm:workflow:list` |
| `wfm:workflow:read` | `done:wfm:workflow:read` |
| `wfm:workflow:update` | `done:wfm:workflow:update` |
| `wfm:workflow:create` | `done:wfm:workflow:create` |
| wfm:cloud:data:workflows:list | ```{<<filter parameters>>}``` |
| wfm:cloud:data:workflows:read | ```<<id of workflow to read>>``` |
| wfm:cloud:data:workflows:update | ```{<<<workflow to update>>>}``` |
| wfm:cloud:data:workflows:create | ```{<<<workflow to update>>>}``` |
| wfm:cloud:data:workflows:delete | ```<<id of workflow to delete>>``` |

### Integration

Expand Down
21 changes: 5 additions & 16 deletions lib/client/mediator-subscribers/begin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
var CONSTANTS = require('../../constants');
var q = require('q');
var Q = require('q');


/**
Expand All @@ -23,41 +22,31 @@ module.exports = function workflowBeginSubscriber(workflowStepSubscribers, workf
*
* @param parameters
* @param parameters.workorderId
* @param parameters.topicUid
*/
return function handleWorkflowBegin(parameters) {
var self = this;

workflowClient.getWorkorderSummary(parameters.workorderId).then(function(workorderSummary) {
return workflowClient.getWorkorderSummary(parameters.workorderId).then(function(workorderSummary) {
var workorder = workorderSummary[0];
var workflow = workorderSummary[1];
var result = workorderSummary[2] || workflowClient.createNewResult(parameters.workorderId);

//When the result has been read/created, then we can move on.
q.when(result).then(function(result) {
return Q.when(result).then(function(result) {
//Now we check the current status of the workflow to see where the next step should be.
var stepReview = workflowClient.stepReview(workflow.steps, result);

result.nextStepIndex = stepReview.nextStepIndex;
result.status = workflowClient.checkStatus(workorder, workflow, result);

//The result has been created if needed
var doneTopic = workflowStepSubscribers.getTopic(CONSTANTS.STEP_TOPICS.BEGIN, CONSTANTS.DONE_PREFIX, parameters.topicUid);

//We now have the current status of the workflow for this workorder, the begin step is now complete.
self.mediator.publish(doneTopic, {
return {
workorder: workorder,
workflow: workflow,
result: result,
nextStepIndex: result.nextStepIndex,
step: result.nextStepIndex > -1 ? workflow.steps[result.nextStepIndex] : workflow.steps[0]
});
};
});

}).catch(function(err) {
var errorTopic = workflowStepSubscribers.getTopic(CONSTANTS.STEP_TOPICS.BEGIN, CONSTANTS.ERROR_PREFIX, parameters.topicUid);

self.mediator.publish(errorTopic, err);
});
};
};
20 changes: 6 additions & 14 deletions lib/client/mediator-subscribers/complete.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var CONSTANTS = require('../../constants');
var _ = require('lodash');
var Q = require('q');

/**
*
Expand All @@ -24,21 +25,17 @@ module.exports = function workflowStepDoneSubscriber(workflowStepSubscribers, wo
*
*/
return function handleWorkflowStepDone(parameters) {
var self = this;

var errorTopic = workflowStepSubscribers.getTopic(CONSTANTS.STEP_TOPICS.COMPLETE, CONSTANTS.ERROR_PREFIX, parameters.topicUid);
var doneTopic = workflowStepSubscribers.getTopic(CONSTANTS.STEP_TOPICS.COMPLETE, CONSTANTS.DONE_PREFIX, parameters.topicUid);

//Getting the currently logged in user data.
workflowClient.readUserProfile().then(function(profileData) {
return workflowClient.readUserProfile().then(function(profileData) {
return workflowClient.getWorkorderSummary(parameters.workorderId).then(function(workorderSummary) {
var workorder = workorderSummary[0];
var workflow = workorderSummary[1];
var result = workorderSummary[2];

if (!result) {
//No result exists, The workflow should have been started
return self.mediator.publish(errorTopic, new Error("No result exists for workorder " + parameters.workorderId + ". The workflow done topic can only be used for a workflow that has begun"));
return Q.reject(new Error("No result exists for workorder " + parameters.workorderId + ". The workflow done topic can only be used for a workflow that has begun"));
}

var step = _.find(workflow.steps, function(step) {
Expand All @@ -48,7 +45,7 @@ module.exports = function workflowStepDoneSubscriber(workflowStepSubscribers, wo
//If there is no step, then this step submission is invalid.
if (!step) {
//No result exists, The workflow should have been started
return self.mediator.publish(errorTopic, new Error("Invalid step to assign completed data for workorder " + parameters.workorderId + " and step code " + parameters.stepCode));
return Q.reject(new Error("Invalid step to assign completed data for workorder " + parameters.workorderId + " and step code " + parameters.stepCode));
}

//Got the workflow, now we can create the step result.
Expand All @@ -67,23 +64,18 @@ module.exports = function workflowStepDoneSubscriber(workflowStepSubscribers, wo
result.status = workflowClient.checkStatus(workorder, workflow, result);
result.nextStepIndex = workflowClient.stepReview(workflow.steps, result).nextStepIndex;



//Updating the result
return workflowClient.updateResult(result).then(function() {

//Result update complete, we can now publish the done topic for the step complete with the details of the next step for the user.
self.mediator.publish(doneTopic, {
return {
workorder: workorder,
workflow: workflow,
result: result,
nextStepIndex: result.nextStepIndex,
step: result.nextStepIndex > -1 ? workflow.steps[result.nextStepIndex] : workflow.steps[0]
});
};
});
});
}).catch(function(err) {
self.mediator.publish(errorTopic, err);
});
};
};
14 changes: 3 additions & 11 deletions lib/client/mediator-subscribers/create.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
var _ = require('lodash');
var CONSTANTS = require('../../constants');
var Q = require('q');


/**
Expand All @@ -16,26 +16,18 @@ module.exports = function createWorkflowSubscriber(workflowEntityTopics, workflo
*
* @param {object} parameters
* @param {object} parameters.workflowToCreate - The workflow item to create
* @param {string/number} parameters.topicUid - (Optional) A unique ID to be used to publish completion / error topics.
* @returns {*}
*/
return function handleCreateWorkflowTopic(parameters) {
var self = this;
parameters = parameters || {};
var workflowCreateErrorTopic = workflowEntityTopics.getTopic(CONSTANTS.TOPICS.CREATE, CONSTANTS.ERROR_PREFIX, parameters.topicUid);

var workflowToCreate = parameters.workflowToCreate;

//If no workflow is passed, can't create one
if (!_.isPlainObject(workflowToCreate)) {
return self.mediator.publish(workflowCreateErrorTopic, new Error("Invalid Data To Create A Workflow."));
return Q.reject(new Error("Invalid Data To Create A Workflow."));
}

workflowClient.create(workflowToCreate)
.then(function(createdWorkflow) {
self.mediator.publish(workflowEntityTopics.getTopic(CONSTANTS.TOPICS.CREATE, CONSTANTS.DONE_PREFIX, parameters.topicUid), createdWorkflow);
}).catch(function(error) {
self.mediator.publish(workflowCreateErrorTopic, error);
});
return workflowClient.create(workflowToCreate);
};
};
Loading