Skip to content

Commit c3601bc

Browse files
authored
Merge pull request #143 from docusign/feature/focused-view-code-example
Add focused view code example
2 parents 021e524 + df9a981 commit c3601bc

File tree

6 files changed

+405
-1
lines changed

6 files changed

+405
-1
lines changed

index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const {
2828
eg016, eg017, eg018, eg019, eg020, eg022, eg023,
2929
eg024, eg025, eg026, eg027, eg028, eg029, eg030,
3030
eg031, eg032, eg033, eg034, eg035, eg036, eg037,
31-
eg038, eg039, eg040, eg041, eg042, eg043
31+
eg038, eg039, eg040, eg041, eg042, eg043, eg044
3232
} = require("./lib/eSignature/controllers");
3333

3434
const {
@@ -264,6 +264,8 @@ app.get('/eg001', eg001.getController)
264264
.get('/eg043reauthenticate', eg043.reauthenticate)
265265
.get('/eg043envelopes', eg043.listEnvelopes)
266266
.post('/eg043', eg043.createController)
267+
.get('/eg044', eg044.getController)
268+
.post('/eg044', eg044.createController)
267269

268270
function dsLoginCB1(req, res, next) { req.dsAuthCodeGrant.oauth_callback1(req, res, next) }
269271
function dsLoginCB2(req, res, next) { req.dsAuthCodeGrant.oauth_callback2(req, res, next) }
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* @file
3+
* Example 044: Focused view
4+
* @author DocuSign
5+
*/
6+
7+
const path = require("path");
8+
const { sendEnvelope } = require("../examples/focusedView");
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 eg044FocusedView = exports;
15+
const exampleNumber = 44;
16+
const eg = `eg0${exampleNumber}`; // This example reference.
17+
const api = API_TYPES.ESIGNATURE;
18+
const mustAuthenticate = "/ds/mustAuthenticate";
19+
const minimumBufferMin = 3;
20+
const signerClientId = 1000; // The id of the signer within this application.
21+
const demoDocsPath = path.resolve(__dirname, "../../../demo_documents");
22+
const pdf1File = "World_Wide_Corp_lorem.pdf";
23+
const dsReturnUrl = dsConfig.appUrl + "/ds-return";
24+
const dsPingUrl = dsConfig.appUrl + "/"; // Url that will be pinged by the DocuSign signing via Ajax
25+
26+
/**
27+
* Create the envelope, the embedded signing, and then redirect to the DocuSign signing
28+
* @param {object} req Request obj
29+
* @param {object} res Response obj
30+
*/
31+
eg044FocusedView.createController = async (req, res) => {
32+
// Step 1. Check the token
33+
// At this point we should have a good token. But we
34+
// double-check here to enable a better UX to the user.
35+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
36+
if (!isTokenOK) {
37+
req.flash("info", "Sorry, you need to re-authenticate.");
38+
// Save the current operation so it will be resumed after authentication
39+
req.dsAuth.setEg(req, eg);
40+
return res.redirect(mustAuthenticate);
41+
}
42+
43+
// Step 2. Call the worker method
44+
const { body } = req;
45+
const envelopeArgs = {
46+
signerEmail: validator.escape(body.signerEmail),
47+
signerName: validator.escape(body.signerName),
48+
signerClientId: signerClientId,
49+
dsReturnUrl: dsReturnUrl,
50+
dsPingUrl: dsPingUrl,
51+
docFile: path.resolve(demoDocsPath, pdf1File),
52+
};
53+
const args = {
54+
accessToken: req.user.accessToken,
55+
basePath: req.session.basePath,
56+
accountId: req.session.accountId,
57+
envelopeArgs: envelopeArgs,
58+
};
59+
let results = null;
60+
61+
try {
62+
results = await sendEnvelope(args);
63+
} catch (error) {
64+
const errorBody = error && error.response && error.response.body;
65+
// we can pull the DocuSign error code and message from the response body
66+
const errorCode = errorBody && errorBody.errorCode;
67+
const errorMessage = errorBody && errorBody.message;
68+
// In production, may want to provide customized error messages and
69+
// remediation advice to the user.
70+
res.render("pages/error", { err: error, errorCode, errorMessage });
71+
}
72+
if (results) {
73+
req.session.envelopeId = results.envelopeId; // Save for use by other examples
74+
75+
// Redirect the user to the embedded signing
76+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
77+
return res.render("pages/examples/eg044Embed", {
78+
example: example,
79+
integrationKey: dsConfig.dsClientId,
80+
url: results.redirectUrl,
81+
});
82+
}
83+
};
84+
85+
/**
86+
* Form page for this application
87+
*/
88+
eg044FocusedView.getController = async (req, res) => {
89+
// Check that the authentication token is ok with a long buffer time.
90+
// If needed, now is the best time to ask the user to authenticate
91+
// since they have not yet entered any information into the form.
92+
const isTokenOK = req.dsAuth.checkToken();
93+
if (!isTokenOK) {
94+
// Save the current operation so it will be resumed after authentication
95+
req.dsAuth.setEg(req, eg);
96+
return res.redirect(mustAuthenticate);
97+
}
98+
99+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
100+
return res.render("pages/examples/eg044FocusedView", {
101+
eg: eg,
102+
csrfToken: req.csrfToken(),
103+
example: example,
104+
sourceFile: path.basename(__filename),
105+
sourceUrl: "https://github.com/docusign/code-examples-node/blob/master/embeddedSigning.js",
106+
documentation: dsConfig.documentation + eg,
107+
showDoc: dsConfig.documentation,
108+
});
109+
};

lib/eSignature/controllers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ module.exports.eg040 = require('./eg040SetDocumentVisibility');
4040
module.exports.eg041 = require('./eg041CFREmbeddedSigning');
4141
module.exports.eg042 = require('./eg042DocumentGeneration');
4242
module.exports.eg043 = require('./eg043SharedAccess');
43+
module.exports.eg044 = require('./eg044FocusedView');
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/**
2+
* @file
3+
* Example 044: Focused view
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 and the
12+
* embedded signing
13+
* @param {object} args
14+
*/
15+
const sendEnvelope = async (args) => {
16+
// Data for this method
17+
// args.basePath
18+
// args.accessToken
19+
// args.accountId
20+
21+
//ds-snippet-start:eSign44Step3
22+
let dsApiClient = new docusign.ApiClient();
23+
dsApiClient.setBasePath(args.basePath);
24+
dsApiClient.addDefaultHeader("Authorization", "Bearer " + args.accessToken);
25+
let envelopesApi = new docusign.EnvelopesApi(dsApiClient),
26+
results = null;
27+
28+
// Make the envelope request body
29+
let envelope = makeEnvelope(args.envelopeArgs);
30+
31+
// Call Envelopes::create API method
32+
// Exceptions will be caught by the calling function
33+
results = await envelopesApi.createEnvelope(args.accountId, {
34+
envelopeDefinition: envelope,
35+
});
36+
//ds-snippet-end:eSign44Step3
37+
38+
let envelopeId = results.envelopeId;
39+
console.log(`Envelope was created. EnvelopeId ${envelopeId}`);
40+
41+
// Create the recipient view, the embedded signing
42+
//ds-snippet-start:eSign44Step5
43+
let viewRequest = makeRecipientViewRequest(args.envelopeArgs);
44+
// Call the CreateRecipientView API
45+
// Exceptions will be caught by the calling function
46+
results = await envelopesApi.createRecipientView(args.accountId, envelopeId, {
47+
recipientViewRequest: viewRequest,
48+
});
49+
50+
return { envelopeId: envelopeId, redirectUrl: results.url };
51+
};
52+
//ds-snippet-end:eSign44Step5
53+
54+
/**
55+
* Creates envelope
56+
* @function
57+
* @param {Object} args parameters for the envelope:
58+
* @returns {Envelope} An envelope definition
59+
* @private
60+
*/
61+
62+
//ds-snippet-start:eSign44Step2
63+
function makeEnvelope(args) {
64+
// Data for this method
65+
// args.signerEmail
66+
// args.signerName
67+
// args.signerClientId
68+
// docFile
69+
70+
// document 1 (pdf) has tag /sn1/
71+
//
72+
// The envelope has one recipients.
73+
// recipient 1 - signer
74+
75+
let docPdfBytes;
76+
// read file from a local directory
77+
// The read could raise an exception if the file is not available!
78+
docPdfBytes = fs.readFileSync(args.docFile);
79+
80+
// create the envelope definition
81+
let env = new docusign.EnvelopeDefinition();
82+
env.emailSubject = "Please sign this document";
83+
84+
// add the documents
85+
let doc1 = new docusign.Document(),
86+
doc1b64 = Buffer.from(docPdfBytes).toString("base64");
87+
doc1.documentBase64 = doc1b64;
88+
doc1.name = "Lorem Ipsum"; // can be different from actual file name
89+
doc1.fileExtension = "pdf";
90+
doc1.documentId = "3";
91+
92+
// The order in the docs array determines the order in the envelope
93+
env.documents = [doc1];
94+
95+
// Create a signer recipient to sign the document, identified by name and email
96+
// We set the clientUserId to enable embedded signing for the recipient
97+
// We're setting the parameters via the object creation
98+
let signer1 = docusign.Signer.constructFromObject({
99+
email: args.signerEmail,
100+
name: args.signerName,
101+
clientUserId: args.signerClientId,
102+
recipientId: 1,
103+
});
104+
105+
// Create signHere fields (also known as tabs) on the documents,
106+
// We're using anchor (autoPlace) positioning
107+
//
108+
// The DocuSign platform seaches throughout your envelope's
109+
// documents for matching anchor strings.
110+
let signHere1 = docusign.SignHere.constructFromObject({
111+
anchorString: "/sn1/",
112+
anchorYOffset: "10",
113+
anchorUnits: "pixels",
114+
anchorXOffset: "20",
115+
});
116+
// Tabs are set per recipient / signer
117+
let signer1Tabs = docusign.Tabs.constructFromObject({
118+
signHereTabs: [signHere1],
119+
});
120+
signer1.tabs = signer1Tabs;
121+
122+
// Add the recipient to the envelope object
123+
let recipients = docusign.Recipients.constructFromObject({
124+
signers: [signer1],
125+
});
126+
env.recipients = recipients;
127+
128+
// Request that the envelope be sent by setting |status| to "sent".
129+
// To request that the envelope be created as a draft, set to "created"
130+
env.status = "sent";
131+
132+
return env;
133+
}
134+
//ds-snippet-end:eSign44Step2
135+
136+
//ds-snippet-start:eSign44Step4
137+
function makeRecipientViewRequest(args) {
138+
// Data for this method
139+
// args.dsReturnUrl
140+
// args.signerEmail
141+
// args.signerName
142+
// args.signerClientId
143+
// args.dsPingUrl
144+
145+
let viewRequest = new docusign.RecipientViewRequest();
146+
147+
// Set the url where you want the recipient to go once they are done signing
148+
// should typically be a callback route somewhere in your app.
149+
// The query parameter is included as an example of how
150+
// to save/recover state information during the redirect to
151+
// the DocuSign signing. It's usually better to use
152+
// the session mechanism of your web framework. Query parameters
153+
// can be changed/spoofed very easily.
154+
viewRequest.returnUrl = args.dsReturnUrl + "?state=123";
155+
156+
// How has your app authenticated the user? In addition to your app's
157+
// authentication, you can include authenticate steps from DocuSign.
158+
// Eg, SMS authentication
159+
viewRequest.authenticationMethod = "none";
160+
161+
// Recipient information must match embedded recipient info
162+
// we used to create the envelope.
163+
viewRequest.email = args.signerEmail;
164+
viewRequest.userName = args.signerName;
165+
viewRequest.clientUserId = args.signerClientId;
166+
167+
// DocuSign recommends that you redirect to DocuSign for the
168+
// embedded signing. There are multiple ways to save state.
169+
// To maintain your application's session, use the pingUrl
170+
// parameter. It causes the DocuSign signing web page
171+
// (not the DocuSign server) to send pings via AJAX to your
172+
// app,
173+
viewRequest.pingFrequency = 600; // seconds
174+
// NOTE: The pings will only be sent if the pingUrl is an https address
175+
viewRequest.pingUrl = args.dsPingUrl; // optional setting
176+
viewRequest.frameAncestors = ["http://localhost:3000", "https://apps-d.docusign.com"];
177+
viewRequest.messageOrigins = ["https://apps-d.docusign.com"]
178+
179+
return viewRequest;
180+
}
181+
//ds-snippet-end:eSign44Step4
182+
183+
module.exports = { sendEnvelope, makeEnvelope, makeRecipientViewRequest };

0 commit comments

Comments
 (0)