Skip to content

Commit be16b39

Browse files
Added new Admin API code examples (#122)
* added new code examples * adding scope to tests --------- Co-authored-by: Paige Rossi <paige.rossi@docusign.com>
1 parent 2faec8c commit be16b39

11 files changed

+277
-3
lines changed

app/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@
5656
app.register_blueprint(admin_views.aeg007)
5757
app.register_blueprint(admin_views.aeg008)
5858
app.register_blueprint(admin_views.aeg009)
59+
app.register_blueprint(admin_views.aeg010)
60+
app.register_blueprint(admin_views.aeg011)
5961

6062
app.register_blueprint(click_views.ceg001)
6163
app.register_blueprint(click_views.ceg002)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from docusign_admin import ApiClient, UsersApi, OrganizationsApi, IndividualUserDataRedactionRequest, \
2+
MembershipDataRedactionRequest
3+
from flask import session, request
4+
5+
from ...ds_config import DS_CONFIG
6+
from app.admin.utils import get_organization_id
7+
8+
9+
class Eg010DeleteUserDataFromOrganizationController:
10+
@staticmethod
11+
def get_args():
12+
"""Get required session and request arguments"""
13+
organization_id = get_organization_id()
14+
return {
15+
"account_id": session["ds_account_id"], # Represents your {ACCOUNT_ID}
16+
"access_token": session["ds_access_token"], # Represents your {ACCESS_TOKEN}
17+
"organization_id": organization_id, # Represents your {ORGANIZATION_ID},
18+
"email": request.form.get("email"),
19+
}
20+
21+
@staticmethod
22+
def worker(args):
23+
"""
24+
1. Create an API client with headers
25+
2. Get user profile data
26+
3. Delete user data
27+
"""
28+
29+
access_token = args["access_token"]
30+
org_id = args["organization_id"]
31+
email = args["email"]
32+
33+
# Create an API client with headers
34+
# Step 2 start
35+
api_client = ApiClient(host=DS_CONFIG["admin_api_client_host"])
36+
api_client.set_default_header(
37+
header_name="Authorization",
38+
header_value=f"Bearer {access_token}"
39+
)
40+
# Step 2 end
41+
42+
# Step 3 start
43+
users_api = UsersApi(api_client=api_client)
44+
results = users_api.get_user_ds_profiles_by_email(organization_id=org_id, email=email)
45+
user = results.users[0]
46+
# Step 3 end
47+
48+
# Step 4 start
49+
organizations_api = OrganizationsApi(api_client=api_client)
50+
user_data_redaction_request = IndividualUserDataRedactionRequest(
51+
user_id=user.id,
52+
memberships=[MembershipDataRedactionRequest(account_id=user.memberships[0].account_id)]
53+
)
54+
results = organizations_api.redact_individual_user_data(org_id, user_data_redaction_request)
55+
# Step 4 end
56+
57+
return results
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from docusign_admin import ApiClient, AccountsApi, IndividualMembershipDataRedactionRequest
2+
from flask import session, request
3+
4+
from ...ds_config import DS_CONFIG
5+
6+
7+
class Eg011DeleteUserDataFromAccountController:
8+
@staticmethod
9+
def get_args():
10+
"""Get required session and request arguments"""
11+
return {
12+
"account_id": session["ds_account_id"], # Represents your {ACCOUNT_ID}
13+
"access_token": session["ds_access_token"], # Represents your {ACCESS_TOKEN}
14+
"user_id": request.form.get("user_id"),
15+
}
16+
17+
@staticmethod
18+
def worker(args):
19+
"""
20+
1. Create an API client with headers
21+
2. Delete user data
22+
"""
23+
24+
access_token = args["access_token"]
25+
account_id = args["account_id"]
26+
user_id = args["user_id"]
27+
28+
# Create an API client with headers
29+
# Step 2 start
30+
api_client = ApiClient(host=DS_CONFIG["admin_api_client_host"])
31+
api_client.set_default_header(
32+
header_name="Authorization",
33+
header_value=f"Bearer {access_token}"
34+
)
35+
# Step 2 end
36+
37+
# Step 3 start
38+
accounts_api = AccountsApi(api_client=api_client)
39+
membership_redaction_request = IndividualMembershipDataRedactionRequest(user_id=user_id)
40+
results = accounts_api.redact_individual_membership_data(account_id, membership_redaction_request)
41+
# Step 3 end
42+
43+
return results

app/admin/views/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
from .eg007_get_user_profile_by_user_id import aeg007
88
from .eg008_update_user_product_permission_profile import aeg008
99
from .eg009_delete_user_product_permission_profile import aeg009
10+
from .eg010_delete_user_data_from_organization import aeg010
11+
from .eg011_delete_user_data_from_account import aeg011
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Example 010: Delete user data from an account as an organization admin. """
2+
3+
import json
4+
5+
from docusign_admin.client.api_exception import ApiException
6+
from flask import Blueprint, render_template, session
7+
8+
from app.docusign import authenticate, ensure_manifest, get_example_by_number
9+
from app.error_handlers import process_error
10+
from ..examples.eg010_delete_user_data_from_organization import Eg010DeleteUserDataFromOrganizationController
11+
from ...ds_config import DS_CONFIG
12+
from ...consts import API_TYPE
13+
14+
example_number = 10
15+
api = API_TYPE["ADMIN"]
16+
eg = f"aeg0{example_number}" # Reference (and URL) for this example
17+
aeg010 = Blueprint(eg, __name__)
18+
19+
20+
@aeg010.route(f"/{eg}", methods=["POST"])
21+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
22+
@authenticate(eg=eg, api=api)
23+
def audit_users():
24+
"""
25+
1. Get required arguments
26+
2. Call the worker method
27+
3. Render the response
28+
"""
29+
example = get_example_by_number(session["manifest"], example_number, api)
30+
31+
# 1. Get required arguments
32+
args = Eg010DeleteUserDataFromOrganizationController.get_args()
33+
try:
34+
# 2. Call the worker method to delete user data by email
35+
results = Eg010DeleteUserDataFromOrganizationController.worker(args)
36+
except ApiException as err:
37+
return process_error(err)
38+
39+
return render_template(
40+
"example_done.html",
41+
title=example["ExampleName"],
42+
message=example["ResultsPageText"],
43+
json=json.dumps(json.dumps(results.to_dict(), default=str))
44+
)
45+
46+
47+
@aeg010.route(f"/{eg}", methods=["GET"])
48+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
49+
@authenticate(eg=eg, api=api)
50+
def get_view():
51+
""" Responds with the form for the example"""
52+
example = get_example_by_number(session["manifest"], example_number, api)
53+
54+
return render_template(
55+
"admin/eg010_delete_user_data_from_organization.html",
56+
title=example["ExampleName"],
57+
example=example,
58+
source_file="eg010_delete_user_data_from_organization.py",
59+
source_url=DS_CONFIG["admin_github_url"] + "eg010_delete_user_data_from_organization.py",
60+
documentation=DS_CONFIG["documentation"] + eg,
61+
)
62+
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Example 011: Delete user data from an account as an account admin. """
2+
3+
import json
4+
5+
from docusign_admin.client.api_exception import ApiException
6+
from flask import Blueprint, render_template, session
7+
8+
from app.docusign import authenticate, ensure_manifest, get_example_by_number
9+
from app.error_handlers import process_error
10+
from ..examples.eg011_delete_user_data_from_account import Eg011DeleteUserDataFromAccountController
11+
from ...ds_config import DS_CONFIG
12+
from ...consts import API_TYPE
13+
14+
example_number = 11
15+
api = API_TYPE["ADMIN"]
16+
eg = f"aeg0{example_number}" # Reference (and URL) for this example
17+
aeg011 = Blueprint(eg, __name__)
18+
19+
20+
@aeg011.route(f"/{eg}", methods=["POST"])
21+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
22+
@authenticate(eg=eg, api=api)
23+
def audit_users():
24+
"""
25+
1. Get required arguments
26+
2. Call the worker method
27+
3. Render the response
28+
"""
29+
example = get_example_by_number(session["manifest"], example_number, api)
30+
31+
# 1. Get required arguments
32+
args = Eg011DeleteUserDataFromAccountController.get_args()
33+
try:
34+
# 2. Call the worker method to delete user data by user ID
35+
results = Eg011DeleteUserDataFromAccountController.worker(args)
36+
except ApiException as err:
37+
return process_error(err)
38+
39+
return render_template(
40+
"example_done.html",
41+
title=example["ExampleName"],
42+
message=example["ResultsPageText"],
43+
json=json.dumps(json.dumps(results.to_dict(), default=str))
44+
)
45+
46+
47+
@aeg011.route(f"/{eg}", methods=["GET"])
48+
@ensure_manifest(manifest_url=DS_CONFIG["example_manifest_url"])
49+
@authenticate(eg=eg, api=api)
50+
def get_view():
51+
""" Responds with the form for the example"""
52+
example = get_example_by_number(session["manifest"], example_number, api)
53+
54+
return render_template(
55+
"admin/eg011_delete_user_data_from_account.html",
56+
title=example["ExampleName"],
57+
example=example,
58+
source_file="eg011_delete_user_data_from_account.py",
59+
source_url=DS_CONFIG["admin_github_url"] + "eg011_delete_user_data_from_account.py",
60+
documentation=DS_CONFIG["documentation"] + eg,
61+
)
62+

app/docusign/ds_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
ADMIN_SCOPES = [
3131
"signature", "organization_read", "group_read", "permission_read", "user_read", "user_write",
32-
"account_read", "domain_read", "identity_provider_read", "impersonation"
32+
"account_read", "domain_read", "identity_provider_read", "impersonation", "user_data_redact"
3333
]
3434

3535

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
8+
<form class="eg" action="" method="post" data-busy="form">
9+
{% if 'FormName' in example['Forms'][form_index] %}
10+
<p>{{ example['Forms'][form_index]['FormName'] | safe }}</p>
11+
{% endif %}
12+
13+
<div class="form-group">
14+
<label for="email">{{ example['Forms'][form_index]['Inputs'][email_index]['InputName'] }}</label>
15+
<input type="email" class="form-control" id="email" name="email" placeholder="{{ example['Forms'][form_index]['Inputs'][email_index]['InputPlaceholder'] }}" required>
16+
<small id="email_help" class="form-text text-muted">{{ session['manifest']['SupportingTexts']['HelpingTexts']['EmailAddressOfUserToDelete'] | safe}}</small>
17+
</div>
18+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
19+
{% include 'continue_button.html' %}
20+
</form>
21+
22+
{% endblock %}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!-- extend base layout --> {% extends "base.html" %} {% block content %}
2+
3+
{% include 'example_info.html' %}
4+
5+
{% set form_index = 0 %}
6+
{% set user_id_index = 0 %}
7+
8+
<form class="eg" action="" method="post" data-busy="form">
9+
{% if 'FormName' in example['Forms'][form_index] %}
10+
<p>{{ example['Forms'][form_index]['FormName'] | safe }}</p>
11+
{% endif %}
12+
13+
<div class="form-group">
14+
<label for="user_id">{{ example['Forms'][form_index]['Inputs'][user_id_index]['InputName'] }}</label>
15+
<input type="text" class="form-control" id="user_id" name="user_id"
16+
placeholder="{{ example['Forms'][form_index]['Inputs'][user_id_index]['InputPlaceholder'] }}" required
17+
pattern="[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}">
18+
<small id="user_id_help" class="form-text text-muted">{{ session['manifest']['SupportingTexts']['HelpingTexts']['UserIDOfUserToDelete'] | safe}}</small>
19+
</div>
20+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
21+
{% include 'continue_button.html' %}
22+
</form>
23+
24+
{% endblock %}

app/tests/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def get_configuration():
2020
"dtr.company.read", "dtr.company.write", "room_forms"],
2121
"admin_scopes": ["organization_read", "group_read", "permission_read",
2222
"user_read", "user_write", "account_read",
23-
"domain_read", "identity_provider_read"],
23+
"domain_read", "identity_provider_read", "user_data_redact"],
2424
"expires_in": 3600,
2525
"test_pdf_file": './app/tests/docs/World_Wide_Corp_lorem.pdf',
2626
"test_docx_file": './app/tests/docs/World_Wide_Corp_Battle_Plan_Trafalgar.docx',

0 commit comments

Comments
 (0)