Skip to content

Commit 9c96f89

Browse files
authored
Merge pull request #146 from docusign/DEVDOCS-12522
Devdocs 12522
2 parents 84a57e1 + c308050 commit 9c96f89

File tree

5 files changed

+834
-376
lines changed

5 files changed

+834
-376
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// <copyright file="Eg044FocusedViewController.cs" company="DocuSign">
2+
// Copyright (c) DocuSign. All rights reserved.
3+
// </copyright>
4+
5+
namespace DocuSign.CodeExamples.Views
6+
{
7+
using System;
8+
using DocuSign.CodeExamples.Common;
9+
using DocuSign.CodeExamples.Controllers;
10+
using DocuSign.CodeExamples.Models;
11+
using System.Runtime.InteropServices;
12+
using Microsoft.AspNetCore.Mvc;
13+
using DocuSign.Rooms.Model;
14+
using System.Configuration;
15+
using Microsoft.Extensions.Configuration;
16+
17+
[Area("eSignature")]
18+
[Route("eg044")]
19+
public class FocusedView : EgController
20+
{
21+
private readonly string dsPingUrl;
22+
private readonly string signerClientId = "1000";
23+
private readonly string dsReturnUrl;
24+
private readonly string dsIntegrationKey;
25+
private readonly IConfiguration _configuration;
26+
27+
public FocusedView(DSConfiguration config, IConfiguration configuration, LauncherTexts launcherTexts, IRequestItemsService requestItemsService)
28+
: base(config, launcherTexts, requestItemsService)
29+
{
30+
this.dsPingUrl = config.AppUrl + "/";
31+
this.dsReturnUrl = config.AppUrl + "/dsReturn";
32+
_configuration = configuration;
33+
34+
this.CodeExampleText = this.GetExampleText("eg044", ExamplesAPIType.ESignature);
35+
this.ViewBag.title = this.CodeExampleText.ExampleName;
36+
}
37+
38+
public override string EgName => "eg044";
39+
40+
[HttpPost]
41+
[SetViewBag]
42+
public IActionResult Create(string signerEmail, string signerName)
43+
{
44+
// Data for this method
45+
// signerEmail
46+
// signerName
47+
// dsPingUrl -- class global
48+
// signerClientId -- class global
49+
// dsReturnUrl -- class global
50+
string accessToken = this.RequestItemsService.User.AccessToken;
51+
string basePath = this.RequestItemsService.Session.BasePath + "/restapi";
52+
string accountId = this.RequestItemsService.Session.AccountId;
53+
string docPDF;
54+
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
55+
{
56+
docPDF = Convert.ToBoolean(this.Config.QuickACG) ? @"../launcher-csharp/" + this.Config.DocPdf : this.Config.DocPdf;
57+
}
58+
else
59+
{
60+
docPDF = Convert.ToBoolean(this.Config.QuickACG) ? @"..\\launcher-csharp\\" + this.Config.DocPdf : this.Config.DocPdf;
61+
}
62+
63+
// Check the token with minimal buffer time.
64+
bool tokenOk = this.CheckToken(3);
65+
if (!tokenOk)
66+
{
67+
// We could store the parameters of the requested operation
68+
// so it could be restarted automatically.
69+
// But since it should be rare to have a token issue here,
70+
// we'll make the user re-enter the form data after
71+
// authentication.
72+
this.RequestItemsService.EgName = this.EgName;
73+
return this.Redirect("/ds/mustAuthenticate");
74+
}
75+
76+
// Call the method from Examples API to send envelope and generate url for focused view signing
77+
var result = global::ESignature.Examples.FocusedView.SendEnvelopeWithFocusedView(
78+
signerEmail,
79+
signerName,
80+
this.signerClientId,
81+
accessToken,
82+
basePath,
83+
accountId,
84+
docPDF,
85+
this.dsReturnUrl,
86+
this.dsPingUrl);
87+
88+
// Save for future use within the example launcher
89+
this.RequestItemsService.EnvelopeId = result.Item1;
90+
this.ViewBag.Url = result.Item2;
91+
this.ViewBag.IntegrationKey = this._configuration["DocuSign:ClientId"];
92+
93+
// Redirect the user to the Signing Ceremony
94+
return this.View("embed");
95+
}
96+
}
97+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// <copyright file="FocusedView.cs" company="DocuSign">
2+
// Copyright (c) DocuSign. All rights reserved.
3+
// </copyright>
4+
5+
namespace ESignature.Examples
6+
{
7+
using System;
8+
using System.Collections.Generic;
9+
using DocuSign.eSign.Api;
10+
using DocuSign.eSign.Client;
11+
using DocuSign.eSign.Model;
12+
using Org.BouncyCastle.Asn1;
13+
using static System.Net.WebRequestMethods;
14+
15+
/// <summary>
16+
/// Used to generate an envelope and allow user to sign it directly from the app without having to open an email.
17+
/// </summary>
18+
public static class FocusedView
19+
{
20+
/// <summary>
21+
/// Creates a new envelope, adds a single document and a signle recipient (signer) and generates a url that is used for embedded signing.
22+
/// </summary>
23+
/// <param name="signerEmail">Email address for the signer</param>
24+
/// <param name="signerName">Full name of the signer</param>
25+
/// <param name="signerClientId">A unique ID for the embedded signing session for this signer</param>
26+
/// <param name="accessToken">Access Token for API call (OAuth)</param>
27+
/// <param name="basePath">BasePath for API calls (URI)</param>
28+
/// <param name="accountId">The DocuSign Account ID (GUID or short version) for which the APIs call would be made</param>
29+
/// <param name="docPdf">String of bytes representing the document (pdf)</param>
30+
/// <param name="returnUrl">URL user will be redirected to after they sign</param>
31+
/// <param name="pingUrl">URL that DocuSign will be able to ping to incdicate signing session is active</param>
32+
/// <returns>The envelopeId (GUID) of the resulting Envelope and the URL for the embedded signing</returns>
33+
public static (string, string) SendEnvelopeWithFocusedView(
34+
string signerEmail,
35+
string signerName,
36+
string signerClientId,
37+
string accessToken,
38+
string basePath,
39+
string accountId,
40+
string docPdf,
41+
string returnUrl,
42+
string pingUrl = null)
43+
{
44+
//ds-snippet-start:eSign44Step3
45+
EnvelopeDefinition envelope = MakeEnvelope(signerEmail, signerName, signerClientId, docPdf);
46+
47+
var docuSignClient = new DocuSignClient(basePath);
48+
docuSignClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);
49+
50+
EnvelopesApi envelopesApi = new EnvelopesApi(docuSignClient);
51+
EnvelopeSummary results = envelopesApi.CreateEnvelope(accountId, envelope);
52+
string envelopeId = results.EnvelopeId;
53+
//ds-snippet-end:eSign44Step3
54+
55+
//ds-snippet-start:eSign44Step5
56+
RecipientViewRequest viewRequest = MakeRecipientViewRequest(signerEmail, signerName, returnUrl, signerClientId, pingUrl);
57+
58+
// call the CreateRecipientView API
59+
ViewUrl results1 = envelopesApi.CreateRecipientView(accountId, envelopeId, viewRequest);
60+
61+
// State can be stored/recovered using the framework's session or a
62+
// query parameter on the returnUrl (see the makeRecipientViewRequest method)
63+
string redirectUrl = results1.Url;
64+
65+
// returning both the envelopeId as well as the url to be used for embedded signing
66+
return (envelopeId, redirectUrl);
67+
//ds-snippet-end:eSign44Step5
68+
}
69+
70+
//ds-snippet-start:eSign44Step4
71+
public static RecipientViewRequest MakeRecipientViewRequest(string signerEmail, string signerName, string returnUrl, string signerClientId, string pingUrl = null)
72+
{
73+
// Data for this method
74+
// signerEmail
75+
// signerName
76+
// dsPingUrl -- class global
77+
// signerClientId -- class global
78+
// dsReturnUrl -- class global
79+
RecipientViewRequest viewRequest = new RecipientViewRequest();
80+
81+
// Set the url where you want the recipient to go once they are done signing
82+
// should typically be a callback route somewhere in your app.
83+
// The query parameter is included as an example of how
84+
// to save/recover state information during the redirect to
85+
// the DocuSign signing ceremony. It's usually better to use
86+
// the session mechanism of your web framework. Query parameters
87+
// can be changed/spoofed very easily.
88+
viewRequest.ReturnUrl = returnUrl + "?state=123";
89+
90+
// How has your app authenticated the user? In addition to your app's
91+
// authentication, you can include authenticate steps from DocuSign.
92+
// Eg, SMS authentication
93+
viewRequest.AuthenticationMethod = "none";
94+
95+
// Recipient information must match embedded recipient info
96+
// we used to create the envelope.
97+
viewRequest.Email = signerEmail;
98+
viewRequest.UserName = signerName;
99+
viewRequest.ClientUserId = signerClientId;
100+
101+
// DocuSign recommends that you redirect to DocuSign for the
102+
// Signing Ceremony. There are multiple ways to save state.
103+
// To maintain your application's session, use the pingUrl
104+
// parameter. It causes the DocuSign Signing Ceremony web page
105+
// (not the DocuSign server) to send pings via AJAX to your
106+
// app,
107+
// NOTE: The pings will only be sent if the pingUrl is an https address
108+
if (pingUrl != null)
109+
{
110+
viewRequest.PingFrequency = "600"; // seconds
111+
viewRequest.PingUrl = pingUrl; // optional setting
112+
}
113+
114+
// The FrameAncestors should include the links https://apps-d.docusign.com
115+
// for demo environments and https://apps.docusign.com for prod environments,
116+
// and the site where the document should be embedded.
117+
// The site must have a valid SSL protocol for the embed to work.
118+
// MessageOrigins includes the demo or prod link and only
119+
// takes a single string.
120+
viewRequest.FrameAncestors = new List<string> { "https://localhost:44333", "https://apps-d.docusign.com" };
121+
viewRequest.MessageOrigins = new List<string> { "https://apps-d.docusign.com" };
122+
123+
return viewRequest;
124+
}
125+
//ds-snippet-end:eSign44Step4
126+
127+
//ds-snippet-start:eSign44Step2
128+
public static EnvelopeDefinition MakeEnvelope(string signerEmail, string signerName, string signerClientId, string docPdf)
129+
{
130+
// Data for this method
131+
// signerEmail
132+
// signerName
133+
// signerClientId -- class global
134+
// Config.docPdf
135+
byte[] buffer = System.IO.File.ReadAllBytes(docPdf);
136+
137+
EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
138+
envelopeDefinition.EmailSubject = "Please sign this document";
139+
Document doc1 = new Document();
140+
141+
string doc1b64 = Convert.ToBase64String(buffer);
142+
143+
doc1.DocumentBase64 = doc1b64;
144+
doc1.Name = "Lorem Ipsum"; // can be different from actual file name
145+
doc1.FileExtension = "pdf";
146+
doc1.DocumentId = "3";
147+
148+
// The order in the docs array determines the order in the envelope
149+
envelopeDefinition.Documents = new List<Document> { doc1 };
150+
151+
// Create a signer recipient to sign the document, identified by name and email
152+
// We set the clientUserId to enable embedded signing for the recipient
153+
// We're setting the parameters via the object creation
154+
Signer signer1 = new Signer
155+
{
156+
Email = signerEmail,
157+
Name = signerName,
158+
ClientUserId = signerClientId,
159+
RecipientId = "1",
160+
};
161+
162+
// Create signHere fields (also known as tabs) on the documents,
163+
// We're using anchor (autoPlace) positioning
164+
//
165+
// The DocuSign platform searches throughout your envelope's
166+
// documents for matching anchor strings.
167+
SignHere signHere1 = new SignHere
168+
{
169+
AnchorString = "/sn1/",
170+
AnchorUnits = "pixels",
171+
AnchorXOffset = "10",
172+
AnchorYOffset = "20",
173+
};
174+
175+
// Tabs are set per recipient / signer
176+
Tabs signer1Tabs = new Tabs
177+
{
178+
SignHereTabs = new List<SignHere> { signHere1 },
179+
};
180+
signer1.Tabs = signer1Tabs;
181+
182+
// Add the recipient to the envelope object
183+
Recipients recipients = new Recipients
184+
{
185+
Signers = new List<Signer> { signer1 },
186+
};
187+
envelopeDefinition.Recipients = recipients;
188+
189+
// Request that the envelope be sent by setting |status| to "sent".
190+
// To request that the envelope be created as a draft, set to "created"
191+
envelopeDefinition.Status = "sent";
192+
193+
return envelopeDefinition;
194+
}
195+
//ds-snippet-end:eSign44Step2
196+
}
197+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
<br />
3+
<h2>Embedded document using focused view</h2>
4+
<br />
5+
6+
<div id="agreement" class="docusign-agreement"></div>
7+
8+
<p><a href="/">@Html.Raw(ViewBag.SupportingTexts.ContinueButton)</a></p>
9+
10+
@Html.Raw("<script src='https://docucdn-a.akamaihd.net/demo/1ds/libs/@embedded-js/core/latest/dist/bundle.js'></script>")
11+
12+
<script>
13+
window.DocuSign.loadDocuSign('{INTEGRATION_KEY}')
14+
.then((docusign) => {
15+
const signing = docusign.signing({
16+
url: '@ViewBag.Url',
17+
displayFormat: 'focused',
18+
//ds-snippet-start:eSign44Step6
19+
style: {
20+
/** High-level variables that mirror our existing branding APIs. Reusing the branding name here for familiarity. */
21+
branding: {
22+
primaryButton: {
23+
/** Background color of primary button */
24+
backgroundColor: '#333',
25+
/** Text color of primary button */
26+
color: '#fff',
27+
}
28+
},
29+
30+
/** High-level components we allow specific overrides for */
31+
signingNavigationButton: {
32+
finishText: 'You have finished the document! Hooray!',
33+
position: 'bottom-center'
34+
}
35+
}
36+
//ds-snippet-end:eSign44Step6
37+
});
38+
39+
signing.on('ready', (event) => {
40+
console.log('UI is rendered');
41+
});
42+
43+
signing.on('sessionEnd', (event) => {
44+
/** The event here denotes what caused the sessionEnd to trigger, such as signing_complete, ttl_expired etc../ **/
45+
console.log('sessionend', event);
46+
});
47+
48+
signing.mount('#agreement');
49+
})
50+
.catch((ex) => {
51+
// Any configuration or API limits will be caught here
52+
});</script>
53+
54+
<!DOCTYPE html>
55+
<html>
56+
<head>
57+
<meta charset="utf-8" />
58+
<title>Signing</title>
59+
<style>
60+
html,
61+
body {
62+
padding: 0;
63+
margin: 0;
64+
font: 13px Helvetica, Arial, sans-serif;
65+
}
66+
67+
.docusign-agreement {
68+
width: 75%;
69+
height: 1600px;
70+
}
71+
</style>
72+
</head>
73+
<body>
74+
<div class="docusign-agreement" id="docusign"></div>
75+
<script src="script.js"></script>
76+
</body>
77+
</html>

0 commit comments

Comments
 (0)