Skip to content

Commit bfa350e

Browse files
added example
1 parent 2019c8c commit bfa350e

File tree

9 files changed

+267
-1
lines changed

9 files changed

+267
-1
lines changed

app/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
app.register_blueprint(esignature_views.eg040)
106106
app.register_blueprint(esignature_views.eg041)
107107
app.register_blueprint(esignature_views.eg042)
108+
app.register_blueprint(esignature_views.eg043)
108109

109110
if "DYNO" in os.environ: # On Heroku?
110111
import logging

app/docusign/utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ def wrapper(*args, **kwargs):
101101

102102
return decorator
103103

104+
def authenticate_agent(eg):
105+
def decorator(func):
106+
@wraps(func)
107+
def wrapper(*args, **kwargs):
108+
session["eg"] = url_for(eg + ".list_envelopes")
109+
110+
if ds_token_ok(minimum_buffer_min):
111+
return func(*args, **kwargs)
112+
else:
113+
return redirect(url_for("ds.ds_must_authenticate"))
114+
115+
return wrapper
116+
117+
return decorator
118+
104119
def ensure_manifest(manifest_url):
105120
def decorator(func):
106121
@wraps(func)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from flask import session, request
2+
from docusign_esign import EnvelopesApi, UsersApi, AccountsApi, NewUsersDefinition, UserInformation,\
3+
UserAuthorizationCreateRequest, AuthorizationUser
4+
from datetime import datetime, timedelta
5+
6+
from ...consts import pattern
7+
from ...ds_config import DS_JWT
8+
from ...docusign import create_api_client
9+
10+
11+
class Eg043SharedAccessController:
12+
@classmethod
13+
def create_agent(cls, args):
14+
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
15+
users_api = UsersApi(api_client)
16+
17+
return users_api.create(args["account_id"], new_users_definition=cls.new_users_definition(args))
18+
19+
@classmethod
20+
def create_authorization(cls, args):
21+
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
22+
accounts_api = AccountsApi(api_client)
23+
24+
return accounts_api.create_user_authorization(
25+
args["account_id"],
26+
args["user_id"],
27+
user_authorization_create_request=cls.user_authorization_request(args)
28+
)
29+
30+
@classmethod
31+
def new_users_definition(cls, args):
32+
agent = UserInformation(
33+
user_name=args["user_name"],
34+
email=args["email"],
35+
activation_access_code=args["activation"]
36+
)
37+
return NewUsersDefinition(new_users=[agent])
38+
39+
@classmethod
40+
def user_authorization_request(cls, args):
41+
return UserAuthorizationCreateRequest(
42+
agent_user=AuthorizationUser(
43+
account_id=args["account_id"],
44+
user_id=args["agent_user_id"]
45+
),
46+
permission="manage"
47+
)
48+
49+
@classmethod
50+
def get_envelopes(cls, args):
51+
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
52+
api_client.set_default_header("X-DocuSign-Act-On-Behalf", args["user_id"])
53+
envelopes_api = EnvelopesApi(api_client)
54+
55+
from_date = (datetime.utcnow() - timedelta(days=30)).isoformat()
56+
return envelopes_api.list_status_changes(account_id=args["account_id"], from_date=from_date)

app/eSignature/views/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@
3939
from .eg040_document_visibility import eg040
4040
from .eg041_cfr_embedded_signing import eg041
4141
from .eg042_document_generation import eg042
42+
from .eg043_shared_access import eg043
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
""" Example 043: Share access to a DocuSign envelope inbox """
2+
3+
import json
4+
5+
from docusign_esign.client.api_exception import ApiException
6+
from flask import render_template, session, Blueprint, redirect, current_app, url_for, request
7+
8+
from ..examples.eg043_shared_access import Eg043SharedAccessController
9+
from ...docusign import authenticate, ensure_manifest, get_example_by_number
10+
from ...docusign.utils import ds_logout_internal, authenticate_agent
11+
from ...ds_config import DS_CONFIG, DS_JWT
12+
from ...error_handlers import process_error
13+
from ...consts import pattern, API_TYPE
14+
15+
example_number = 43
16+
api = API_TYPE["ESIGNATURE"]
17+
eg = f"eg0{example_number}" # reference (and url) for this example
18+
eg043 = Blueprint(eg, __name__)
19+
20+
21+
@eg043.route(f"/{eg}", methods=["POST"])
22+
@authenticate(eg=eg, api=api)
23+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
24+
def create_agent():
25+
args = {
26+
"account_id": session["ds_account_id"],
27+
"base_path": session["ds_base_path"],
28+
"access_token": session["ds_access_token"],
29+
"email": pattern.sub("", request.form.get("email")),
30+
"user_name": pattern.sub("", request.form.get("user_name")),
31+
"activation": pattern.sub("", request.form.get("activation"))
32+
}
33+
try:
34+
# 1. Create the agent user
35+
results = Eg043SharedAccessController.create_agent(args)
36+
except ApiException as err:
37+
return process_error(err)
38+
39+
session["agent_user_id"] = results.new_users[0].user_id
40+
41+
example = get_example_by_number(session["manifest"], example_number, api)
42+
return render_template(
43+
"eSignature/eg043_shared_access/eg043_shared_access_agent_created.html",
44+
title="Agent user created",
45+
message=example["ResultsPageText"],
46+
json=json.dumps(json.dumps(results.to_dict()))
47+
)
48+
49+
50+
@eg043.route(f"/{eg}auth", methods=["GET"])
51+
@authenticate(eg=eg, api=api)
52+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
53+
def create_authorization():
54+
args = {
55+
"account_id": session["ds_account_id"],
56+
"base_path": session["ds_base_path"],
57+
"access_token": session["ds_access_token"],
58+
"user_id": DS_JWT["ds_impersonated_user_id"],
59+
"agent_user_id": session["agent_user_id"]
60+
}
61+
try:
62+
# 2. Create the authorization for agent user
63+
Eg043SharedAccessController.create_authorization(args)
64+
except ApiException as err:
65+
return process_error(err)
66+
67+
example = get_example_by_number(session["manifest"], example_number, api)
68+
additional_page_data = next((p for p in example["AdditionalPage"] if p["Name"] == "authenticate_as_agent"), None)
69+
return render_template(
70+
"eSignature/eg043_shared_access/eg043_shared_access_reauthenticate.html",
71+
title="Authenticate as the agent",
72+
message=additional_page_data["ResultsPageText"]
73+
)
74+
75+
76+
@eg043.route(f"/{eg}reauthenticate", methods=["GET"])
77+
def reauthenticate():
78+
# 3. Logout principal user and redirect to page with the list of envelopes, login as agent user
79+
ds_logout_internal()
80+
current_app.config["isLoggedIn"] = False
81+
return redirect(url_for(f"{eg}.list_envelopes"))
82+
83+
84+
@eg043.route(f"/{eg}envelopes", methods=["GET"])
85+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
86+
@authenticate_agent(eg=eg)
87+
def list_envelopes():
88+
args = {
89+
"account_id": session["ds_account_id"],
90+
"base_path": session["ds_base_path"],
91+
"access_token": session["ds_access_token"],
92+
"user_id": DS_JWT["ds_impersonated_user_id"]
93+
}
94+
try:
95+
# 4. Retrieve the list of envelopes
96+
results = Eg043SharedAccessController.get_envelopes(args)
97+
except ApiException as err:
98+
return process_error(err)
99+
100+
example = get_example_by_number(session["manifest"], example_number, api)
101+
102+
if int(results.result_set_size) > 0:
103+
additional_page = next((p for p in example["AdditionalPage"] if p["Name"] == "list_status_successful"), None)
104+
return render_template(
105+
"example_done.html",
106+
title="Principal's envelopes visible in the agent's Shared Access UI",
107+
message=additional_page["ResultsPageText"],
108+
json=json.dumps(json.dumps(results.to_dict()))
109+
)
110+
111+
additional_page = next((p for p in example["AdditionalPage"] if p["Name"] == "list_status_unsuccessful"), None)
112+
return render_template(
113+
"example_done.html",
114+
title="No envelopes in the principal user's account",
115+
message=additional_page["ResultsPageText"]
116+
)
117+
118+
119+
@eg043.route(f"/{eg}", methods=["GET"])
120+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
121+
@authenticate(eg=eg, api=api)
122+
def get_view():
123+
"""responds with the form for the example"""
124+
example = get_example_by_number(session["manifest"], example_number, api)
125+
126+
return render_template(
127+
"eSignature/eg043_shared_access/eg043_shared_access.html",
128+
title=example["ExampleName"],
129+
example=example,
130+
source_file="eg043_shared_access.py",
131+
source_url=DS_CONFIG["github_example_url"] + "eg043_shared_access.py",
132+
documentation=DS_CONFIG["documentation"] + eg,
133+
show_doc=DS_CONFIG["documentation"],
134+
signer_name=DS_CONFIG["signer_name"],
135+
signer_email=DS_CONFIG["signer_email"]
136+
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!-- extend base layout --> {% extends "base.html" %} {% block content %}
2+
3+
{% include 'example_info.html' %}
4+
5+
{% set form_index = 0 %}
6+
{% set email_index = 0 %}
7+
{% set username_index = 1 %}
8+
{% set activation_index = 2 %}
9+
10+
<form class="eg" action="" method="post" data-busy="form">
11+
{% if 'FormName' in example['Forms'][form_index] %}
12+
<p>{{ example['Forms'][form_index]['FormName'] | safe }}</p>
13+
{% endif %}
14+
<div class="form-group">
15+
<label for="email">{{ example['Forms'][form_index]['Inputs'][email_index]['InputName'] }}</label>
16+
<input type="email" class="form-control" id="email" name="email"
17+
aria-describedby="emailHelp" placeholder="{{ example['Forms'][form_index]['Inputs'][email_index]['InputPlaceholder'] }}" required>
18+
</div>
19+
<div class="form-group">
20+
<label for="user_name">{{ example['Forms'][form_index]['Inputs'][username_index]['InputName'] }}</label>
21+
<input type="text" class="form-control" id="user_name" placeholder="{{ example['Forms'][form_index]['Inputs'][username_index]['InputPlaceholder'] }}" name="user_name"
22+
required>
23+
</div>
24+
<div class="form-group">
25+
<label for="activation">{{ example['Forms'][form_index]['Inputs'][activation_index]['InputName'] }}</label>
26+
<input type="text" class="form-control" id="activation" name="activation"
27+
placeholder="{{ example['Forms'][form_index]['Inputs'][activation_index]['InputPlaceholder'] }}" required>
28+
<small id="activationHelp" class="form-text text-muted">{{ session['manifest']['SupportingTexts']['HelpingTexts']['SaveAgentActivationCode'] | safe}}</small>
29+
</div>
30+
31+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
32+
{% include 'submit_button.html' %}
33+
</form>
34+
35+
{% endblock %}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!-- extend base layout --> {% extends "base.html" %} {% block content %}
2+
3+
<h2>{{ title }}</h2>
4+
<p>{{ message | safe }}</p>
5+
6+
{% if json %}
7+
<!-- Data from the server -->
8+
<div id="server_json_data" data-server-json-data='{"json": {{ json | safe }} }' class="hidden"></div>
9+
<p><pre class="json-display"><code id="json-display"></code></pre></p>
10+
{% endif %}
11+
12+
<p><a href="/eg043auth">Continue</a></p>
13+
14+
{% endblock %}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- extend base layout --> {% extends "base.html" %} {% block content %}
2+
3+
<h2>{{ title }}</h2>
4+
<p>{{ message | safe }}</p>
5+
6+
<p><a href="/eg043reauthenticate">Continue</a></p>
7+
8+
{% endblock %}

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cffi==1.15.1
44
chardet==5.1.0
55
Click
66
cryptography==39.0.0
7-
docusign-esign==3.21.0
7+
docusign-esign==3.22.0
88
docusign-rooms==1.1.0
99
docusign-monitor==1.1.0
1010
docusign-click==1.2.2

0 commit comments

Comments
 (0)