Skip to content

Commit f7d04c8

Browse files
committed
Merging DEVDOCS-8173 and 8122
2 parents b105e9d + f95c592 commit f7d04c8

6 files changed

Lines changed: 415 additions & 182 deletions

File tree

app/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,10 @@
112112
app.register_blueprint(esignature_views.eg036)
113113
app.register_blueprint(esignature_views.eg037)
114114
app.register_blueprint(esignature_views.eg038)
115+
app.register_blueprint(esignature_views.eg039)
115116
app.register_blueprint(esignature_views.eg040)
117+
118+
116119
if "DYNO" in os.environ: # On Heroku?
117120
import logging
118121

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import base64
2+
from os import path
3+
4+
from docusign_esign import EnvelopesApi, RecipientViewRequest, Document, Signer, EnvelopeDefinition, SignHere, Tabs, \
5+
Recipients, InPersonSigner
6+
from flask import session, url_for, request
7+
8+
from ...consts import authentication_method, demo_docs_path, pattern, signer_client_id
9+
from ...docusign import create_api_client, DSClient
10+
from ...ds_config import DS_CONFIG
11+
12+
13+
class Eg039InPersonSigner:
14+
@staticmethod
15+
def get_args():
16+
"""Get request and session arguments"""
17+
# More data validation would be a good idea here
18+
# Strip anything other than characters listed
19+
# 1. Parse request arguments
20+
signer_name = pattern.sub("", request.form.get("signer_name"))
21+
envelope_args = {
22+
"host_email": session["ds_user_email"],
23+
"host_name": session["ds_user_name"],
24+
"signer_name": signer_name,
25+
"ds_return_url": url_for("ds.ds_return", _external=True),
26+
}
27+
args = {
28+
"account_id": session["ds_account_id"],
29+
"base_path": session["ds_base_path"],
30+
"access_token": session["ds_access_token"],
31+
"envelope_args": envelope_args
32+
}
33+
return args
34+
35+
@classmethod
36+
def worker(cls, args):
37+
"""
38+
1. Create the envelope request object
39+
2. Send the envelope
40+
3. Create the Recipient View request object
41+
4. Obtain the recipient_view_url for the embedded signing
42+
"""
43+
envelope_args = args["envelope_args"]
44+
# 1. Create the envelope request object
45+
envelope_definition = cls.make_envelope(envelope_args)
46+
47+
# 2. call Envelopes::create API method
48+
# Exceptions will be caught by the calling function
49+
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
50+
51+
envelope_api = EnvelopesApi(api_client)
52+
results = envelope_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition)
53+
54+
envelope_id = results.envelope_id
55+
56+
# 3. Create the Recipient View request object
57+
recipient_view_request = RecipientViewRequest(
58+
authentication_method=authentication_method,
59+
recipient_id="1",
60+
return_url=envelope_args["ds_return_url"],
61+
user_name=envelope_args["host_name"],
62+
email=envelope_args["host_email"]
63+
)
64+
# 4. Obtain the recipient_view_url for the embedded signing session
65+
# Exceptions will be caught by the calling function
66+
results = envelope_api.create_recipient_view(
67+
account_id=args["account_id"],
68+
envelope_id=envelope_id,
69+
recipient_view_request=recipient_view_request
70+
)
71+
72+
return {"envelope_id": envelope_id, "redirect_url": results.url}
73+
74+
@classmethod
75+
def make_envelope(cls, args):
76+
"""
77+
Creates envelope
78+
args -- parameters for the envelope:
79+
signer_email, signer_name, signer_client_id
80+
returns an envelope definition
81+
"""
82+
83+
# document 1 (pdf) has tag /sn1/
84+
#
85+
# The envelope has one recipient.
86+
# recipient 1 - signer
87+
with open(path.join(demo_docs_path, DS_CONFIG["doc_pdf"]), "rb") as file:
88+
content_bytes = file.read()
89+
base64_file_content = base64.b64encode(content_bytes).decode("ascii")
90+
91+
# Create the document model
92+
document = Document( # create the DocuSign document object
93+
document_base64=base64_file_content,
94+
name="Example document", # can be different from actual file name
95+
file_extension="pdf", # many different document types are accepted
96+
document_id=1 # a label used to reference the doc
97+
)
98+
99+
# Create the in person signer recipient model
100+
signer = InPersonSigner(
101+
# The signer
102+
host_name = args["host_name"],
103+
host_email = args["host_email"],
104+
signer_name = args["signer_name"],
105+
recipient_id="1",
106+
routing_order="1",
107+
108+
)
109+
110+
# Create a sign_here tab (field on the document)
111+
sign_here = SignHere(
112+
# DocuSign SignHere field/tab
113+
anchor_string="/sn1/",
114+
anchor_units="pixels",
115+
anchor_y_offset="10",
116+
anchor_x_offset="20"
117+
)
118+
119+
# Add the tabs model (including the sign_here tab) to the signer
120+
# The Tabs object wants arrays of the different field/tab types
121+
InPersonSigner.tabs = Tabs(sign_here_tabs=[sign_here])
122+
123+
# Next, create the top level envelope definition and populate it.
124+
envelope_definition = EnvelopeDefinition(
125+
email_subject="Please host this in-person signing session",
126+
documents=[document],
127+
# The Recipients object wants arrays for each recipient type
128+
recipients=Recipients(in_person_signers=[signer]),
129+
status="sent" # requests that the envelope be created and sent.
130+
)
131+
132+
return envelope_definition

app/eSignature/views/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,5 @@
3535
from .eg036_delayed_routing import eg036
3636
from .eg037_sms_delivery import eg037
3737
from .eg038_responsive_signing import eg038
38+
from .eg038_responsive_signing import eg038
3839
from .eg040_document_visibility import eg040
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
""" Example 039: In Person Signer """
2+
3+
from os import path
4+
5+
from docusign_esign.client.api_exception import ApiException
6+
from flask import render_template, redirect, session, Blueprint, request
7+
8+
from ..examples.eg039_in_person_signer import Eg039InPersonSigner
9+
from ...docusign import authenticate
10+
from ...ds_config import DS_CONFIG
11+
from ...error_handlers import process_error
12+
from ...consts import pattern
13+
14+
eg = "eg039" # reference (and url) for this example
15+
eg039 = Blueprint("eg039", __name__)
16+
17+
@eg039.route("/eg039", methods=["POST"])
18+
@authenticate(eg=eg)
19+
def in_person_signer():
20+
"""
21+
1. Get required arguments
22+
2. Call the worker method
23+
3. Render success response with envelopeId
24+
"""
25+
26+
# 1. Get required arguments
27+
args = Eg039InPersonSigner.get_args()
28+
try:
29+
# 1. Call the worker method
30+
results = Eg039InPersonSigner.worker(args)
31+
except ApiException as err:
32+
return process_error(err)
33+
34+
session["envelope_id"] = results["envelope_id"] # Save for use by other examples which need an envelopeId
35+
36+
# 2. Redirect to in person signing session
37+
return redirect(results["redirect_url"])
38+
39+
40+
@eg039.route("/eg039", methods=["GET"])
41+
@authenticate(eg=eg)
42+
def get_view():
43+
"""responds with the form for the example"""
44+
45+
return render_template(
46+
"eg039_in_person_signer.html",
47+
title="Signing via email",
48+
source_file="eg039_in_person_signer.py",
49+
source_url=DS_CONFIG["github_example_url"] + "eg039_in_person_signer.py",
50+
documentation=DS_CONFIG["documentation"] + eg,
51+
show_doc=DS_CONFIG["documentation"],
52+
signer_name=DS_CONFIG["signer_name"],
53+
)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!-- extend base layout --> {% extends "base.html" %} {% block content %}
2+
3+
<h4>Send an envelope to an In Person Signer</h4>
4+
<p>Demonstrates how to host an In Person Signing session with embedded signing.</p>
5+
6+
{% if show_doc %}
7+
<p><a target='_blank' href='{{ documentation | safe }}'>Documentation</a> about this example.</p>
8+
{% endif %}
9+
10+
<p>API method used:
11+
<a target ='_blank' href="https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/create/">Envelopes::create</a> and
12+
<a target ='_blank' href="https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopeviews/createrecipient/">EnvelopeViews::createRecipient</a>.
13+
</p>
14+
15+
<p>
16+
View source file <a target="_blank" href="{{ source_url | safe }}">{{ source_file }}</a> on GitHub.
17+
</p>
18+
19+
<form class="eg" action="" method="post" data-busy="form">
20+
<div class="form-group">
21+
<label for="signer_name">Signer Name</label>
22+
<input type="text" class="form-control" id="signer_name" placeholder="Pat Johnson" name="signer_name"
23+
value="{{ signer_name }}" required />
24+
</div>
25+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
26+
<button type="submit" class="btn btn-docu">Submit</button>
27+
</form>
28+
29+
30+
{% endblock %}

0 commit comments

Comments
 (0)