Skip to content

Commit 6b4efd5

Browse files
updated maestro examples
1 parent 2a6ff32 commit 6b4efd5

File tree

14 files changed

+254
-112
lines changed

14 files changed

+254
-112
lines changed

config/appsettings.example.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@
2929
"clickAPIUrl": "https://demo.docusign.net/clickapi",
3030
"adminAPIUrl": "https://api-d.docusign.net/management",
3131
"monitorApiUrl": "https://lens-d.docusign.net",
32-
"maestroApiIrl": "https://demo.services.docusign.net/aow-manage/v1.0",
32+
"maestroApiUrl": "https://demo.services.docusign.net/",
3333
"codeExamplesManifest": "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/CodeExamplesManifest.json"
3434
}

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ app.get('/cneg001', eg001connect.getController)
275275

276276
app.get('/mseg001', eg001maestro.getController)
277277
.post('/mseg001', eg001maestro.createController)
278+
.post('/mseg001publish', eg001maestro.publishController)
278279
.get('/mseg002', eg002maestro.getController)
279280
.post('/mseg002', eg002maestro.createController)
280281
.get('/mseg003', eg003maestro.getController)

lib/maestro/controllers/eg001TriggerWorkflow.js

Lines changed: 121 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const validator = require('validator');
99
const { formatString, API_TYPES } = require('../../utils.js');
1010
const { getExampleByNumber } = require('../../manifestService');
1111
const dsConfig = require('../../../config/index.js').config;
12-
const { getWorkflowDefinition, triggerWorkflow } = require('../examples/triggerWorkflow');
12+
const { getWorkflowDefinitions, getWorkflowDefinition, triggerWorkflow } = require('../examples/triggerWorkflow');
1313
const { createWorkflow, publishWorkflow } = require('../workflowUtils.js');
1414

1515
const eg001TriggerWorkflow = exports;
@@ -18,6 +18,7 @@ const eg = `mseg00${exampleNumber}`; // This example reference.
1818
const api = API_TYPES.MAESTRO;
1919
const mustAuthenticate = '/ds/mustAuthenticate';
2020
const minimumBufferMin = 3;
21+
const workflowName = 'Example workflow - send invite to signer';
2122

2223

2324
/**
@@ -47,7 +48,8 @@ eg001TriggerWorkflow.createController = async (req, res) => {
4748
ccName: validator.escape(body.ccName),
4849
workflowId: req.session.workflowId,
4950
accessToken: req.user.accessToken,
50-
basePath: dsConfig.maestroApiIrl,
51+
basePath: dsConfig.maestroApiUrl,
52+
triggerWorkflowBasePath: dsConfig.maestroTriggerWorkflowApiUrl,
5153
accountId: req.session.accountId,
5254
};
5355
let results = null;
@@ -56,13 +58,16 @@ eg001TriggerWorkflow.createController = async (req, res) => {
5658
const workflow = await getWorkflowDefinition(args);
5759
results = await triggerWorkflow(workflow, args);
5860
} catch (error) {
59-
const errorBody = error && error.response && error.response.body;
60-
// we can pull the DocuSign error code and message from the response body
61-
const errorCode = errorBody && errorBody.errorCode;
62-
const errorMessage = errorBody && errorBody.message;
63-
// In production, may want to provide customized error messages and
64-
// remediation advice to the user.
65-
res.render('pages/error', { err: error, errorCode, errorMessage });
61+
const errorCode = error?.response?.statusCode;
62+
const errorMessage = error?.response?.body?.message;
63+
let errorInfo;
64+
65+
// use custom error message if Maestro is not enabled for the account
66+
if (errorCode === 403) {
67+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
68+
}
69+
70+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
6671
}
6772
if (results) {
6873
req.session.instanceId = results.instanceId; // Save for use by other examples
@@ -90,33 +95,128 @@ eg001TriggerWorkflow.getController = async (req, res) => {
9095
return res.redirect(mustAuthenticate);
9196
}
9297

98+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
99+
const additionalPageData = example.AdditionalPage.filter(p => p.Name === 'publish_workflow')[0];
100+
const sourceFile =
101+
path.basename(__filename)[5].toLowerCase() +
102+
path.basename(__filename).substr(6);
103+
93104
const args = {
94105
templateId: req.session.templateId,
95106
accessToken: req.user.accessToken,
96-
basePath: dsConfig.maestroApiIrl,
107+
basePath: dsConfig.maestroApiUrl,
97108
accountId: req.session.accountId,
98109
};
99110

100-
// if there is no workflow, then create one
101-
if (!req.session.workflowId) {
102-
if (!req.session.templateId) {
103-
return res.redirect('/eg008');
111+
try {
112+
const workflows = await getWorkflowDefinitions(args);
113+
114+
if (workflows.count > 0) {
115+
const workflow = workflows.value
116+
.filter(workflow => workflow.name === workflowName)
117+
.sort((wf1, wf2) => wf2.lastUpdatedDate - wf1.lastUpdatedDate)[0];
118+
if (workflow) {
119+
req.session.workflowId = workflow.id;
120+
}
104121
}
105122

106-
req.session.workflowId = await createWorkflow(args);
123+
// if there is no workflow, then create one
124+
if (!req.session.workflowId) {
125+
if (!req.session.templateId) {
126+
return res.render('pages/maestro-examples/eg001TriggerWorkflow', {
127+
eg: eg,
128+
csrfToken: req.csrfToken(),
129+
example: example,
130+
templateOk: false,
131+
sourceFile: sourceFile,
132+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
133+
documentation: dsConfig.documentation + eg,
134+
showDoc: dsConfig.documentation,
135+
});
136+
}
137+
138+
req.session.workflowId = await createWorkflow(args);
139+
140+
const consentUrl = await publishWorkflow(args, req.session.workflowId);
141+
if (consentUrl) {
142+
return res.render('pages/maestro-examples/eg001PublishWorkflow', {
143+
example,
144+
consentUrl,
145+
message: additionalPageData.ResultsPageText,
146+
csrfToken: req.csrfToken(),
147+
});
148+
}
149+
}
150+
} catch (error) {
151+
const errorCode = error?.response?.statusCode;
152+
const errorMessage = error?.response?.body?.message;
153+
let errorInfo;
154+
155+
// use custom error message if Maestro is not enabled for the account
156+
if (errorCode === 403) {
157+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
158+
}
159+
160+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
107161
}
108162

109-
if (!req.session.workflowPublished) {
163+
res.render('pages/maestro-examples/eg001TriggerWorkflow', {
164+
eg: eg,
165+
csrfToken: req.csrfToken(),
166+
example: example,
167+
sourceFile: sourceFile,
168+
templateOk: true,
169+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
170+
documentation: dsConfig.documentation + eg,
171+
showDoc: dsConfig.documentation,
172+
});
173+
};
174+
175+
/**
176+
* Publish workflow page
177+
*/
178+
eg001TriggerWorkflow.publishController = async (req, res) => {
179+
// Check that the authentication token is ok with a long buffer time.
180+
// If needed, now is the best time to ask the user to authenticate
181+
// since they have not yet entered any information into the form.
182+
const isTokenOK = req.dsAuth.checkToken();
183+
if (!isTokenOK) {
184+
// Save the current operation so it will be resumed after authentication
185+
req.dsAuth.setEg(req, eg);
186+
return res.redirect(mustAuthenticate);
187+
}
188+
189+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
190+
const additionalPageData = example.AdditionalPage.filter(p => p.Name === 'publish_workflow')[0];
191+
192+
try {
193+
const args = {
194+
accessToken: req.user.accessToken,
195+
basePath: dsConfig.maestroApiUrl,
196+
accountId: req.session.accountId,
197+
};
110198
const consentUrl = await publishWorkflow(args, req.session.workflowId);
111199
if (consentUrl) {
112-
const redirectUrl = `${consentUrl}&host=${dsConfig.appUrl}/${eg}`;
113-
return res.redirect(redirectUrl);
200+
return res.render('pages/maestro-examples/eg001PublishWorkflow', {
201+
example,
202+
consentUrl,
203+
message: additionalPageData.ResultsPageText,
204+
csrfToken: req.csrfToken(),
205+
});
206+
}
207+
} catch (error) {
208+
const errorCode = error?.response?.statusCode;
209+
const errorMessage = error?.response?.body?.message;
210+
let errorInfo;
211+
212+
// use custom error message if Maestro is not enabled for the account
213+
if (errorCode === 403) {
214+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
114215
}
115216

116-
req.session.workflowPublished = true;
217+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
117218
}
118219

119-
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
120220
const sourceFile =
121221
path.basename(__filename)[5].toLowerCase() +
122222
path.basename(__filename).substr(6);
@@ -125,10 +225,9 @@ eg001TriggerWorkflow.getController = async (req, res) => {
125225
csrfToken: req.csrfToken(),
126226
example: example,
127227
sourceFile: sourceFile,
228+
templateOk: true,
128229
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
129230
documentation: dsConfig.documentation + eg,
130231
showDoc: dsConfig.documentation,
131232
});
132233
};
133-
134-

lib/maestro/controllers/eg002CancelWorkflow.js

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const path = require('path');
88
const { formatString, API_TYPES } = require('../../utils.js');
99
const { getExampleByNumber } = require('../../manifestService');
1010
const dsConfig = require('../../../config/index.js').config;
11-
const { cancelWorkflowInstance } = require('../examples/cancelWorkflow');
11+
const { cancelWorkflowInstance, getWorkflowInstanceState } = require('../examples/cancelWorkflow');
1212

1313
const eg002CancelWorkflow = exports;
1414
const exampleNumber = 2;
@@ -39,21 +39,24 @@ eg002CancelWorkflow.createController = async (req, res) => {
3939
const args = {
4040
instanceId: req.session.instanceId,
4141
accessToken: req.user.accessToken,
42-
basePath: dsConfig.maestroApiIrl,
42+
basePath: dsConfig.maestroApiUrl,
4343
accountId: req.session.accountId,
4444
};
4545
let results = null;
4646

4747
try {
4848
results = await cancelWorkflowInstance(args);
4949
} catch (error) {
50-
const errorBody = error && error.response && error.response.body;
51-
// we can pull the DocuSign error code and message from the response body
52-
const errorCode = errorBody && errorBody.errorCode;
53-
const errorMessage = errorBody && errorBody.message;
54-
// In production, may want to provide customized error messages and
55-
// remediation advice to the user.
56-
res.render('pages/error', { err: error, errorCode, errorMessage });
50+
const errorCode = error?.response?.statusCode;
51+
const errorMessage = error?.response?.body?.message;
52+
let errorInfo;
53+
54+
// use custom error message if Maestro is not enabled for the account
55+
if (errorCode === 403) {
56+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
57+
}
58+
59+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
5760
}
5861
if (results) {
5962
// which need an envelopeId
@@ -80,17 +83,45 @@ eg002CancelWorkflow.getController = async (req, res) => {
8083
return res.redirect(mustAuthenticate);
8184
}
8285

86+
let instanceOk = false;
87+
if (req.session.workflowId && req.session.instanceId) {
88+
const args = {
89+
workflowId: req.session.workflowId,
90+
instanceId: req.session.instanceId,
91+
accessToken: req.user.accessToken,
92+
basePath: dsConfig.maestroApiUrl,
93+
accountId: req.session.accountId,
94+
};
95+
96+
try {
97+
const state = await getWorkflowInstanceState(args);
98+
instanceOk = state.toLowerCase().includes('in progress');
99+
} catch (error) {
100+
const errorCode = error?.response?.statusCode;
101+
const errorMessage = error?.response?.body?.message;
102+
let errorInfo;
103+
104+
// use custom error message if Maestro is not enabled for the account
105+
if (errorCode === 403) {
106+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
107+
}
108+
109+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
110+
}
111+
}
112+
83113
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
84114
const sourceFile =
85115
path.basename(__filename)[5].toLowerCase() +
86116
path.basename(__filename).substr(6);
87117
res.render('pages/maestro-examples/eg002CancelWorkflow', {
88-
eg: eg,
118+
eg,
89119
csrfToken: req.csrfToken(),
90-
example: example,
120+
example,
121+
instanceOk,
91122
workflowId: req.session.workflowId,
92123
instanceId: req.session.instanceId,
93-
sourceFile: sourceFile,
124+
sourceFile,
94125
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
95126
documentation: dsConfig.documentation + eg,
96127
showDoc: dsConfig.documentation,

lib/maestro/controllers/eg003GetWorkflowStatus.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,24 @@ eg002CancelWorkflow.createController = async (req, res) => {
4040
workflowId: req.session.workflowId,
4141
instanceId: req.session.instanceId,
4242
accessToken: req.user.accessToken,
43-
basePath: dsConfig.maestroApiIrl,
43+
basePath: dsConfig.maestroApiUrl,
4444
accountId: req.session.accountId,
4545
};
4646
let results = null;
4747

4848
try {
4949
results = await getWorkflowInstance(args);
5050
} catch (error) {
51-
const errorBody = error && error.response && error.response.body;
52-
// we can pull the DocuSign error code and message from the response body
53-
const errorCode = errorBody && errorBody.errorCode;
54-
const errorMessage = errorBody && errorBody.message;
55-
// In production, may want to provide customized error messages and
56-
// remediation advice to the user.
57-
res.render('pages/error', { err: error, errorCode, errorMessage });
51+
const errorCode = error?.response?.statusCode;
52+
const errorMessage = error?.response?.body?.message;
53+
let errorInfo;
54+
55+
// use custom error message if Maestro is not enabled for the account
56+
if (errorCode === 403) {
57+
errorInfo = formatString(res.locals.manifest.SupportingTexts.ContactSupportToEnableFeature, 'Maestro');
58+
}
59+
60+
return res.render('pages/error', { err: error, errorCode, errorMessage, errorInfo });
5861
}
5962
if (results) {
6063
// which need an envelopeId

lib/maestro/examples/cancelWorkflow.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,20 @@ const cancelWorkflowInstance = async (args) => {
2525
return cancelResponse;
2626
};
2727

28-
module.exports = { cancelWorkflowInstance };
28+
const getWorkflowInstanceState = async (args) => {
29+
const dsApiClient = new docusign.ApiClient();
30+
dsApiClient.setBasePath(args.basePath);
31+
dsApiClient.addDefaultHeader('Authorization', `Bearer ${args.accessToken}`);
32+
33+
const workflowInstanceManagementApi = new docusign.WorkflowInstanceManagementApi(dsApiClient);
34+
const workflowInstance =
35+
await workflowInstanceManagementApi.getWorkflowInstance(
36+
args.accountId,
37+
args.workflowId,
38+
args.instanceId
39+
);
40+
41+
return workflowInstance.instanceState;
42+
};
43+
44+
module.exports = { cancelWorkflowInstance, getWorkflowInstanceState };

0 commit comments

Comments
 (0)