Skip to content

Commit 3aa8ab1

Browse files
add maestro examples
1 parent 352021e commit 3aa8ab1

24 files changed

+606
-14
lines changed

index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ const { eg001webforms } = require('./lib/webforms/controllers');
6060
const { eg004notary } = require('./lib/notary/controllers');
6161
const { eg001fields } = require('./lib/connectedFields/controllers');
6262
const { eg001Navigator, eg002Navigator } = require('./lib/navigator/controllers');
63+
const { eg001maestro, eg002maestro, eg003maestro, eg004maestro } = require('./lib/maestro/controllers');
6364

6465
const PORT = process.env.PORT || 3000;
6566
const HOST = process.env.HOST || 'localhost';
@@ -299,6 +300,15 @@ app.get('/nav001', eg001Navigator.getController)
299300
.get('/nav002', eg002Navigator.getController)
300301
.post('/nav002', eg002Navigator.createController);
301302

303+
app.get('/mae001', eg001maestro.getController)
304+
.post('/mae001', eg001maestro.createController)
305+
.get('/mae002', eg002maestro.getController)
306+
.post('/mae002', eg002maestro.createController)
307+
.get('/mae003', eg003maestro.getController)
308+
.post('/mae003', eg003maestro.createController)
309+
.get('/mae004', eg004maestro.getController)
310+
.post('/mae004', eg004maestro.createController);
311+
302312
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next); }
303313
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next); }
304314

@@ -352,6 +362,9 @@ const NOTARY_SCOPES = [
352362
const CONNECTED_FIELDS_SCOPES = [
353363
'signature', 'adm_store_unified_repo_read'
354364
];
365+
const MAESTRO_SCOPES = [
366+
'signature', 'aow_manage'
367+
];
355368

356369
const scope = [
357370
...ROOM_SCOPES,
@@ -362,6 +375,7 @@ const scope = [
362375
...WEBFORMS_SCOPES,
363376
...NOTARY_SCOPES,
364377
...CONNECTED_FIELDS_SCOPES,
378+
...MAESTRO_SCOPES
365379
];
366380

367381
// Configure passport for DocusignStrategy

lib/connectedFields/controllers/eg001SetConnectedFields.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,10 @@ eg001SetConnectedFields.createController = async (req, res) => {
102102

103103
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
104104
if (tabGroups.length === 0) {
105-
const additionalPageData = example.AdditionalPage.filter(p => p.Name === 'no_verification_app')[0];
106-
107-
return res.render('pages/example_done', {
108-
title: example.ExampleName,
109-
message: additionalPageData?.ResultsPageText,
110-
});
105+
const errorCode = '404';
106+
const errorMessage = 'No data verification extension apps found';
107+
const errorInfo = example.CustomErrorTexts[0].ErrorMessage;
108+
return res.render('pages/error', { errorCode, errorMessage, errorInfo });
111109
}
112110
req.session.apps = tabGroups;
113111

lib/connectedFields/examples/setConnectedFields.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const iam = require('@docusign/iam-sdk');
1313
* @param {object} args
1414
*/
1515
const getTabGroups = async (args) => {
16-
const client = new iam.IamClient({ accessToken: args.accessToken, serverURL: args.basePath });
16+
const client = new iam.IamClient({ accessToken: args.accessToken });
1717
return await client.connectedFields.tabInfo.getConnectedFieldsTabGroups({ accountId: args.accountId });
1818
};
1919

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @file
3+
* Example 001: How to trigger a Maestro workflow
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const validator = require('validator');
9+
const { formatString, API_TYPES } = require('../../utils.js');
10+
const { getExampleByNumber } = require('../../manifestService');
11+
const dsConfig = require('../../../config/index.js').config;
12+
const { getMaestroWorkflows, triggerWorkflow } = require('../examples/triggerWorkflow');
13+
14+
const eg001TriggerWorkflow = exports;
15+
const exampleNumber = 1;
16+
const eg = `mae00${exampleNumber}`; // This example reference.
17+
const api = API_TYPES.MAESTRO;
18+
const mustAuthenticate = '/ds/mustAuthenticate';
19+
const minimumBufferMin = 3;
20+
const workflowName = 'Example workflow - send invite to signer';
21+
22+
23+
/**
24+
* Trigger workflow
25+
* @param {object} req Request obj
26+
* @param {object} res Response obj
27+
*/
28+
eg001TriggerWorkflow.createController = async (req, res) => {
29+
// Step 1. Check the token
30+
// At this point we should have a good token. But we
31+
// double-check here to enable a better UX to the user.
32+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
33+
if (!isTokenOK) {
34+
req.flash('info', 'Sorry, you need to re-authenticate.');
35+
// Save the current operation so it will be resumed after authentication
36+
req.dsAuth.setEg(req, eg);
37+
return res.redirect(mustAuthenticate);
38+
}
39+
40+
// Step 2. Call the worker method
41+
const { body } = req;
42+
const args = {
43+
instanceName: validator.escape(body.instanceName),
44+
signerEmail: validator.escape(body.signerEmail),
45+
signerName: validator.escape(body.signerName),
46+
ccEmail: validator.escape(body.ccEmail),
47+
ccName: validator.escape(body.ccName),
48+
accessToken: req.user.accessToken,
49+
basePath: dsConfig.maestroApiUrl,
50+
accountId: req.session.accountId,
51+
};
52+
53+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
54+
try {
55+
const workflows = await getMaestroWorkflows(args);
56+
57+
if (workflows.data && workflows.data.length > 0) {
58+
const workflow = workflows.data.find(wf => wf.status === 'active' && wf.name === workflowName);
59+
if (workflow) {
60+
const { instanceUrl, instanceId } = await triggerWorkflow(args, workflow.id);
61+
req.session.workflowId = workflow.id;
62+
req.session.instanceId = instanceId;
63+
64+
return res.render('pages/maestro-examples/eg001EmbedWorkflow', {
65+
title: example.ExampleName,
66+
message: formatString(example.ResultsPageText, JSON.stringify(instanceId)),
67+
instanceUrl,
68+
});
69+
}
70+
} else {
71+
const errorCode = '404';
72+
const errorMessage = 'No active workflow found';
73+
const errorInfo = example.CustomErrorTexts[0].ErrorMessage;
74+
return res.render('pages/error', { errorCode, errorMessage, errorInfo });
75+
}
76+
} catch (error) {
77+
const errorCode = error?.response?.statusCode;
78+
const errorMessage = error?.response?.body?.message;
79+
return res.render('pages/error', { err: error, errorCode, errorMessage });
80+
}
81+
};
82+
83+
/**
84+
* Form page for this application
85+
*/
86+
eg001TriggerWorkflow.getController = async (req, res) => {
87+
// Check that the authentication token is ok with a long buffer time.
88+
// If needed, now is the best time to ask the user to authenticate
89+
// since they have not yet entered any information into the form.
90+
const isTokenOK = req.dsAuth.checkToken();
91+
if (!isTokenOK) {
92+
// Save the current operation so it will be resumed after authentication
93+
req.dsAuth.setEg(req, eg);
94+
return res.redirect(mustAuthenticate);
95+
}
96+
97+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
98+
const sourceFile =
99+
path.basename(__filename)[5].toLowerCase() +
100+
path.basename(__filename).substr(6);
101+
102+
res.render('pages/maestro-examples/eg001TriggerWorkflow', {
103+
eg: eg,
104+
csrfToken: req.csrfToken(),
105+
example: example,
106+
sourceFile: sourceFile,
107+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
108+
documentation: dsConfig.documentation + eg,
109+
showDoc: dsConfig.documentation,
110+
});
111+
};
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @file
3+
* Example 002: How to pause a Maestro workflow
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const { formatString, API_TYPES } = require('../../utils.js');
9+
const { getExampleByNumber } = require('../../manifestService');
10+
const dsConfig = require('../../../config/index.js').config;
11+
const { pauseWorkflow } = require('../examples/pauseWorkflow');
12+
13+
const eg002PauseWorkflow = exports;
14+
const exampleNumber = 2;
15+
const eg = `mae00${exampleNumber}`; // This example reference.
16+
const api = API_TYPES.MAESTRO;
17+
const mustAuthenticate = '/ds/mustAuthenticate';
18+
const minimumBufferMin = 3;
19+
20+
/**
21+
* Trigger workflow
22+
* @param {object} req Request obj
23+
* @param {object} res Response obj
24+
*/
25+
eg002PauseWorkflow.createController = async (req, res) => {
26+
// Step 1. Check the token
27+
// At this point we should have a good token. But we
28+
// double-check here to enable a better UX to the user.
29+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
30+
if (!isTokenOK) {
31+
req.flash('info', 'Sorry, you need to re-authenticate.');
32+
// Save the current operation so it will be resumed after authentication
33+
req.dsAuth.setEg(req, eg);
34+
return res.redirect(mustAuthenticate);
35+
}
36+
37+
// Step 2. Call the worker method
38+
const args = {
39+
workflowId: req.session.workflowId,
40+
instanceId: req.session.instanceId,
41+
accessToken: req.user.accessToken,
42+
basePath: dsConfig.maestroApiUrl,
43+
accountId: req.session.accountId,
44+
};
45+
46+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
47+
try {
48+
const result = await pauseWorkflow(args);
49+
50+
res.render('pages/example_done', {
51+
title: example.ExampleName,
52+
message: formatString(example.ResultsPageText, req.session.instanceId),
53+
json: JSON.stringify(result)
54+
});
55+
} catch (error) {
56+
const errorCode = error?.response?.statusCode;
57+
const errorMessage = error?.response?.body?.message;
58+
const errorInfo = formatString(example.CustomErrorTexts[1].ErrorMessage, req.session.workflowId);
59+
60+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
61+
}
62+
};
63+
64+
/**
65+
* Form page for this application
66+
*/
67+
eg002PauseWorkflow.getController = async (req, res) => {
68+
// Check that the authentication token is ok with a long buffer time.
69+
// If needed, now is the best time to ask the user to authenticate
70+
// since they have not yet entered any information into the form.
71+
const isTokenOK = req.dsAuth.checkToken();
72+
if (!isTokenOK) {
73+
// Save the current operation so it will be resumed after authentication
74+
req.dsAuth.setEg(req, eg);
75+
return res.redirect(mustAuthenticate);
76+
}
77+
78+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
79+
if (!req.session.workflowId) {
80+
const errorCode = '404';
81+
const errorMessage = 'No workflow ID found';
82+
const errorInfo = example.CustomErrorTexts[0].ErrorMessage;
83+
return res.render('pages/error', { errorCode, errorMessage, errorInfo });
84+
}
85+
86+
const sourceFile =
87+
path.basename(__filename)[5].toLowerCase() +
88+
path.basename(__filename).substr(6);
89+
90+
res.render('pages/maestro-examples/eg002PauseWorkflow', {
91+
eg: eg,
92+
csrfToken: req.csrfToken(),
93+
example: example,
94+
sourceFile: sourceFile,
95+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
96+
documentation: dsConfig.documentation + eg,
97+
showDoc: dsConfig.documentation,
98+
});
99+
};
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* @file
3+
* Example 003: How to resume a Maestro workflow
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const { formatString, API_TYPES } = require('../../utils.js');
9+
const { getExampleByNumber } = require('../../manifestService');
10+
const dsConfig = require('../../../config/index.js').config;
11+
const { resumePausedWorkflow } = require('../examples/resumeWorkflow');
12+
13+
const eg003ResumeWorkflow = exports;
14+
const exampleNumber = 3;
15+
const eg = `mae00${exampleNumber}`; // This example reference.
16+
const api = API_TYPES.MAESTRO;
17+
const mustAuthenticate = '/ds/mustAuthenticate';
18+
const minimumBufferMin = 3;
19+
20+
/**
21+
* Trigger workflow
22+
* @param {object} req Request obj
23+
* @param {object} res Response obj
24+
*/
25+
eg003ResumeWorkflow.createController = async (req, res) => {
26+
// Step 1. Check the token
27+
// At this point we should have a good token. But we
28+
// double-check here to enable a better UX to the user.
29+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
30+
if (!isTokenOK) {
31+
req.flash('info', 'Sorry, you need to re-authenticate.');
32+
// Save the current operation so it will be resumed after authentication
33+
req.dsAuth.setEg(req, eg);
34+
return res.redirect(mustAuthenticate);
35+
}
36+
37+
// Step 2. Call the worker method
38+
const args = {
39+
workflowId: req.session.workflowId,
40+
instanceId: req.session.instanceId,
41+
accessToken: req.user.accessToken,
42+
basePath: dsConfig.maestroApiUrl,
43+
accountId: req.session.accountId,
44+
};
45+
46+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
47+
try {
48+
const result = await resumePausedWorkflow(args);
49+
50+
res.render('pages/example_done', {
51+
title: example.ExampleName,
52+
message: formatString(example.ResultsPageText, req.session.instanceId),
53+
json: JSON.stringify(result)
54+
});
55+
} catch (error) {
56+
const errorCode = error?.response?.statusCode;
57+
const errorMessage = error?.response?.body?.message;
58+
const errorInfo = formatString(example.CustomErrorTexts[1].ErrorMessage, req.session.workflowId);
59+
60+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
61+
}
62+
};
63+
64+
/**
65+
* Form page for this application
66+
*/
67+
eg003ResumeWorkflow.getController = async (req, res) => {
68+
// Check that the authentication token is ok with a long buffer time.
69+
// If needed, now is the best time to ask the user to authenticate
70+
// since they have not yet entered any information into the form.
71+
const isTokenOK = req.dsAuth.checkToken();
72+
if (!isTokenOK) {
73+
// Save the current operation so it will be resumed after authentication
74+
req.dsAuth.setEg(req, eg);
75+
return res.redirect(mustAuthenticate);
76+
}
77+
78+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
79+
if (!req.session.workflowId) {
80+
const errorCode = '404';
81+
const errorMessage = 'No workflow ID found';
82+
const errorInfo = example.CustomErrorTexts[0].ErrorMessage;
83+
return res.render('pages/error', { errorCode, errorMessage, errorInfo });
84+
}
85+
86+
const sourceFile =
87+
path.basename(__filename)[5].toLowerCase() +
88+
path.basename(__filename).substr(6);
89+
90+
res.render('pages/maestro-examples/eg003ResumeWorkflow', {
91+
eg: eg,
92+
csrfToken: req.csrfToken(),
93+
example: example,
94+
sourceFile: sourceFile,
95+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
96+
documentation: dsConfig.documentation + eg,
97+
showDoc: dsConfig.documentation,
98+
});
99+
};

0 commit comments

Comments
 (0)