Skip to content

Commit 9f4ee8a

Browse files
author
Raileen Del Rosario
committed
2 parents 5db4402 + 3215395 commit 9f4ee8a

File tree

16 files changed

+343
-38
lines changed

16 files changed

+343
-38
lines changed

config/appsettings.example.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@
3030
"adminAPIUrl": "https://api-d.docusign.net/management",
3131
"monitorApiUrl": "https://lens-d.docusign.net",
3232
"webformsApiUrl": "https://apps-d.docusign.com/api/webforms/v1.1",
33+
"iamBasePath": "https://api-d.docusign.com/v1",
3334
"codeExamplesManifest": "https://raw.githubusercontent.com/docusign/code-examples-csharp/master/manifest/CodeExamplesManifest.json"
3435
}

index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const { eg001connect } = require('./lib/connect/controllers');
5959
const { eg001webforms } = require('./lib/webforms/controllers');
6060
const { eg004notary } = require('./lib/notary/controllers');
6161
const { eg001fields } = require('./lib/connectedFields/controllers');
62+
const { eg001Navigator, eg002Navigator } = require('./lib/navigator/controllers');
6263

6364
const PORT = process.env.PORT || 3000;
6465
const HOST = process.env.HOST || 'localhost';
@@ -293,6 +294,10 @@ app.get('/neg004', eg004notary.getController)
293294
app.get('/feg001', eg001fields.getController)
294295
.post('/feg001', eg001fields.createController);
295296

297+
app.get('/nav001', eg001Navigator.getController)
298+
.post('/nav001', eg001Navigator.createController)
299+
.get('/nav002', eg002Navigator.getController)
300+
.post('/nav002', eg002Navigator.createController);
296301

297302
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next); }
298303
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next); }

lib/connectedFields/controllers/eg001SetConnectedFields.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
const path = require('path');
8-
const { getTabGroups, sendEnvelope, extractVerificationData } = require('../examples/setConnectedFields');
8+
const { getTabGroups, sendEnvelope, filterData } = require('../examples/setConnectedFields');
99
const validator = require('validator');
1010
const { getExampleByNumber } = require('../../manifestService');
1111
const dsConfig = require('../../../config/index.js').config;
@@ -94,10 +94,11 @@ eg001SetConnectedFields.createController = async (req, res) => {
9494

9595
const args = {
9696
accessToken: req.user.accessToken,
97-
basePath: 'https://api-d.docusign.com',
97+
basePath: dsConfig.iamBasePath,
9898
accountId: req.session.accountId,
9999
};
100-
const tabGroups = await getTabGroups(args);
100+
let tabGroups = await getTabGroups(args);
101+
tabGroups = filterData(tabGroups);
101102

102103
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
103104
if (tabGroups.length === 0) {

lib/connectedFields/examples/setConnectedFields.js

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,31 @@
44
* @author DocuSign
55
*/
66

7-
const axios = require('axios');
87
const fs = require('fs-extra');
98
const docusign = require('docusign-esign');
9+
const iam = require('@docusign/iam-sdk');
1010

1111
/**
1212
* This function does the work of retrieving the tab groups
1313
* @param {object} args
1414
*/
15+
//ds-snippet-start:ConnectedFields1Step2
1516
const getTabGroups = async (args) => {
16-
//ds-snippet-start:ConnectedFields1Step2
17-
const headers = {
18-
Authorization: 'Bearer ' + args.accessToken,
19-
Accept: 'application/json',
20-
'Content-Type': 'application/json',
21-
};
22-
//ds-snippet-end:ConnectedFields1Step2
23-
24-
//ds-snippet-start:ConnectedFields1Step3
25-
const url = `${args.basePath}/v1/accounts/${args.accountId}/connected-fields/tab-groups`;
26-
const response = await axios.get(url, { headers });
27-
const responseData = response.data;
17+
const client = new iam.IamClient({ accessToken: args.accessToken, serverURL: args.basePath });
18+
return await client.connectedFields.tabInfo.getConnectedFieldsTabGroups({ accountId: args.accountId });
19+
};
20+
//ds-snippet-end:ConnectedFields1Step2
2821

29-
const filteredApps = responseData.filter(app =>
22+
//ds-snippet-start:ConnectedFields1Step3
23+
const filterData = (connectedFields) => {
24+
return connectedFields.filter(app =>
3025
app.tabs?.some(tab =>
3126
(tab.extensionData?.actionContract?.includes('Verify')) ||
3227
(tab.tabLabel?.includes('connecteddata'))
3328
)
3429
);
35-
36-
let uniqueApps = [];
37-
if (filteredApps.length > 0) {
38-
uniqueApps = [...new Map(responseData.map(item => [item.appId, item])).values()];
39-
}
40-
//ds-snippet-end:ConnectedFields1Step3
41-
42-
return uniqueApps;
4330
};
31+
//ds-snippet-end:ConnectedFields1Step3
4432

4533
/**
4634
* This function does the work of creating the envelope
@@ -58,11 +46,8 @@ const sendEnvelope = async (args) => {
5846
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + args.accessToken);
5947
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
6048

61-
// Step 1. Make the envelope request body
6249
const envelope = makeEnvelope(args.envelopeArgs);
6350

64-
// Step 2. call Envelopes::create API method
65-
// Exceptions will be caught by the calling function
6651
const results = await envelopesApi.createEnvelope(args.accountId, {
6752
envelopeDefinition: envelope,
6853
});
@@ -234,4 +219,4 @@ const makeTextTab = (verificationData, textTabsCount) => ({
234219
});
235220
//ds-snippet-end:ConnectedFields1Step5
236221

237-
module.exports = { getTabGroups, sendEnvelope, extractVerificationData };
222+
module.exports = { getTabGroups, filterData, sendEnvelope, extractVerificationData };
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @file
3+
* Example 001: List agreements
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const { listAgreements } = require('../examples/listAgreements');
9+
const { getExampleByNumber } = require('../../manifestService');
10+
const dsConfig = require('../../../config/index.js').config;
11+
const { API_TYPES } = require('../../utils.js');
12+
13+
const eg001ListAgreements = exports;
14+
const exampleNumber = 1;
15+
const eg = `nav00${exampleNumber}`; // This example reference.
16+
const api = API_TYPES.NAVIGATOR;
17+
const mustAuthenticate = '/ds/mustAuthenticate';
18+
const minimumBufferMin = 3;
19+
20+
/**
21+
* Get the list of agreements
22+
* @param {object} req Request obj
23+
* @param {object} res Response obj
24+
*/
25+
eg001ListAgreements.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+
accessToken: req.user.accessToken,
40+
basePath: dsConfig.iamBasePath,
41+
accountId: req.session.accountId,
42+
};
43+
44+
let results = null;
45+
try {
46+
results = await listAgreements(args);
47+
} catch (error) {
48+
const errorBody = error?.body || error?.response?.body;
49+
// we can pull the DocuSign error code and message from the response body
50+
const errorCode = errorBody?.errorCode;
51+
const errorMessage = errorBody?.message;
52+
// In production, may want to provide customized error messages and
53+
// remediation advice to the user.
54+
res.render('pages/error', { err: error, errorCode, errorMessage });
55+
}
56+
if (results) {
57+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
58+
res.render('pages/example_done', {
59+
title: example.ExampleName,
60+
message: example.ResultsPageText,
61+
json: JSON.stringify(results).replace(/'/g, ''),
62+
});
63+
}
64+
};
65+
66+
/**
67+
* Form page for this application
68+
*/
69+
eg001ListAgreements.getController = async (req, res) => {
70+
// Check that the authentication token is ok with a long buffer time.
71+
// If needed, now is the best time to ask the user to authenticate
72+
// since they have not yet entered any information into the form.
73+
const isTokenOK = req.dsAuth.checkToken();
74+
if (!isTokenOK) {
75+
// Save the current operation so it will be resumed after authentication
76+
req.dsAuth.setEg(req, eg);
77+
return res.redirect(mustAuthenticate);
78+
}
79+
80+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
81+
const sourceFile =
82+
path.basename(__filename)[5].toLowerCase() +
83+
path.basename(__filename).substr(6);
84+
res.render('pages/navigator-examples/eg001ListAgreements', {
85+
eg: eg,
86+
csrfToken: req.csrfToken(),
87+
example: example,
88+
sourceFile: sourceFile,
89+
sourceUrl: dsConfig.githubExampleUrl + 'navigator/examples/' + sourceFile,
90+
documentation: dsConfig.documentation + eg,
91+
showDoc: dsConfig.documentation
92+
});
93+
};
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* @file
3+
* Example 002: Get single agreement
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const { listAgreements, getAgreement } = require('../examples/getSingleAgreement');
9+
const validator = require('validator');
10+
const { getExampleByNumber } = require('../../manifestService');
11+
const dsConfig = require('../../../config/index.js').config;
12+
const { API_TYPES } = require('../../utils.js');
13+
14+
const eg002GetSingleAgreement = exports;
15+
const exampleNumber = 2;
16+
const eg = `nav00${exampleNumber}`; // This example reference.
17+
const api = API_TYPES.NAVIGATOR;
18+
const mustAuthenticate = '/ds/mustAuthenticate';
19+
const minimumBufferMin = 3;
20+
21+
/**
22+
* Get a single agreement
23+
* @param {object} req Request obj
24+
* @param {object} res Response obj
25+
*/
26+
eg002GetSingleAgreement.createController = async (req, res) => {
27+
// Step 1. Check the token
28+
// At this point we should have a good token. But we
29+
// double-check here to enable a better UX to the user.
30+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
31+
if (!isTokenOK) {
32+
req.flash('info', 'Sorry, you need to re-authenticate.');
33+
// Save the current operation so it will be resumed after authentication
34+
req.dsAuth.setEg(req, eg);
35+
return res.redirect(mustAuthenticate);
36+
}
37+
38+
// Step 2. Call the worker method
39+
const { body } = req;
40+
const args = {
41+
accessToken: req.user.accessToken,
42+
basePath: dsConfig.iamBasePath,
43+
accountId: req.session.accountId,
44+
agreementId: validator.escape(body.agreementId),
45+
};
46+
47+
let results = null;
48+
try {
49+
results = await getAgreement(args);
50+
} catch (error) {
51+
const errorBody = error?.body || error?.response?.body;
52+
// we can pull the DocuSign error code and message from the response body
53+
const errorCode = errorBody?.errorCode;
54+
const errorMessage = 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 });
58+
}
59+
if (results) {
60+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
61+
res.render('pages/example_done', {
62+
title: example.ExampleName,
63+
message: example.ResultsPageText,
64+
json: JSON.stringify(results).replace(/'/g, ''),
65+
});
66+
}
67+
};
68+
69+
/**
70+
* Form page for this application
71+
*/
72+
eg002GetSingleAgreement.getController = async (req, res) => {
73+
// Check that the authentication token is ok with a long buffer time.
74+
// If needed, now is the best time to ask the user to authenticate
75+
// since they have not yet entered any information into the form.
76+
const isTokenOK = req.dsAuth.checkToken();
77+
if (!isTokenOK) {
78+
// Save the current operation so it will be resumed after authentication
79+
req.dsAuth.setEg(req, eg);
80+
return res.redirect(mustAuthenticate);
81+
}
82+
83+
const args = {
84+
accessToken: req.user.accessToken,
85+
basePath: dsConfig.iamBasePath,
86+
accountId: req.session.accountId,
87+
};
88+
89+
let agreements = null;
90+
try {
91+
agreements = await listAgreements(args);
92+
} catch (error) {
93+
const errorBody = error?.body || error?.response?.body;
94+
// we can pull the DocuSign error code and message from the response body
95+
const errorCode = errorBody?.errorCode;
96+
const errorMessage = errorBody?.message;
97+
// In production, may want to provide customized error messages and
98+
// remediation advice to the user.
99+
return res.render('pages/error', { err: error, errorCode, errorMessage });
100+
}
101+
102+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
103+
const sourceFile =
104+
path.basename(__filename)[5].toLowerCase() +
105+
path.basename(__filename).substr(6);
106+
res.render('pages/navigator-examples/eg002GetSingleAgreement', {
107+
eg: eg,
108+
csrfToken: req.csrfToken(),
109+
example: example,
110+
sourceFile: sourceFile,
111+
sourceUrl: dsConfig.githubExampleUrl + 'navigator/examples/' + sourceFile,
112+
documentation: dsConfig.documentation + eg,
113+
showDoc: dsConfig.documentation,
114+
agreements: agreements,
115+
});
116+
};

lib/navigator/controllers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
module.exports.eg001Navigator = require('./eg001ListAgreements');
2+
module.exports.eg002Navigator = require('./eg002GetSingleAgreement');
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @file
3+
* Example 002: Get a single agreement
4+
* @author DocuSign
5+
*/
6+
7+
const iam = require('@docusign/iam-sdk');
8+
9+
const listAgreements = async (args) => {
10+
//ds-snippet-start:Navigator2Step2
11+
const client = new iam.IamClient({ accessToken: args.accessToken, serverURL: args.basePath });
12+
//ds-snippet-end:Navigator2Step2
13+
return await client.navigator.agreements.getAgreementsList({ accountId: args.accountId });
14+
};
15+
16+
//ds-snippet-start:Navigator2Step3
17+
const getAgreement = async (args) => {
18+
const client = new iam.IamClient({ accessToken: args.accessToken, serverURL: args.basePath });
19+
return await client.navigator.agreements.getAgreement({ accountId: args.accountId, agreementId: args.agreementId });
20+
};
21+
22+
module.exports = { listAgreements, getAgreement };
23+
//ds-snippet-end:Navigator2Step3
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @file
3+
* Example 001: List agreements
4+
* @author DocuSign
5+
*/
6+
7+
const iam = require('@docusign/iam-sdk');
8+
9+
const listAgreements = async (args) => {
10+
//ds-snippet-start:Navigator1Step2
11+
const client = new iam.IamClient({ accessToken: args.accessToken, serverURL: args.basePath });
12+
//ds-snippet-end:Navigator1Step2
13+
//ds-snippet-start:Navigator1Step3
14+
return await client.navigator.agreements.getAgreementsList({ accountId: args.accountId });
15+
};
16+
17+
module.exports = { listAgreements };
18+
//ds-snippet-end:Navigator1Step3

lib/utils.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ const API_TYPES = {
2323
CONNECT: 'Connect',
2424
WEBFORMS: 'WebForms',
2525
NOTARY: 'Notary',
26-
CONNECTED_FIELDS: 'ConnectedFields'
26+
CONNECTED_FIELDS: 'ConnectedFields',
27+
NAVIGATOR: 'Navigator',
2728
};
2829

2930
async function isCFR(accessToken, accountId, basePath) {

0 commit comments

Comments
 (0)