-
Notifications
You must be signed in to change notification settings - Fork 55
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #135 from docusign/feature/focused-view-code-example
Added focused view code example
- Loading branch information
Showing
6 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import base64 | ||
from os import path | ||
|
||
from docusign_esign import EnvelopesApi, RecipientViewRequest, Document, Signer, EnvelopeDefinition, SignHere, Tabs, \ | ||
Recipients | ||
from flask import session, url_for, request | ||
|
||
from ...consts import authentication_method, demo_docs_path, pattern, signer_client_id | ||
from ...docusign import create_api_client | ||
from ...ds_config import DS_CONFIG | ||
|
||
|
||
class Eg044FocusedViewController: | ||
@staticmethod | ||
def get_args(): | ||
"""Get request and session arguments""" | ||
# More data validation would be a good idea here | ||
# Strip anything other than characters listed | ||
# 1. Parse request arguments | ||
signer_email = pattern.sub("", request.form.get("signer_email")) | ||
signer_name = pattern.sub("", request.form.get("signer_name")) | ||
envelope_args = { | ||
"signer_email": signer_email, | ||
"signer_name": signer_name, | ||
"signer_client_id": signer_client_id, | ||
"ds_return_url": url_for("ds.ds_return", _external=True), | ||
} | ||
args = { | ||
"account_id": session["ds_account_id"], | ||
"base_path": session["ds_base_path"], | ||
"access_token": session["ds_access_token"], | ||
"envelope_args": envelope_args | ||
} | ||
return args | ||
|
||
@classmethod | ||
def worker(cls, args): | ||
""" | ||
1. Create the envelope request object | ||
2. Send the envelope | ||
3. Create the Recipient View request object | ||
4. Obtain the recipient_view_url for the embedded signing | ||
""" | ||
#ds-snippet-start:eSign44Step3 | ||
envelope_args = args["envelope_args"] | ||
# 1. Create the envelope request object | ||
envelope_definition = cls.make_envelope(envelope_args) | ||
|
||
# 2. call Envelopes::create API method | ||
# Exceptions will be caught by the calling function | ||
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"]) | ||
|
||
envelope_api = EnvelopesApi(api_client) | ||
results = envelope_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition) | ||
|
||
envelope_id = results.envelope_id | ||
#ds-snippet-end:eSign44Step3 | ||
|
||
# 3. Create the Recipient View request object | ||
#ds-snippet-start:eSign44Step4 | ||
recipient_view_request = RecipientViewRequest( | ||
authentication_method=authentication_method, | ||
client_user_id=envelope_args["signer_client_id"], | ||
recipient_id="1", | ||
return_url=envelope_args["ds_return_url"], | ||
user_name=envelope_args["signer_name"], | ||
email=envelope_args["signer_email"], | ||
frame_ancestors=["http://localhost:3000", "https://apps-d.docusign.com"], | ||
message_origins=["https://apps-d.docusign.com"] | ||
) | ||
#ds-snippet-end:eSign44Step4 | ||
|
||
# 4. Obtain the recipient_view_url for the embedded signing | ||
# Exceptions will be caught by the calling function | ||
|
||
#ds-snippet-start:eSign44Step5 | ||
results = envelope_api.create_recipient_view( | ||
account_id=args["account_id"], | ||
envelope_id=envelope_id, | ||
recipient_view_request=recipient_view_request | ||
) | ||
|
||
return {"envelope_id": envelope_id, "redirect_url": results.url} | ||
#ds-snippet-end:eSign44Step5 | ||
|
||
@classmethod | ||
#ds-snippet-start:eSign44Step2 | ||
def make_envelope(cls, args): | ||
""" | ||
Creates envelope | ||
args -- parameters for the envelope: | ||
signer_email, signer_name, signer_client_id | ||
returns an envelope definition | ||
""" | ||
|
||
# document 1 (pdf) has tag /sn1/ | ||
# | ||
# The envelope has one recipient. | ||
# recipient 1 - signer | ||
with open(path.join(demo_docs_path, DS_CONFIG["doc_pdf"]), "rb") as file: | ||
content_bytes = file.read() | ||
base64_file_content = base64.b64encode(content_bytes).decode("ascii") | ||
|
||
# Create the document model | ||
document = Document( # create the DocuSign document object | ||
document_base64=base64_file_content, | ||
name="Example document", # can be different from actual file name | ||
file_extension="pdf", # many different document types are accepted | ||
document_id=1 # a label used to reference the doc | ||
) | ||
|
||
# Create the signer recipient model | ||
signer = Signer( | ||
# The signer | ||
email=args["signer_email"], | ||
name=args["signer_name"], | ||
recipient_id="1", | ||
routing_order="1", | ||
# Setting the client_user_id marks the signer as embedded | ||
client_user_id=args["signer_client_id"] | ||
) | ||
|
||
# Create a sign_here tab (field on the document) | ||
sign_here = SignHere( | ||
# DocuSign SignHere field/tab | ||
anchor_string="/sn1/", | ||
anchor_units="pixels", | ||
anchor_y_offset="10", | ||
anchor_x_offset="20" | ||
) | ||
|
||
# Add the tabs model (including the sign_here tab) to the signer | ||
# The Tabs object wants arrays of the different field/tab types | ||
signer.tabs = Tabs(sign_here_tabs=[sign_here]) | ||
|
||
# Next, create the top level envelope definition and populate it. | ||
envelope_definition = EnvelopeDefinition( | ||
email_subject="Please sign this document sent from the Python SDK", | ||
documents=[document], | ||
# The Recipients object wants arrays for each recipient type | ||
recipients=Recipients(signers=[signer]), | ||
status="sent" # requests that the envelope be created and sent. | ||
) | ||
|
||
return envelope_definition | ||
#ds-snippet-end:eSign44Step2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
"""Example 044: Focused view""" | ||
|
||
from docusign_esign.client.api_exception import ApiException | ||
from flask import render_template, Blueprint, session | ||
|
||
from ..examples.eg044_focused_view import Eg044FocusedViewController | ||
from ...docusign import authenticate, ensure_manifest, get_example_by_number | ||
from ...ds_config import DS_CONFIG | ||
from ...error_handlers import process_error | ||
from ...consts import API_TYPE | ||
|
||
example_number = 44 | ||
api = API_TYPE["ESIGNATURE"] | ||
eg = f"eg0{example_number}" # reference (and url) for this example | ||
eg044 = Blueprint(eg, __name__) | ||
|
||
|
||
@eg044.route(f"/{eg}", methods=["POST"]) | ||
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"]) | ||
@authenticate(eg=eg, api=api) | ||
def embedded_signing(): | ||
""" | ||
1. Get required arguments | ||
2. Call the worker method | ||
3. Redirect the user to the embedded signing | ||
""" | ||
try: | ||
# 1. Get required arguments | ||
args = Eg044FocusedViewController.get_args() | ||
# 2. Call the worker method | ||
results = Eg044FocusedViewController.worker(args) | ||
except ApiException as err: | ||
return process_error(err) | ||
|
||
session["envelope_id"] = results["envelope_id"] | ||
example = get_example_by_number(session["manifest"], example_number, api) | ||
|
||
return render_template( | ||
"eSignature/eg044_embed.html", | ||
title=example["ExampleName"], | ||
url=results["redirect_url"], | ||
integration_key=DS_CONFIG["ds_client_id"] | ||
) | ||
|
||
|
||
@eg044.route(f"/{eg}", methods=["GET"]) | ||
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"]) | ||
@authenticate(eg=eg, api=api) | ||
def get_view(): | ||
"""responds with the form for the example""" | ||
example = get_example_by_number(session["manifest"], example_number, api) | ||
|
||
return render_template( | ||
"eSignature/eg044_focused_view.html", | ||
title=example["ExampleName"], | ||
example=example, | ||
source_file="eg044_focused_view.py", | ||
source_url=DS_CONFIG["github_example_url"] + "eg044_focused_view.py", | ||
documentation=DS_CONFIG["documentation"] + eg, | ||
show_doc=DS_CONFIG["documentation"], | ||
signer_name=DS_CONFIG["signer_name"], | ||
signer_email=DS_CONFIG["signer_email"] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<!-- extend base layout --> {% extends "base.html" %} {% block content %} | ||
|
||
<br /> | ||
<h2>The document has been embedded with focused view.</h2> | ||
<br /> | ||
|
||
<!-- | ||
//ds-snippet-start:eSign44Step6 | ||
--> | ||
|
||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title>Signing</title> | ||
<style> | ||
html, | ||
body { | ||
padding: 0; | ||
margin: 0; | ||
font: 13px Helvetica, Arial, sans-serif; | ||
} | ||
|
||
.docusign-agreement { | ||
width: 75%; | ||
height: 800px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div class="docusign-agreement" id="agreement"></div> | ||
<script src="script.js"></script> | ||
</body> | ||
</html> | ||
|
||
<p><a href="/">Continue</a></p> | ||
|
||
<script src='https://docucdn-a.akamaihd.net/demo/1ds/libs/@embedded-js/core/latest/dist/bundle.js'></script> | ||
<script> | ||
window.DocuSign.loadDocuSign('{{ integration_key }}') | ||
.then((docusign) => { | ||
const signing = docusign.signing({ | ||
url: '{{ url }}', | ||
displayFormat: 'focused', | ||
style: { | ||
/** High-level variables that mirror our existing branding APIs. Reusing the branding name here for familiarity. */ | ||
branding: { | ||
primaryButton: { | ||
/** Background color of primary button */ | ||
backgroundColor: '#333', | ||
/** Text color of primary button */ | ||
color: '#fff', | ||
} | ||
}, | ||
|
||
/** High-level components we allow specific overrides for */ | ||
signingNavigationButton: { | ||
finishText: 'You have finished the document! Hooray!', | ||
position: 'bottom-center' | ||
} | ||
} | ||
}); | ||
|
||
signing.on('ready', (event) => { | ||
console.log('UI is rendered'); | ||
}); | ||
|
||
signing.on('sessionEnd', (event) => { | ||
/** The event here denotes what caused the sessionEnd to trigger, such as signing_complete, ttl_expired etc../ **/ | ||
console.log('sessionend', event); | ||
}); | ||
|
||
signing.mount('#agreement'); | ||
}) | ||
.catch((ex) => { | ||
// Any configuration or API limits will be caught here | ||
});</script> | ||
|
||
<!-- | ||
//ds-snippet-end:eSign44Step6 | ||
--> | ||
|
||
{% endblock %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!-- extend base layout --> {% extends "base.html" %} {% block content %} | ||
|
||
{% include 'example_info.html' %} | ||
|
||
{% set signer_form_index = 0 %} | ||
{% set signer_email_index = 0 %} | ||
{% set signer_name_index = 1 %} | ||
|
||
<form class="eg" action="" method="post" data-busy="form"> | ||
{% if 'FormName' in example['Forms'][signer_form_index] %} | ||
<p>{{ example['Forms'][signer_form_index]['FormName'] | safe }}</p> | ||
{% endif %} | ||
|
||
<div class="form-group"> | ||
<label for="signer_email">{{ example['Forms'][signer_form_index]['Inputs'][signer_email_index]['InputName'] }}</label> | ||
<input type="email" class="form-control" id="signer_email" name="signer_email" | ||
aria-describedby="emailHelp" placeholder="{{ example['Forms'][signer_form_index]['Inputs'][signer_email_index]['InputPlaceholder'] }}" required | ||
value="{{ signer_email }}"> | ||
<small id="emailHelp" class="form-text text-muted">{{ session['manifest']['SupportingTexts']['HelpingTexts']['EmailWontBeShared'] | safe}}</small> | ||
</div> | ||
<div class="form-group"> | ||
<label for="signer_name">{{ example['Forms'][signer_form_index]['Inputs'][signer_name_index]['InputName'] }}</label> | ||
<input type="text" class="form-control" id="signer_name" placeholder="{{ example['Forms'][signer_form_index]['Inputs'][signer_name_index]['InputPlaceholder'] }}" name="signer_name" | ||
value="{{ signer_name }}" required> | ||
</div> | ||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> | ||
{% include 'submit_button.html' %} | ||
</form> | ||
|
||
{% endblock %} | ||
|