Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit 5c02186

Browse files
kurtripskurtrips
kurtrips
authored and
kurtrips
committed
docusign callback local commit
1 parent c82d0f2 commit 5c02186

28 files changed

+928
-11
lines changed

Diff for: actions/docusign.js

+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
* Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
3+
*
4+
* @version 1.0
5+
* @author TCSASSEMBLER
6+
*/
7+
"use strict";
8+
/*jslint unparam: true */
9+
10+
var _ = require("underscore");
11+
var async = require("async");
12+
var S = require("string");
13+
var config = require("../config").config;
14+
15+
/**
16+
* The TermsOfUse Handler
17+
* Note that just like the Java code, it can be reused for different templates and termsOfUseId
18+
* The contrcutor takes the termsOfUseId during initialization
19+
*/
20+
function TermsOfUseHandler(termsOfUseId) {
21+
this.termsOfUseId = termsOfUseId;
22+
}
23+
TermsOfUseHandler.prototype.termsOfUseId = 0;
24+
/**
25+
* The function that actually handles the document
26+
* All future document handlers must also follow the same method signature as used here (akin to a Java interface)
27+
* @param userId The user for which to handle the document
28+
* @param tabs Arrays of objects which have tabLabel and tabValue parameters.
29+
* This is actually not used here but is needed because the method signature needs to consistent for all document handlers
30+
* @param api The actionhero api object
31+
* @param dbConnectionMap The DB connection map
32+
* @param done The callback to call once done. It will be called with argument if there is error, otherwise will be called without argument.
33+
* The argument must have a message property. If the error is temporary, then it should also have a temporary property set to true.
34+
*/
35+
TermsOfUseHandler.prototype.handleDocument = function (userId, tabs, api, dbConnectionMap, done) {
36+
var sqlParams = {
37+
termsOfUseId: this.termsOfUseId,
38+
userId: userId
39+
};
40+
async.waterfall([
41+
function (cb) {
42+
api.dataAccess.executeQuery("get_terms_of_use", sqlParams, dbConnectionMap, cb);
43+
}, function (rows, cb) {
44+
if (rows.length === 0) {
45+
done({
46+
message: "No terms of use exists for id: " + sqlParams.termsOfUseId,
47+
});
48+
return;
49+
}
50+
api.dataAccess.executeQuery("check_user_terms_of_use_ban", sqlParams, dbConnectionMap, cb);
51+
}, function (rows, cb) {
52+
if (rows.length !== 0) {
53+
api.log("User with id: " + userId + " is not allowed to accept terms of use with id: " + sqlParams.termsOfUseId, 'error');
54+
done();
55+
return;
56+
}
57+
api.dataAccess.executeQuery("check_user_terms_of_use_exist", sqlParams, dbConnectionMap, cb);
58+
}, function (rows, cb) {
59+
if (rows.length !== 0) {
60+
api.log("User with id: " + userId + " has already accepted terms of use with id: " + sqlParams.termsOfUseId, 'warn');
61+
done();
62+
return;
63+
}
64+
api.dataAccess.executeQuery("insert_user_terms_of_use", sqlParams, dbConnectionMap, cb);
65+
}, function (notUsed, cb) {
66+
cb();
67+
}
68+
], function (err) {
69+
if (err) {
70+
//If we have an error here, it is because of unexpected error (like DB connection died)
71+
//So this needs to be considered a temporary failure, so that Docusign Connect can call us again later
72+
done({
73+
message: "Unable to process terms of use. Try again later.",
74+
temporary: true
75+
});
76+
} else {
77+
done();
78+
}
79+
});
80+
};
81+
82+
83+
/**
84+
* Contains the template name, id and the handlers for the template
85+
* Note that there can be more than 1 handlers per template
86+
* Handlers that are not required for this contest are left empty
87+
*/
88+
var templates = [{
89+
name: 'W9',
90+
templateId: config.docusign.w9TemplateId,
91+
handlers: []
92+
}, {
93+
name: 'W-8BEN',
94+
templateId: config.docusign.w8benTemplateId,
95+
handlers: []
96+
}, {
97+
name: 'TopCoder Assignment v2.0',
98+
templateId: config.docusign.assignmentTemplateId,
99+
handlers: [
100+
new TermsOfUseHandler(config.docusign.assignmentDocTermsOfUseId)
101+
]
102+
}, {
103+
name: 'Appirio Mutual NDA',
104+
templateId: config.docusign.mutualNDATemplateId,
105+
handlers: []
106+
}, {
107+
name: 'Affidavit',
108+
templateId: config.docusign.affidavitTemplateId,
109+
handlers: []
110+
}];
111+
112+
/**
113+
* Convenience function that writes the response and calls the actionhero next
114+
* @param connection actionhero connection
115+
* @param statusCode the status code to write
116+
* @param next The actionhero next callback
117+
* @param message If exists then this message is set to body, otherwise body is simply 'success'
118+
*/
119+
function writeResponse(connection, statusCode, next, message) {
120+
connection.rawConnection.responseHttpCode = statusCode;
121+
connection.response = {
122+
message: message || 'success'
123+
};
124+
next(connection, true);
125+
}
126+
127+
/**
128+
* The error to throw if connect key is missing or invalid
129+
*/
130+
var CONNECT_KEY_MISSING = 'Connect Key is missing or invalid.';
131+
132+
/**
133+
* The Docusign Callback Action which accepts JSON.
134+
* Performs the logic common to all Docusign documents.
135+
*/
136+
exports.action = {
137+
name: 'docusignCallback',
138+
description: 'docusignCallback',
139+
blockedConnectionTypes: [],
140+
outputExample: {},
141+
version: 'v2',
142+
transaction : 'write',
143+
cacheEnabled : false,
144+
databases : ["informixoltp", "common_oltp"],
145+
inputs: {
146+
required: ['envelopeStatus', 'envelopeId', 'tabs', 'connectKey'],
147+
optional: [],
148+
},
149+
run: function (api, connection, next) {
150+
api.log("Execute docusignCallback#run", 'debug');
151+
var dbConnectionMap = connection.dbConnectionMap,
152+
envelopeStatus = connection.params.envelopeStatus,
153+
envelopeId = connection.params.envelopeId,
154+
connectKey = connection.params.connectKey,
155+
tabs = connection.params.tabs,
156+
sqlParams = {},
157+
envelopeInfo;
158+
159+
async.waterfall([
160+
function (cb) {
161+
if (connectKey !== config.docusign.callbackConnectKey) {
162+
api.log(CONNECT_KEY_MISSING, 'error');
163+
writeResponse(connection, 404, next, CONNECT_KEY_MISSING);
164+
return;
165+
}
166+
167+
if (envelopeStatus !== 'Completed') {
168+
api.log('Status is not completed.', 'info');
169+
writeResponse(connection, 200, next);
170+
return;
171+
}
172+
173+
if (new S(envelopeId).isEmpty()) {
174+
api.log('envelopeId is null or empty', 'error');
175+
writeResponse(connection, 200, next);
176+
return;
177+
}
178+
179+
//Set completed = 1 for the envelope id
180+
sqlParams.envelopeId = envelopeId;
181+
api.dataAccess.executeQuery("complete_docusign_envelope", sqlParams, dbConnectionMap, cb);
182+
}, function (updatedCount, cb) {
183+
//updatedCount is the number of rows that were updated.
184+
if (updatedCount === 1) {
185+
//Get the docusign data (we need the templateId) for the envelope
186+
api.dataAccess.executeQuery("get_docusign_envelope_by_envelope_id", sqlParams, dbConnectionMap, cb);
187+
} else {
188+
api.log('No enevelope with id: ' + envelopeId + ' was found.', 'error');
189+
writeResponse(connection, 200, next);
190+
return;
191+
}
192+
}, function (rows, cb) {
193+
envelopeInfo = rows[0];
194+
195+
//Find the template for the envelope
196+
var template = _.findWhere(templates, {templateId: envelopeInfo.docusign_template_id});
197+
if (template === undefined) {
198+
api.log('No Template was found for template id: ' + envelopeInfo.docusign_template_id, 'warn');
199+
writeResponse(connection, 200, next);
200+
return;
201+
}
202+
203+
//Call the handlers for the template, one after the other
204+
async.eachSeries(template.handlers, function (handler, cbx) {
205+
handler.handleDocument(envelopeInfo.user_id, tabs, api, dbConnectionMap, cbx);
206+
}, function (err) {
207+
if (err) {
208+
cb(err);
209+
return;
210+
}
211+
cb();
212+
});
213+
}
214+
], function (err) {
215+
if (err) {
216+
//All errors need to be communicated to the support staff
217+
api.tasks.enqueue("sendEmail", {
218+
subject : config.docusign.callbackFailedEmailSubject,
219+
template : 'docusign_callback_failure_email',
220+
toAddress : config.docusign.supportEmailAddress,
221+
fromAddress : config.docusign.fromEmailAddress,
222+
userId : envelopeInfo.user_id,
223+
templateId: envelopeInfo.docusign_template_id,
224+
envelopeId : envelopeInfo.docusign_envelope_id,
225+
message : err.message
226+
}, 'default');
227+
228+
//Only temporary errors are to return 500, otherwise 200
229+
if (err.temporary === true) {
230+
writeResponse(connection, 500, next, err.message);
231+
} else {
232+
writeResponse(connection, 200, next, err.message);
233+
}
234+
} else {
235+
writeResponse(connection, 200, next);
236+
}
237+
});
238+
}
239+
};

Diff for: apiary.apib

+46
Original file line numberDiff line numberDiff line change
@@ -5141,3 +5141,49 @@ Register a new user.
51415141
"value":"503",
51425142
"description":"Servers are up but overloaded. Try again later."
51435143
}
5144+
5145+
## Docusign Callback [/terms/docusignCallback]
5146+
### Docusign Callback [POST]
5147+
5148+
+ Parameters
5149+
+ envelopeStatus (required, String, `Complete`) ... The status of the envelope
5150+
+ envelopeId (required, UUID, `9103DC77-D8F1-4D7B-BED1-6116604EE98C`) ... The envelope to process
5151+
+ tabs (required, Array, [{tabLabel: 'Handle', tabValue: 'anix'}, {...}]) ... The tab values. Can be empty
5152+
+ connectKey (required, String, 'ABCDED-12435-EDFADSEC') The conenct key
5153+
5154+
+ Response 200 (application/json)
5155+
{
5156+
"message": "some message"
5157+
}
5158+
5159+
+ Response 400 (application/json)
5160+
5161+
{
5162+
"name":"Bad Request",
5163+
"value":"400",
5164+
"description":"The request was invalid. An accompanying message will explain why."
5165+
}
5166+
5167+
+ Response 404 (application/json)
5168+
5169+
{
5170+
"name":"Not Found",
5171+
"value":"404",
5172+
"description":"This message will explain why the URI requested is invalid or the resource does not exist."
5173+
}
5174+
5175+
+ Response 500 (application/json)
5176+
5177+
{
5178+
"name":"Internal Server Error",
5179+
"value":"500",
5180+
"description":"Unknown server error. Please contact support."
5181+
}
5182+
5183+
+ Response 503 (application/json)
5184+
5185+
{
5186+
"name":"Service Unavailable",
5187+
"value":"503",
5188+
"description":"Servers are up but overloaded. Try again later."
5189+
}

Diff for: config.js

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*
22
* Copyright (C) 2013 - 2014 TopCoder Inc., All Rights Reserved.
33
*
4-
* @author vangavroche, Ghost_141, kurtrips, Sky_, isv
5-
* @version 1.12
4+
* @author vangavroche, Ghost_141, kurtrips, Sky_, isv, TCSASSEMBLER
5+
* @version 1.13
66
* changes in 1.1:
77
* - add defaultCacheLifetime parameter
88
* changes in 1.2:
@@ -30,6 +30,8 @@
3030
* - added designSubmissionsBasePath for design submissions
3131
* changes in 1.12:
3232
* - add defaultUserCacheLifetime property.
33+
* changes in 1.13:
34+
* - added the docusign object
3335
*/
3436
"use strict";
3537

@@ -284,6 +286,17 @@ config.thurgoodApiKey = process.env.THURGOOD_API_KEY || 'mock_api_key';
284286
//The base folder for design submission files
285287
config.designSubmissionsBasePath = process.env.DESIGN_SUBMISSIONS_BASE_PATH || 'test/tmp/design_submissions';
286288

287-
//////////////////////////////////
289+
config.docusign = {
290+
w9TemplateId: '8E95BEB4-1C77-4CE2-97C7-5F64A3366370',
291+
w8benTemplateId: 'CD415871-17F5-4A1E-A007-FE416B030FFB',
292+
assignmentTemplateId: 'E12C78DE-67B1-4150-BEC8-C44CE20A2F0B',
293+
mutualNDATemplateId: '19D958E1-E2EC-4828-B270-CA8F14CF7BF4',
294+
affidavitTemplateId: '9103DC77-D8F1-4D7B-BED1-6116604EE98C',
295+
assignmentDocTermsOfUseId: 20753,
296+
callbackFailedEmailSubject: 'Processing DocuSign document failed',
297+
callbackConnectKey: 'ABCDED-12435-EDFADSEC',
298+
supportEmailAddress: '[email protected]',
299+
fromEmailAddress: '[email protected]'
300+
};
288301

289302
exports.config = config;

Diff for: deploy/development.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# tests rely on caching being off. But set this to a real value (or remove) while coding.
1313
export CACHE_EXPIRY=-1
1414

15-
VM_IP=informix.cloud.topcoder.com
15+
VM_IP=54.237.172.92
1616
if [ -n "$TC_VM_IP" ]
1717
then
1818
VM_IP=$TC_VM_IP
Binary file not shown.

Diff for: docusign_callback/Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node docusignCallbackListener.js

0 commit comments

Comments
 (0)