Skip to content

Commit a8abd91

Browse files
add notary example (#206)
* add notary example * update example number * Update sendThirdPartyNotary.js * Update testHelpers.js * Update index.js * codeDepot markers and fixing properties --------- Co-authored-by: Paige Rossi <[email protected]>
1 parent 08a151f commit a8abd91

File tree

9 files changed

+360
-2
lines changed

9 files changed

+360
-2
lines changed

Diff for: index.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const {
5757

5858
const { eg001connect } = require('./lib/connect/controllers');
5959
const { eg001webforms } = require('./lib/webforms/controllers');
60+
const { eg004notary } = require('./lib/notary/controllers');
6061

6162
const PORT = process.env.PORT || 3000;
6263
const HOST = process.env.HOST || 'localhost';
@@ -285,6 +286,9 @@ app.get('/weg001', eg001webforms.getController)
285286
.post('/weg001', eg001webforms.createWebFormTemplate)
286287
.post('/weg001webForm', eg001webforms.createWebFormInstance);
287288

289+
app.get('/neg004', eg004notary.getController)
290+
.post('/neg004', eg004notary.createController)
291+
288292

289293
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next); }
290294
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next); }
@@ -333,8 +337,11 @@ const ADMIN_SCOPES = [
333337
const WEBFORMS_SCOPES = [
334338
'webforms_read', 'webforms_instance_read', 'webforms_instance_write'
335339
];
340+
const NOTARY_SCOPES = [
341+
'signature', 'organization_read', 'notary_read', 'notary_write'
342+
];
336343

337-
const scope = [...ROOM_SCOPES, ...CLICK_SCOPES, ...MONITOR_SCOPES, ...ADMIN_SCOPES, ...SCOPES, ...WEBFORMS_SCOPES];
344+
const scope = [...ROOM_SCOPES, ...CLICK_SCOPES, ...MONITOR_SCOPES, ...ADMIN_SCOPES, ...SCOPES, ...WEBFORMS_SCOPES, ...NOTARY_SCOPES];
338345

339346
// Configure passport for DocusignStrategy
340347
const docusignStrategyOptions = {

Diff for: lib/notary/controllers/eg004SendThirdPartyNotary.js

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @file
3+
* Example 004: Send third party notary
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.js');
11+
const dsConfig = require('../../../config/index.js').config;
12+
const { sendEnvelope } = require('../examples/sendThirdPartyNotary.js');
13+
14+
const eg004SendThirdPartyNotary = exports;
15+
const exampleNumber = 4;
16+
const eg = `neg00${exampleNumber}`; // This example reference.
17+
const api = API_TYPES.NOTARY;
18+
const mustAuthenticate = '/ds/mustAuthenticate';
19+
const minimumBufferMin = 3;
20+
21+
/**
22+
* Create the envelope
23+
* @param {object} req Request obj
24+
* @param {object} res Response obj
25+
*/
26+
eg004SendThirdPartyNotary.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 envelopeArgs = {
41+
signerEmail: validator.escape(body.signerEmail),
42+
signerName: validator.escape(body.signerName),
43+
status: 'sent',
44+
docFile: ''
45+
};
46+
const args = {
47+
accessToken: req.user.accessToken,
48+
basePath: req.session.basePath,
49+
accountId: req.session.accountId,
50+
envelopeArgs: envelopeArgs,
51+
};
52+
let results = null;
53+
54+
try {
55+
results = await sendEnvelope(args);
56+
} catch (error) {
57+
const errorBody = error && error.response && error.response.body;
58+
// we can pull the DocuSign error code and message from the response body
59+
const errorCode = errorBody && errorBody.errorCode;
60+
const errorMessage = errorBody && errorBody.message;
61+
// In production, may want to provide customized error messages and
62+
// remediation advice to the user.
63+
res.render('pages/error', { err: error, errorCode, errorMessage });
64+
}
65+
if (results) {
66+
req.session.envelopeId = results.envelopeId; // Save for use by other examples
67+
// which need an envelopeId
68+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
69+
res.render('pages/example_done', {
70+
title: example.ExampleName,
71+
message: formatString(example.ResultsPageText, results.envelopeId),
72+
});
73+
}
74+
};
75+
76+
/**
77+
* Form page for this application
78+
*/
79+
eg004SendThirdPartyNotary.getController = (req, res) => {
80+
// Check that the authentication token is ok with a long buffer time.
81+
// If needed, now is the best time to ask the user to authenticate
82+
// since they have not yet entered any information into the form.
83+
const isTokenOK = req.dsAuth.checkToken();
84+
if (!isTokenOK) {
85+
// Save the current operation so it will be resumed after authentication
86+
req.dsAuth.setEg(req, eg);
87+
return res.redirect(mustAuthenticate);
88+
}
89+
90+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
91+
const sourceFile =
92+
path.basename(__filename)[5].toLowerCase() +
93+
path.basename(__filename).substr(6);
94+
res.render('pages/notary-examples/eg004SendThirdPartyNotary', {
95+
eg: eg,
96+
csrfToken: req.csrfToken(),
97+
example: example,
98+
sourceFile: sourceFile,
99+
sourceUrl: dsConfig.githubExampleUrl + 'notary/examples/' + sourceFile,
100+
documentation: dsConfig.documentation + eg,
101+
showDoc: dsConfig.documentation,
102+
});
103+
};

Diff for: lib/notary/controllers/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports.eg004notary = require('./eg004SendThirdPartyNotary');

Diff for: lib/notary/examples/sendThirdPartyNotary.js

+216
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/**
2+
* @file
3+
* Example 004: Send third party notary
4+
* @author DocuSign
5+
*/
6+
7+
const fs = require('fs-extra');
8+
const docusign = require('docusign-esign');
9+
10+
/**
11+
* This function does the work of creating the envelope
12+
*/
13+
14+
const sendEnvelope = async (args) => {
15+
// Data for this method
16+
// args.basePath
17+
// args.accessToken
18+
// args.accountId
19+
20+
//ds-snippet-start:Notary4Step2
21+
let dsApiClient = new docusign.ApiClient();
22+
dsApiClient.setBasePath(args.basePath);
23+
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + args.accessToken);
24+
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
25+
//ds-snippet-end:Notary4Step2
26+
let results = null;
27+
28+
// Make the envelope request body
29+
//ds-snippet-start:Notary4Step3
30+
let envelope = makeEnvelope(args.envelopeArgs);
31+
//ds-snippet-end:Notary4Step3
32+
33+
// Call the Envelopes::create API method
34+
// Exceptions will be caught by the calling function
35+
//ds-snippet-start:Notary4Step4
36+
results = await envelopesApi.createEnvelope(args.accountId, {
37+
envelopeDefinition: envelope,
38+
});
39+
let envelopeId = results.envelopeId;
40+
//ds-snippet-end:Notary4Step4
41+
42+
console.log(`Envelope was created. EnvelopeId ${envelopeId}`);
43+
return { envelopeId: envelopeId };
44+
};
45+
46+
/**
47+
* Creates envelope
48+
* @function
49+
* @param {Object} args parameters for the envelope
50+
* @returns {Envelope} An envelope definition
51+
* @private
52+
*/
53+
54+
//ds-snippet-start:Notary4Step3
55+
function makeEnvelope(args) {
56+
// Data for this method
57+
// args.signerEmail
58+
// args.signerName
59+
// args.status
60+
61+
// document 1 (html) has tag **signature_1**
62+
//
63+
// The envelope has two recipients.
64+
// recipient 1 - signer
65+
// The envelope will be sent first to the signer.
66+
// After it is signed, a copy is sent to the cc person.
67+
68+
// create the envelope definition
69+
let env = new docusign.EnvelopeDefinition();
70+
env.emailSubject = 'Please sign this document set';
71+
72+
// add the documents
73+
let doc1 = new docusign.Document();
74+
let doc1b64 = Buffer.from(document1(args)).toString('base64');
75+
doc1.documentBase64 = doc1b64;
76+
doc1.name = 'Order acknowledgement'; // can be different from actual file name
77+
doc1.fileExtension = 'html'; // Source data format. Signed docs are always pdf.
78+
doc1.documentId = '1'; // a label used to reference the doc
79+
80+
// The order in the docs array determines the order in the envelope
81+
env.documents = [doc1];
82+
83+
// create a signer recipient to sign the document, identified by name and email
84+
// We're setting the parameters via the object constructor
85+
let signer1 = docusign.Signer.constructFromObject({
86+
email: args.signerEmail,
87+
name: args.signerName,
88+
recipientId: '2',
89+
routingOrder: '1',
90+
notaryId: '1',
91+
clientUserId: '1000',
92+
});
93+
// routingOrder (lower means earlier) determines the order of deliveries
94+
// to the recipients. Parallel routing order is supported by using the
95+
// same integer as the order for two or more recipients.
96+
97+
// Create signHere fields (also known as tabs) on the documents,
98+
// We're using anchor (autoPlace) positioning
99+
//
100+
// The DocuSign platform searches throughout your envelope's
101+
// documents for matching anchor strings. So the
102+
// use the same anchor string for their "signer 1" tabs.
103+
let signHere1 = docusign.SignHere.constructFromObject({
104+
xPosition: '200',
105+
yPosition: '235',
106+
pageNumber: '1',
107+
documentId: '1'
108+
});
109+
let signHere2 = docusign.SignHere.constructFromObject({
110+
stampType: 'stamp',
111+
documentId: '1',
112+
xPosition: '200',
113+
yPosition: '150',
114+
pageNumber: '1',
115+
116+
});
117+
// Tabs are set per recipient / signer
118+
let signer1Tabs = docusign.Tabs.constructFromObject({
119+
signHereTabs: [signHere1, signHere2],
120+
});
121+
signer1.tabs = signer1Tabs;
122+
123+
const notarySealTab = {
124+
xPosition: '300',
125+
yPosition: '235',
126+
documentId: '1',
127+
pageNumber: '1',
128+
};
129+
130+
const notarySignHereTab = {
131+
xPosition: '300',
132+
yPosition: '150',
133+
documentId: '1',
134+
pageNumber: '1',
135+
};
136+
137+
const notaryTabs = {
138+
signHereTabs: [notarySignHereTab],
139+
notarySealTabs: [notarySealTab],
140+
};
141+
142+
const notaryRecipient = [
143+
{
144+
name: 'Notary',
145+
recipientId: '1',
146+
routingOrder: '1',
147+
tabs: notaryTabs,
148+
notaryType: 'remote',
149+
notarySourceType: 'thirdparty',
150+
notaryThirdPartyPartner: 'onenotary',
151+
recipientSignatureProviders: [
152+
{
153+
sealDocumentsWithTabsOnly: 'false',
154+
signatureProviderName: 'ds_authority_idv',
155+
signatureProviderOptions: {}
156+
}
157+
],
158+
},
159+
];
160+
161+
// Add the recipients to the envelope object
162+
let recipients = docusign.Recipients.constructFromObject({
163+
signers: [signer1],
164+
notaries: [...notaryRecipient],
165+
});
166+
env.recipients = recipients;
167+
168+
// Request that the envelope be sent by setting |status| to "sent".
169+
// To request that the envelope be created as a draft, set to "created"
170+
env.status = args.status;
171+
172+
return env;
173+
}
174+
//ds-snippet-end:Notary4Step3
175+
176+
/**
177+
* Creates document 1
178+
* @function
179+
* @private
180+
* @param {Object} args parameters for the envelope
181+
* @returns {string} A document in HTML format
182+
*/
183+
184+
function document1(args) {
185+
// Data for this method
186+
// args.signerEmail
187+
// args.signerName
188+
// args.ccEmail
189+
// args.ccName
190+
191+
return `
192+
<!DOCTYPE html>
193+
<html>
194+
<head>
195+
<meta charset="UTF-8">
196+
</head>
197+
<body style="font-family:sans-serif;margin-left:2em;">
198+
<h1 style="font-family: 'Trebuchet MS', Helvetica, sans-serif;
199+
color: darkblue;margin-bottom: 0;">World Wide Corp</h1>
200+
<h2 style="font-family: 'Trebuchet MS', Helvetica, sans-serif;
201+
margin-top: 0px;margin-bottom: 3.5em;font-size: 1em;
202+
color: darkblue;">Order Processing Division</h2>
203+
<h4>Ordered by ${args.signerName}</h4>
204+
<p style="margin-top:0em; margin-bottom:0em;">Email: ${args.signerEmail}</p>
205+
<p style="margin-top:0em; margin-bottom:0em;">Copy to: ${args.ccName}, ${args.ccEmail}</p>
206+
<p style="margin-top:3em;">
207+
Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. Donut jujubes oat cake jelly-o. Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake.
208+
</p>
209+
<!-- Note the anchor tag for the signature field is in white. -->
210+
<h3 style="margin-top:3em;">Agreed: <span style="color:white;">**signature_1**/</span></h3>
211+
</body>
212+
</html>
213+
`;
214+
}
215+
216+
module.exports = { sendEnvelope, makeEnvelope, document1 };

Diff for: lib/utils.js

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const API_TYPES = {
2222
ADMIN: 'Admin',
2323
CONNECT: 'Connect',
2424
WEBFORMS: 'WebForms',
25+
NOTARY: 'Notary',
2526
};
2627

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

Diff for: public/assets/search.js

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const DS_SEARCH = (function () {
77
ADMIN: "admin",
88
CONNECT: "connect",
99
WEBFORMS: "webforms",
10+
NOTARY: "notary",
1011
}
1112

1213
const processJSONData = function () {
@@ -132,6 +133,8 @@ const DS_SEARCH = (function () {
132133
return "cneg";
133134
case API_TYPES.WEBFORMS:
134135
return "weg";
136+
case API_TYPES.NOTARY:
137+
return "neg";
135138
}
136139
}
137140

Diff for: test/testHelpers.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const path = require('path');
55
const config = require('./testConfig').getConfiguration();
66
const { REDIRECT_URI, BASE_PATH, OAUTH_BASE_PATH, PRIVATE_KEY_FILENAME, EXPIRES_IN, SCOPES, CLICK_SCOPES, ROOM_SCOPES, ADMIN_SCOPES } = require('./constants');
77

8-
const TEST_TIMEOUT_MS = 20000;
8+
const TEST_TIMEOUT_MS = 30000;
99

1010
const apiClient = new docusign.ApiClient({
1111
basePath: BASE_PATH,

Diff for: views/pages/index_examples_list.ejs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
: api.Name == "Rooms" ? "r"
2020
: api.Name == "Connect" ? "cn"
2121
: api.Name == "WebForms" ? "w"
22+
: api.Name == "Notary" ? "n"
2223
: ""; %>
2324
2425
<h4

0 commit comments

Comments
 (0)