Skip to content

Commit e28b2ed

Browse files
annahiletaAaronWDS
andauthored
Added clone account code example (#123)
* added clone account code example * fixes after code review * removed usage of str_contains for backward compatability * cd Snippet markers --------- Co-authored-by: AaronWDS <[email protected]>
1 parent a9b777c commit e28b2ed

File tree

9 files changed

+302
-8
lines changed

9 files changed

+302
-8
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
},
2424
"description": "DocuSign PHP launcher",
2525
"require": {
26-
"docusign/admin-client": "^1.3.0-rc",
26+
"docusign/admin-client": "^1.4.0",
2727
"docusign/click-client": "^1.3.0-rc",
2828
"docusign/esign-client": "^6.15.0-rc",
2929
"docusign/rooms-client": "^2.1.0",

composer.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Controllers/Auth/DocuSign.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public function getDefaultScopes(): array
117117
];
118118
} elseif ($_SESSION['api_type'] == ApiTypes::Admin) {
119119
return [
120-
"signature user_write group_read organization_read permission_read user_read account_read domain_read identity_provider_read user_data_redact"
120+
"signature user_write group_read organization_read permission_read user_read account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read"
121121
];
122122
} else {
123123
return [
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace Example\Controllers\Examples\Admin;
4+
5+
use DocuSign\Admin\Client\ApiException;
6+
use Example\Controllers\AdminApiBaseController;
7+
use Example\Services\Examples\Admin\CloneAccountService;
8+
9+
class EG012CloneAccount extends AdminApiBaseController
10+
{
11+
public const EG = 'aeg012'; # reference (and url) for this example
12+
public const FILE = __FILE__;
13+
14+
/**
15+
* Create a new controller instance
16+
*
17+
* @return void
18+
*/
19+
public function __construct()
20+
{
21+
parent::__construct();
22+
23+
$this->checkDsToken();
24+
25+
try {
26+
$this->orgId = $this->clientService->getOrgAdminId();
27+
$provisionAssetGroupApi = $this->clientService->provisionAssetGroupApi();
28+
29+
$assetGroupAccountsResponse = CloneAccountService::getAccounts($provisionAssetGroupApi, $this->orgId);
30+
parent::controller(['groups' => $assetGroupAccountsResponse['asset_group_accounts']]);
31+
} catch (ApiException $e) {
32+
$this->clientService->showErrorTemplate($e);
33+
}
34+
}
35+
36+
/**
37+
* 1. Check the token
38+
* 2. Call the worker method
39+
*
40+
* @return void
41+
*/
42+
public function createController(): void
43+
{
44+
$this->checkDsToken();
45+
46+
try {
47+
$this->orgId = $this->clientService->getOrgAdminId();
48+
$provisionAssetGroupApi = $this->clientService->provisionAssetGroupApi();
49+
50+
$assetGroupAccountClone = CloneAccountService::cloneAccount(
51+
$provisionAssetGroupApi,
52+
$this->orgId,
53+
$this->args['source_account_id'],
54+
$this->args['target_account_name'],
55+
$this->args['target_account_first_name'],
56+
$this->args['target_account_last_name'],
57+
$this->args['target_account_email']
58+
);
59+
60+
$this->clientService->showDoneTemplateFromManifest(
61+
$this->codeExampleText,
62+
json_encode($assetGroupAccountClone->__toString())
63+
);
64+
} catch (ApiException $e) {
65+
$this->clientService->showErrorTemplate($e);
66+
}
67+
}
68+
69+
/**
70+
* Get specific template arguments
71+
*
72+
* @return array
73+
*/
74+
public function getTemplateArgs(): array
75+
{
76+
return [
77+
'account_id' => $_SESSION['ds_account_id'],
78+
'ds_access_token' => $_SESSION['ds_access_token'],
79+
'source_account_id' => $this->checkInputValues($_POST['source_account_id']),
80+
'target_account_name' => $this->checkInputValues($_POST['target_account_name']),
81+
'target_account_first_name' => $this->checkInputValues($_POST['target_account_first_name']),
82+
'target_account_last_name' => $this->checkInputValues($_POST['target_account_last_name']),
83+
'target_account_email' => $this->checkInputValues($_POST['target_account_email']),
84+
];
85+
}
86+
}

src/Services/AdminApiClientService.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use DocuSign\Admin\Api\BulkImportsApi;
1010
use DocuSign\Admin\Api\DSGroupsApi;
1111
use DocuSign\Admin\Api\ProductPermissionProfilesApi;
12+
use DocuSign\Admin\Api\ProvisionAssetGroupApi;
1213
use DocuSign\Admin\Client\ApiClient;
1314
use DocuSign\Admin\Api\UsersApi;
1415
use DocuSign\Admin\Configuration;
@@ -81,6 +82,14 @@ public function permProfilesApi(): ProductPermissionProfilesApi
8182
return new ProductPermissionProfilesApi($this->apiClient);
8283
}
8384

85+
/**
86+
* Get provision asset group api
87+
*/
88+
public function provisionAssetGroupApi(): ProvisionAssetGroupApi
89+
{
90+
return new ProvisionAssetGroupApi($this->apiClient);
91+
}
92+
8493
/**
8594
* Get Org Admin Id
8695
*
@@ -95,7 +104,6 @@ public function getOrgAdminId(): String
95104
throw new ApiException ("You must create an organization for this account to use the DocuSign Admin API. For details, see <a target='_blank' href='https://support.docusign.com/guides/org-admin-guide'> this support article.</a>", 1);
96105
else
97106
return $orgs["organizations"][0]["id"];
98-
99107
}
100108

101109
/**
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace Example\Services\Examples\Admin;
4+
5+
use DocuSign\Admin\Api\ProvisionAssetGroupApi;
6+
use DocuSign\Admin\Api\ProvisionAssetGroupApi\GetAssetGroupAccountsOptions;
7+
use DocuSign\Admin\Client\ApiException;
8+
use DocuSign\Admin\Model\AssetGroupAccountClone;
9+
use DocuSign\Admin\Model\AssetGroupAccountCloneSourceAccount;
10+
use DocuSign\Admin\Model\AssetGroupAccountCloneTargetAccount;
11+
use DocuSign\Admin\Model\AssetGroupAccountCloneTargetAccountAdmin;
12+
use DocuSign\Admin\Model\AssetGroupAccountsResponse;
13+
14+
class CloneAccountService
15+
{
16+
/**
17+
* Get all accounts in asset groups for the organization.
18+
* @param ProvisionAssetGroupApi $provisionAssetGroupApi
19+
* @param string $organizationId
20+
* @return AssetGroupAccountsResponse
21+
* @throws ApiException
22+
*/
23+
public static function getAccounts(
24+
ProvisionAssetGroupApi $provisionAssetGroupApi,
25+
string $organizationId
26+
): AssetGroupAccountsResponse {
27+
#ds-snippet-start:Admin12Step3
28+
$options = new GetAssetGroupAccountsOptions();
29+
$options->setCompliant(true);
30+
31+
return $provisionAssetGroupApi->getAssetGroupAccounts($organizationId, $options);
32+
#ds-snippet-end:Admin12Step3
33+
}
34+
35+
/**
36+
* Clones an existing DocuSign account to a new DocuSign account
37+
* @param ProvisionAssetGroupApi $provisionAssetGroupApi
38+
* @param string $organizationId
39+
* @param string $sourceAccountId
40+
* @param string $targetAccountName
41+
* @param string $targetAccountFirstName
42+
* @param string $targetAccountLastName
43+
* @param string $targetAccountEmail
44+
* @return AssetGroupAccountClone
45+
* @throws ApiException
46+
*/
47+
public static function cloneAccount(
48+
ProvisionAssetGroupApi $provisionAssetGroupApi,
49+
string $organizationId,
50+
string $sourceAccountId,
51+
string $targetAccountName,
52+
string $targetAccountFirstName,
53+
string $targetAccountLastName,
54+
string $targetAccountEmail
55+
): AssetGroupAccountClone {
56+
#ds-snippet-start:Admin12Step4
57+
$countryCode = "US";
58+
59+
$accountData = new AssetGroupAccountClone([
60+
'source_account' => new AssetGroupAccountCloneSourceAccount(
61+
[
62+
'id' => $sourceAccountId,
63+
]
64+
),
65+
'target_account' => new AssetGroupAccountCloneTargetAccount(
66+
[
67+
'name' => $targetAccountName,
68+
'country_code' => $countryCode,
69+
'admin' => new AssetGroupAccountCloneTargetAccountAdmin(
70+
[
71+
'first_name' => $targetAccountFirstName,
72+
'last_name' => $targetAccountLastName,
73+
'email' => $targetAccountEmail,
74+
]
75+
),
76+
]
77+
),
78+
]);
79+
#ds-snippet-end:Admin12Step4
80+
81+
#ds-snippet-start:Admin12Step5
82+
return $provisionAssetGroupApi->cloneAssetGroupAccount($organizationId, $accountData);
83+
#ds-snippet-end:Admin12Step5
84+
}
85+
}

src/Services/RouterService.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class RouterService implements IRouterService
8787
'aeg009' => 'Admin\EG009DeleteUserProductPermissionProfile',
8888
'aeg010' => 'Admin\EG010DeleteUserDataFromOrganization',
8989
'aeg011' => 'Admin\EG011DeleteUserDataFromAccount',
90+
'aeg012' => 'Admin\EG012CloneAccount',
9091
];
9192
/**
9293
* The list of templates with examples
@@ -166,7 +167,7 @@ class RouterService implements IRouterService
166167
"aeg009" => "admin/eg009_delete_user_product_permission_profile.html",
167168
"aeg010" => "admin/eg010_delete_user_data_from_organization.html",
168169
"aeg011" => "admin/eg011_delete_user_data_from_account.html",
169-
170+
"aeg012" => "admin/eg012_clone_account.html",
170171
];
171172

172173
/**
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
4+
{% set formNumber = 0 %}
5+
{% set sourceAccountIdInputNumber = 0 %}
6+
{% set targetAccountNameInputNumber = 1 %}
7+
{% set targetAccountFirstNameInputNumber = 2 %}
8+
{% set targetAccountLastNameInputNumber = 3 %}
9+
{% set targetAccountEmailInputNumber = 4 %}
10+
11+
<h4>{{ code_example_text['ExampleName'] | raw }}</h4>
12+
13+
<p>{{ code_example_text["ExampleDescription"] | raw }}</p>
14+
15+
16+
{% if show_doc %}
17+
<p><a target='_blank' href='{{ documentation | raw }}'>Documentation</a> about this example.</p>
18+
{% endif %}
19+
20+
<p>
21+
{% if code_example_text["LinksToAPIMethod"] | length == 1 %}
22+
<span>{{ common_texts["APIMethodUsed"] | raw }}</span>
23+
{% else %}
24+
<span>{{ common_texts["APIMethodUsedPlural"] | raw }}</span>
25+
{% endif %}
26+
27+
{% for i in 0..(code_example_text["LinksToAPIMethod"] | length - 1) %}
28+
<a target='_blank' href="{{ example['LinksToAPIMethod'][i]['Path'] }}">
29+
{{ code_example_text['LinksToAPIMethod'][i]['PathName'] | raw}}
30+
</a>
31+
32+
{% if i + 1 == code_example_text["LinksToAPIMethod"] | length - 1 %}
33+
<span>and</span>
34+
{% elseif i + 1 != code_example_text["LinksToAPIMethod"] | length %}
35+
<span>,</span>
36+
{% endif %}
37+
{% endfor %}
38+
</p>
39+
40+
<p>
41+
{{ common_texts["ViewSourceFile"]|replace({ ("{0}"): ("<a target='_blank' href='%s'>%s</a>"|format(source_url, source_file)) })| raw }}
42+
</p>
43+
44+
<form class="eg" action="" method="post">
45+
<div class="form-group">
46+
<label for="source_account_id">
47+
{{ code_example_text['Forms'][formNumber]['Inputs'][sourceAccountIdInputNumber]['InputName'] | raw }}
48+
</label>
49+
50+
<select id="source_account_id" name="source_account_id" class="form-control">
51+
{% for group in args['groups'] %}
52+
<option value="{{ group['account_id'] }}"> {{ group['account_name'] }} </option>
53+
{% endfor %}
54+
</select>
55+
</div>
56+
57+
<div class="form-group">
58+
<label for="target_account_name">
59+
{{ code_example_text['Forms'][formNumber]['Inputs'][targetAccountNameInputNumber]['InputName'] | raw }}
60+
</label>
61+
62+
<input type="text"
63+
class="form-control"
64+
id="target_account_name"
65+
name="target_account_name"
66+
placeholder="{{code_example_text['Forms'][formNumber]['Inputs'][targetAccountNameInputNumber]['InputPlaceholder']}}"
67+
required>
68+
</div>
69+
70+
<div class="form-group">
71+
<label for="target_account_first_name">
72+
{{ code_example_text['Forms'][formNumber]['Inputs'][targetAccountFirstNameInputNumber]['InputName'] | raw }}
73+
</label>
74+
75+
<input type="text"
76+
class="form-control"
77+
id="target_account_first_name"
78+
name="target_account_first_name"
79+
placeholder="{{code_example_text['Forms'][formNumber]['Inputs'][targetAccountFirstNameInputNumber]['InputPlaceholder']}}"
80+
required>
81+
</div>
82+
83+
<div class="form-group">
84+
<label for="target_account_last_name">
85+
{{ code_example_text['Forms'][formNumber]['Inputs'][targetAccountLastNameInputNumber]['InputName'] | raw }}
86+
</label>
87+
88+
<input type="text"
89+
class="form-control"
90+
id="target_account_last_name"
91+
name="target_account_last_name"
92+
placeholder="{{code_example_text['Forms'][formNumber]['Inputs'][targetAccountLastNameInputNumber]['InputPlaceholder']}}"
93+
required>
94+
</div>
95+
96+
<div class="form-group">
97+
<label for="target_account_email">
98+
{{ code_example_text['Forms'][formNumber]['Inputs'][targetAccountEmailInputNumber]['InputName'] | raw }}
99+
</label>
100+
101+
<input type="email"
102+
class="form-control"
103+
id="target_account_email"
104+
name="target_account_email"
105+
aria-describedby="emailHelp"
106+
placeholder="{{code_example_text['Forms'][formNumber]['Inputs'][targetAccountEmailInputNumber]['InputPlaceholder']}}"
107+
required>
108+
</div>
109+
110+
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
111+
<button type="submit" class="btn btn-primary">{{ common_texts["SubmitButton"] | raw }}</button>
112+
</form>
113+
114+
{% endblock %}

tests/JWTLoginMethod.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public static function jwtAuthenticationMethod(string $apiType, TestConfig $test
3333
$scopes = "signature click.manage click.send";
3434
} elseif ($apiType == ApiTypes::Admin) {
3535
$scopes = "signature user_write group_read organization_read permission_read user_read "
36-
. "account_read domain_read identity_provider_read user_data_redact";
36+
. "account_read domain_read identity_provider_read user_data_redact"
37+
. "asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read";
3738
} else {
3839
$scopes = "signature";
3940
}
@@ -57,7 +58,7 @@ public static function jwtAuthenticationMethod(string $apiType, TestConfig $test
5758
$testConfig->setAccessToken($access_token);
5859
}
5960
} catch (\Throwable $th) {
60-
if (str_contains($th->getMessage(), "consent_required")) {
61+
if (strpos($th->getMessage(), "consent_required") !== false) {
6162
$authorizationURL = 'https://account-d.docusign.com/oauth/auth?' .
6263
http_build_query([
6364
'scope' => $scopes,

0 commit comments

Comments
 (0)