Skip to content

Commit a024cc2

Browse files
first example
1 parent 4b353da commit a024cc2

File tree

9 files changed

+859
-5
lines changed

9 files changed

+859
-5
lines changed

index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const {
5454
} = require('./lib/admin/controllers');
5555

5656
const { eg001connect } = require('./lib/connect/controllers');
57+
const { eg001maestro } = require('./lib/maestro/controllers');
5758

5859
const PORT = process.env.PORT || 3000;
5960
const HOST = process.env.HOST || 'localhost';
@@ -272,6 +273,9 @@ app.get('/eg001', eg001.getController)
272273
app.get('/cneg001', eg001connect.getController)
273274
.post('/cneg001', eg001connect.createController);
274275

276+
app.get('/mseg001', eg001maestro.getController)
277+
.post('/mseg001', eg001maestro.createController);
278+
275279
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next); }
276280
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next); }
277281

@@ -297,7 +301,7 @@ You can set them in the configuration file config/appsettings.json or set enviro
297301
passport.serializeUser(function(user, done) { done(null, user); });
298302
passport.deserializeUser(function(obj, done) { done(null, obj); });
299303

300-
const SCOPES = ['signature'];
304+
const SCOPES = ['signature', 'webforms_manage'];
301305
const ROOM_SCOPES = [
302306
'signature', 'dtr.rooms.read', 'dtr.rooms.write',
303307
'dtr.documents.read', 'dtr.documents.write', 'dtr.profile.read', 'dtr.profile.write',
@@ -316,8 +320,9 @@ const ADMIN_SCOPES = [
316320
'user_data_redact', 'asset_group_account_read', 'asset_group_account_clone_write',
317321
'asset_group_account_clone_read'
318322
];
323+
const MAESTRO_SCOPES = ['signature', 'aow_manage'];
319324

320-
const scope = [...ROOM_SCOPES, ...CLICK_SCOPES, ...MONITOR_SCOPES, ...ADMIN_SCOPES, ...SCOPES];
325+
const scope = [...ROOM_SCOPES, ...CLICK_SCOPES, ...MONITOR_SCOPES, ...ADMIN_SCOPES, ...SCOPES, ...MAESTRO_SCOPES];
321326

322327
// Configure passport for DocusignStrategy
323328
let docusignStrategy = new DocusignStrategy({

lib/DSJwtAuth.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let DsJwtAuth = function _DsJwtAuth(req) {
1818
this.accountName = req.user && req.user.accountName;
1919
this.basePath = req.user && req.user.basePath;
2020
this._tokenExpiration = req.user && req.user.tokenExpirationTimestamp;
21-
this.scopes = 'signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read';
21+
this.scopes = 'signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read webforms_manage aow_manage';
2222

2323
// For production use, you'd want to store the refresh token in non-volatile storage since it is
2424
// good for 30 days. You'd probably want to encrypt it too.

lib/common/DSJwtAuth.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
this.accountName = req.user && req.user.accountName;
1919
this.basePath = req.user && req.user.basePath;
2020
this._tokenExpiration = req.user && req.user.tokenExpirationTimestamp;
21-
this.scopes = 'signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send';
21+
this.scopes = 'signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send aow_manage';
2222

2323
// For production use, you'd want to store the refresh token in non-volatile storage since it is
2424
// good for 30 days. You'd probably want to encrypt it too.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/**
2+
* @file
3+
* Example 001: Trigger a 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 { getWorkflowDefinition, triggerWorkflow } = require('../examples/triggerWorkflow');
13+
const { createWorkflow, publishWorkflow } = require('../workflowUtils.js');
14+
15+
const eg001TriggerWorkflow = exports;
16+
const exampleNumber = 1;
17+
const eg = `mseg00${exampleNumber}`; // This example reference.
18+
const api = API_TYPES.MAESTRO;
19+
const mustAuthenticate = '/ds/mustAuthenticate';
20+
const minimumBufferMin = 3;
21+
22+
23+
/**
24+
* Create the envelope
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+
workflowId: req.session.workflowId,
49+
accessToken: req.user.accessToken,
50+
basePath: dsConfig.maestroApiIrl,
51+
accountId: req.session.accountId,
52+
};
53+
let results = null;
54+
55+
try {
56+
const workflow = await getWorkflowDefinition(args);
57+
results = await triggerWorkflow(workflow, args);
58+
} 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 });
66+
}
67+
if (results) {
68+
req.session.envelopeId = results.envelopeId; // Save for use by other examples
69+
// which need an envelopeId
70+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
71+
res.render('pages/example_done', {
72+
title: example.ExampleName,
73+
message: formatString(example.ResultsPageText, JSON.stringify(results.envelopeId)),
74+
});
75+
}
76+
};
77+
78+
/**
79+
* Form page for this application
80+
*/
81+
eg001TriggerWorkflow.getController = async (req, res) => {
82+
// Check that the authentication token is ok with a long buffer time.
83+
// If needed, now is the best time to ask the user to authenticate
84+
// since they have not yet entered any information into the form.
85+
const isTokenOK = req.dsAuth.checkToken();
86+
if (!isTokenOK) {
87+
// Save the current operation so it will be resumed after authentication
88+
req.dsAuth.setEg(req, eg);
89+
return res.redirect(mustAuthenticate);
90+
}
91+
92+
req.session.templateId = 'ae232f1f-911f-4115-8fff-6bcf47fa959a';
93+
// req.session.workflowId = '0d4d954c-24d1-49d9-bc7f-4467041141c4';
94+
const args = {
95+
templateId: req.session.templateId,
96+
accessToken: req.user.accessToken,
97+
basePath: dsConfig.maestroApiIrl,
98+
accountId: req.session.accountId,
99+
};
100+
let workflowId; // = '0d4d954c-24d1-49d9-bc7f-4467041141c4';
101+
102+
// req.session.workflowId = 'c71e27eb-9ca7-4e88-8663-9bd2e76e77c7';
103+
104+
105+
// if there is no workflow, then create one
106+
if (!req.session.workflowId) {
107+
if (!req.session.templateId) {
108+
return res.redirect('/eg008');
109+
}
110+
111+
req.session.workflowId = await createWorkflow(args);
112+
}
113+
114+
if (!req.session.workflowPublished) {
115+
const consentUrl = await publishWorkflow(args, req.session.workflowId);
116+
if (consentUrl) {
117+
const redirectUrl = `${consentUrl}&host=${dsConfig.appUrl}/${eg}`;
118+
return res.redirect(redirectUrl);
119+
}
120+
121+
req.session.workflowPublished = true;
122+
}
123+
124+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
125+
const sourceFile =
126+
path.basename(__filename)[5].toLowerCase() +
127+
path.basename(__filename).substr(6);
128+
res.render('pages/maestro-examples/eg001TriggerWorkflow', {
129+
eg: eg,
130+
csrfToken: req.csrfToken(),
131+
example: example,
132+
sourceFile: sourceFile,
133+
sourceUrl: dsConfig.githubExampleUrl + 'maestro/examples/' + sourceFile,
134+
documentation: dsConfig.documentation + eg,
135+
showDoc: dsConfig.documentation,
136+
});
137+
};
138+
139+

lib/maestro/controllers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports.eg001maestro = require('./eg001TriggerWorkflow');
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @file
3+
* Example 001: Trigger workflow
4+
* @author DocuSign
5+
*/
6+
7+
const docusign = require('docusign-maestro');
8+
const { makePostRequest } = require('../../utils');
9+
10+
const getWorkflowDefinitions = async (args) => {
11+
const dsApiClient = new docusign.ApiClient();
12+
dsApiClient.setBasePath(args.basePath);
13+
dsApiClient.addDefaultHeader('Authorization', `Bearer ${args.accessToken}`);
14+
15+
const workflowManagementApi = new docusign.WorkflowManagementApi(dsApiClient);
16+
const workflowDefinition = await workflowManagementApi.getWorkflowDefinitions(args.accountId);
17+
18+
return workflowDefinition;
19+
};
20+
21+
const getWorkflowDefinition = async (args) => {
22+
const dsApiClient = new docusign.ApiClient();
23+
dsApiClient.setBasePath(args.basePath);
24+
dsApiClient.addDefaultHeader('Authorization', `Bearer ${args.accessToken}`);
25+
26+
const workflowManagementApi = new docusign.WorkflowManagementApi(dsApiClient);
27+
const workflowDefinition = await workflowManagementApi.getWorkflowDefinition(args.accountId, args.workflowId);
28+
29+
return workflowDefinition;
30+
};
31+
32+
const triggerWorkflow = async (workflow, args) => {
33+
const triggerPayload = docusign.TriggerPayload.constructFromObject({
34+
instanceName: args.instanceName,
35+
participant: {},
36+
payload: {
37+
signerEmail: args.signerEmail,
38+
signerName: args.signerName,
39+
ccEmail: args.ccEmail,
40+
ccName: args.ccName
41+
},
42+
metadata: {}
43+
});
44+
45+
const response = makePostRequest(workflow.triggerUrl, triggerPayload, {
46+
headers: {
47+
Authorization: `Bearer ${args.accessToken}`,
48+
'Content-Type': 'application/json',
49+
},
50+
});
51+
52+
return response;
53+
};
54+
55+
module.exports = { getWorkflowDefinitions, getWorkflowDefinition, triggerWorkflow };

0 commit comments

Comments
 (0)