Skip to content

Commit c97070b

Browse files
Account cloning code example (#140)
* added code example * change the region with countryCode * fixes * remove space * DEVDOCS-12276 fixing template index --------- Co-authored-by: Paige Rossi <[email protected]>
1 parent df7928c commit c97070b

File tree

9 files changed

+857
-34
lines changed

9 files changed

+857
-34
lines changed

index.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ const flash = require('express-flash');
1818
const helmet = require('helmet'); // https://expressjs.com/en/advanced/best-practice-security.html
1919
const moment = require('moment');
2020
const csrf = require('csurf'); // https://www.npmjs.com/package/csurf
21-
const examplesApi = require('./config/examplesAPI.json');
2221
const { getManifest } = require('./lib/manifestService')
2322

2423
const eg001 = require('./lib/eSignature/controllers/eg001EmbeddedSigning');
@@ -51,7 +50,7 @@ const {
5150
eg001admin, eg002admin, eg003admin,
5251
eg004admin, eg005admin, eg006admin,
5352
eg007admin, eg008admin, eg009admin,
54-
eg010admin, eg011admin
53+
eg010admin, eg011admin, eg012admin
5554
} = require("./lib/admin/controllers");
5655

5756
const PORT = process.env.PORT || 3000;
@@ -175,6 +174,8 @@ app.get('/aeg001', eg001admin.getController)
175174
.post('/aeg010', eg010admin.createController)
176175
.get('/aeg011', eg011admin.getController)
177176
.post('/aeg011', eg011admin.createController)
177+
.get('/aeg012', eg012admin.getController)
178+
.post('/aeg012', eg012admin.createController)
178179

179180
app.get('/eg001', eg001.getController)
180181
.post('/eg001', eg001.createController)
@@ -302,10 +303,11 @@ const MONITOR_SCOPES = [
302303
"signature", "impersonation"
303304
];
304305
const ADMIN_SCOPES = [
305-
"organization_read", "group_read", "permission_read ",
306+
"organization_read", "group_read", "permission_read",
306307
"user_read", "user_write", "account_read",
307308
"domain_read", "identity_provider_read", "signature",
308-
"user_data_redact"
309+
"user_data_redact", "asset_group_account_read", "asset_group_account_clone_write",
310+
"asset_group_account_clone_read"
309311
];
310312

311313
const scope = [...ROOM_SCOPES, ...CLICK_SCOPES, ...MONITOR_SCOPES, ...ADMIN_SCOPES, ...SCOPES];

lib/DSJwtAuth.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let DsJwtAuth = function _DsJwtAuth(req) {
1818
this.accountName = req.user && req.user.accountName;
1919
this.basePath = req.user && req.user.basePath;
2020
this._tokenExpiration = req.user && req.user.tokenExpirationTimestamp;
21-
this.scopes = "signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact";
21+
this.scopes = "signature dtr.rooms.read dtr.rooms.write dtr.documents.read dtr.documents.write dtr.profile.read dtr.profile.write dtr.company.read dtr.company.write room_forms click.manage click.send organization_read group_read permission_read user_read user_write account_read domain_read identity_provider_read user_data_redact asset_group_account_read asset_group_account_clone_write asset_group_account_clone_read";
2222

2323
// For production use, you'd want to store the refresh token in non-volatile storage since it is
2424
// good for 30 days. You'd probably want to encrypt it too.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* @file
3+
* Example 012: How to clone an account
4+
* @author DocuSign
5+
*/
6+
7+
const path = require('path');
8+
const validator = require('validator');
9+
const dsConfig = require('../../../config/index.js').config;
10+
const { cloneAccount, getAccounts } = require('../examples/cloneAccount');
11+
const { getOrganizationId } = require("../getOrganizationId.js");
12+
const { getExampleByNumber } = require("../../manifestService");
13+
const { API_TYPES } = require('../../utils.js');
14+
15+
const eg012CloneAccount = exports;
16+
const exampleNumber = 12;
17+
const eg = `aeg0${exampleNumber}`; // This example reference.
18+
const api = API_TYPES.ADMIN;
19+
const mustAuthenticate = '/ds/mustAuthenticate';
20+
const minimumBufferMin = 3;
21+
22+
/**
23+
* Clone an account
24+
* @param {object} req Request obj
25+
* @param {object} res Response obj
26+
*/
27+
eg012CloneAccount.createController = async(req, res) => {
28+
// Step 1. Check the token
29+
// At this point we should have a good token. But we
30+
// double-check here to enable a better UX to the user.
31+
const isTokenOK = req.dsAuth.checkToken(minimumBufferMin);
32+
if (!isTokenOK) {
33+
req.flash('info', 'Sorry, you need to re-authenticate.');
34+
// Save the current operation so it will be resumed after authentication
35+
req.dsAuth.setEg(req, eg);
36+
return res.redirect(mustAuthenticate);
37+
}
38+
39+
const { body } = req;
40+
const args = {
41+
accessToken: req.user.accessToken,
42+
basePath: dsConfig.adminAPIUrl,
43+
organizationId: req.session.organizationId,
44+
sourceAccountId: validator.escape(body.sourceAccountId),
45+
targetAccountName: validator.escape(body.targetAccountName),
46+
targetAccountFirstName: validator.escape(body.targetAccountFirstName),
47+
targetAccountLastName: validator.escape(body.targetAccountLastName),
48+
targetAccountEmail: validator.escape(body.targetAccountEmail),
49+
};
50+
51+
let results = null;
52+
53+
try {
54+
results = await cloneAccount(args);
55+
} catch (error) {
56+
// we can pull the DocuSign error code and message from the response body
57+
const errorBody = error?.response?.body;
58+
const errorCode = errorBody?.errorCode;
59+
const errorMessage = errorBody?.message;
60+
61+
// In production, may want to provide customized error messages and
62+
// remediation advice to the user.
63+
res.render('pages/error', { err: error, errorCode, errorMessage });
64+
}
65+
if (results) {
66+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
67+
res.render('pages/example_done', {
68+
title: example.ExampleName,
69+
message: example.ResultsPageText,
70+
json: JSON.stringify(results)
71+
});
72+
}
73+
}
74+
75+
/**
76+
* Form page for this application
77+
*/
78+
eg012CloneAccount.getController = async (req, res) => {
79+
// Check that the authentication token is ok with a long buffer time.
80+
// If needed, now is the best time to ask the user to authenticate
81+
// since they have not yet entered any information into the form.
82+
83+
const isTokenOK = req.dsAuth.checkToken();
84+
if (!isTokenOK) {
85+
// Save the current operation so it will be resumed after authentication
86+
req.dsAuth.setEg(req, eg);
87+
return res.redirect(mustAuthenticate);
88+
}
89+
90+
try {
91+
await getOrganizationId(req)
92+
const args = {
93+
accessToken: req.user.accessToken,
94+
basePath: dsConfig.adminAPIUrl,
95+
organizationId: req.session.organizationId
96+
};
97+
98+
const accounts = await getAccounts(args);
99+
100+
const example = getExampleByNumber(res.locals.manifest, exampleNumber, api);
101+
const sourceFile = (path.basename(__filename))[5].toLowerCase() + (path.basename(__filename)).substr(6);
102+
res.render('pages/admin-examples/eg012CloneAccount', {
103+
eg: eg,
104+
csrfToken: req.csrfToken(),
105+
example: example,
106+
sourceFile: sourceFile,
107+
sourceUrl: dsConfig.githubExampleUrl + "admin/examples/" + sourceFile,
108+
documentation: dsConfig.documentation + eg,
109+
showDoc: dsConfig.documentation,
110+
accounts: accounts.assetGroupAccounts,
111+
});
112+
} catch (error) {
113+
const errorCode = error?.response?.body?.errorCode;
114+
const errorMessage = error?.response?.body?.message;
115+
116+
// In production, may want to provide customized error messages and
117+
// remediation advice to the user.
118+
res.render('pages/error', { err: error, errorCode, errorMessage });
119+
}
120+
}
121+

lib/admin/controllers/index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ module.exports.eg004admin = require('./eg004ImportUser');
55
module.exports.eg005admin = require('./eg005AuditUsers');
66
module.exports.eg006admin = require('./eg006GetUserProfileByEmail');
77
module.exports.eg007admin = require('./eg007GetUserProfileByUserId');
8-
module.exports.eg008admin = require('./eg008UpdateUserProductPermissionProfile')
9-
module.exports.eg009admin = require('./eg009DeleteUserProductPermissionProfile')
10-
module.exports.eg010admin = require('./eg010DeleteUserDataFromOrganization')
11-
module.exports.eg011admin = require('./eg011DeleteUserDataFromAccount')
8+
module.exports.eg008admin = require('./eg008UpdateUserProductPermissionProfile');
9+
module.exports.eg009admin = require('./eg009DeleteUserProductPermissionProfile');
10+
module.exports.eg010admin = require('./eg010DeleteUserDataFromOrganization');
11+
module.exports.eg011admin = require('./eg011DeleteUserDataFromAccount');
12+
module.exports.eg012admin = require('./eg012CloneAccount');

lib/admin/examples/cloneAccount.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const docusignAdmin = require('docusign-admin');
2+
3+
/**
4+
* This function clones an account
5+
* @param {object} args parameters for account cloning
6+
* @returns {docusignAdmin.AssetGroupAccountClone} Summary of cloning an account
7+
*/
8+
const cloneAccount = async(args) => {
9+
//ds-snippet-start:Admin12Step2
10+
const apiClient = new docusignAdmin.ApiClient();
11+
apiClient.setBasePath(args.basePath);
12+
apiClient.addDefaultHeader("Authorization", "Bearer " + args.accessToken);
13+
//ds-snippet-end:Admin12Step2
14+
15+
//ds-snippet-start:Admin12Step4
16+
const accountData = docusignAdmin.AssetGroupAccountClone.constructFromObject({
17+
sourceAccount: {
18+
id: args.sourceAccountId,
19+
},
20+
targetAccount: {
21+
name: args.targetAccountName,
22+
admin: {
23+
firstName: args.targetAccountFirstName,
24+
lastName: args.targetAccountLastName,
25+
email: args.targetAccountEmail,
26+
},
27+
countryCode: 'US',
28+
}
29+
});
30+
//ds-snippet-end:Admin12Step4
31+
32+
//ds-snippet-start:Admin12Step5
33+
const assetGroupApi = new docusignAdmin.ProvisionAssetGroupApi(apiClient);
34+
return assetGroupApi.cloneAssetGroupAccount(accountData, args.organizationId);
35+
//ds-snippet-end:Admin12Step5
36+
}
37+
38+
/**
39+
* Get list of asset group accounts for an organization
40+
* @param {object} args parameters for getting the accounts
41+
* @returns {docusignAdmin.AssetGroupAccountsResponse} Asset group accounts information
42+
*/
43+
const getAccounts = async(args) => {
44+
const apiClient = new docusignAdmin.ApiClient();
45+
apiClient.setBasePath(args.basePath);
46+
apiClient.addDefaultHeader("Authorization", "Bearer " + args.accessToken);
47+
48+
//ds-snippet-start:Admin12Step3
49+
const assetGroupApi = new docusignAdmin.ProvisionAssetGroupApi(apiClient);
50+
const options = {
51+
compliant: true,
52+
};
53+
const accounts = await assetGroupApi.getAssetGroupAccounts(args.organizationId, options);
54+
//ds-snippet-end:Admin12Step3
55+
56+
return accounts;
57+
}
58+
59+
module.exports = { cloneAccount, getAccounts };

0 commit comments

Comments
 (0)