Skip to content

Commit e8aaa12

Browse files
Version 4.10.1-v2-20.3.01 release (#230)
Co-authored-by: DevCenter-DocuSign <[email protected]>
1 parent e099534 commit e8aaa12

File tree

8 files changed

+3188
-23
lines changed

8 files changed

+3188
-23
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# DocuSign Node Client Changelog
22

33
See [DocuSign Support Center](https://support.docusign.com/en/releasenotes/) for Product Release Notes.
4+
## [v4.10.1] - eSignature API v2-20.3.01
5+
### Fixed
6+
- DCM-3866, Added support for updateBrandResourcesByContentType function to take in file to upload.
7+
- DCM-3369, Updated ApiClient to use an empty JSON object if the body is null.
8+
- DCM-4614, Fixed out of memory issue when deserializing large files.
9+
410
## [v4.10.0] - eSignature API v2-20.3.00
511
### Changed
612
- Added support for version v2-20.3.00 of the DocuSign eSignature API.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "docusign-esign",
3-
"version": "4.10.0",
3+
"version": "4.10.1",
44
"description": "DocuSign Node.js API client.",
55
"license": "MIT",
66
"main": "src/index.js",

src/ApiClient.js

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,22 @@
445445
// Rely on SuperAgent for parsing response body.
446446
// See http://visionmedia.github.io/superagent/#parsing-response-bodies
447447
var data = response.body || (response.res && response.res.data);
448-
if (data == null || !Object.keys(data).length) {
448+
if (data == null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) {
449449
// SuperAgent does not always produce a body; use the unparsed response as a fallback
450450
data = response.text;
451451
}
452452
return exports.convertToType(data, returnType);
453453
};
454454

455+
exports.prototype.hasBufferFormParam = function(formParams) {
456+
if (!formParams) {
457+
return false;
458+
}
459+
return Object.keys(formParams).some(function(key) {
460+
return formParams[key] instanceof Buffer;
461+
});
462+
};
463+
455464
/**
456465
* (Optional)Callback function to receive the result of the <operationId> operation. If none specified a Promise will be returned.
457466
* @callback module:ApiClient~callApiCallback
@@ -484,7 +493,8 @@
484493
var _this = this;
485494
var url = this.buildUrl(path, pathParams);
486495
var request = superagent(httpMethod, url);
487-
496+
var _formParams = this.normalizeParams(formParams);
497+
var body = bodyParam || {};
488498
// apply authentications
489499
this.applyAuthToRequest(request, authNames);
490500

@@ -513,19 +523,32 @@
513523
if (contentType === 'application/x-www-form-urlencoded') {
514524
request.send(this.normalizeParams(formParams));
515525
} else if (contentType == 'multipart/form-data') {
516-
var _formParams = this.normalizeParams(formParams);
517-
for (var key in _formParams) {
518-
if (_formParams.hasOwnProperty(key)) {
519-
if (this.isFileParam(_formParams[key])) {
520-
// file field
521-
request.attach(key, _formParams[key]);
522-
} else {
523-
request.field(key, _formParams[key]);
526+
if (this.hasBufferFormParam(_formParams)) {
527+
var formAttachmentKey = Object.keys(formParams).find(function(key) {
528+
return _this.isFileParam(_formParams[key]);
529+
});
530+
request.set({
531+
'Content-Disposition': 'form-data; name="file"; filename="file.xml"'
532+
});
533+
request.set({
534+
'Content-Type': 'application/octet-stream'
535+
});
536+
request.send(removeNulls(formParams[formAttachmentKey]));
537+
} else {
538+
var _formParams = this.normalizeParams(formParams);
539+
for (var key in _formParams) {
540+
if (_formParams.hasOwnProperty(key)) {
541+
if (this.isFileParam(_formParams[key])) {
542+
// file field
543+
request.attach(key, _formParams[key]);
544+
} else {
545+
request.field(key, _formParams[key]);
546+
}
524547
}
525548
}
526549
}
527-
} else if (bodyParam) {
528-
request.send(removeNulls(bodyParam));
550+
} else if (body) {
551+
request.send(removeNulls(body));
529552
}
530553

531554
var accept = this.jsonPreferredMime(accepts);
@@ -556,7 +579,6 @@
556579
})
557580
}
558581

559-
560582
var data = null;
561583
if (!callback) {
562584
return new Promise(function(resolve, reject){
@@ -791,7 +813,6 @@
791813
});
792814
});
793815
} catch (err) {
794-
console.log(err)
795816
throw(err)
796817
}
797818
} else {
@@ -911,4 +932,4 @@
911932
}));
912933

913934
module.exports.OAuth = require('./OAuth');
914-
module.exports.RestApi = require('./RestApi');
935+
module.exports.RestApi = require('./RestApi');

src/api/AccountsApi.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ A 201 code is returned if the call succeeded. While the call may have succeed,
182182
An error is returned if `brandId` property for a brand profile is already set for the account. To upload a new version of an existing brand profile, you must delete the profile and then upload the newer version.
183183
184184
When brand profile files are being uploaded, they must be combined into one zip file and the `Content-Type` must be `application/zip`.
185-
* @param {String} accountId The external account number (int) or account ID Guid.
185+
* @param {String} accountId The external account number (int) or account id GUID.
186186
* @param {Object} optsOrCallback Optional parameters, if you are passing no optional parameters, you can either pass a null or omit this parameter entirely.
187187
* @param {module:model/Brand} optsOrCallback.brand
188188
* @param {module:api/AccountsApi~createBrandCallback} callback The callback function, accepting three arguments: error, data, response
@@ -2624,13 +2624,14 @@ Users with account administration privileges can retrieve shared access informat
26242624

26252625
/**
26262626
* Uploads a branding resource file.
2627-
* @param {String} accountId The external account number (int) or account ID Guid.
2627+
* @param {String} accountId The external account number (int) or account id GUID.
26282628
* @param {String} brandId The unique identifier of a brand.
26292629
* @param {String} resourceContentType
2630+
* @param {Object} fileXml Brand resource XML file.
26302631
* @param {module:api/AccountsApi~updateBrandResourcesByContentTypeCallback} callback The callback function, accepting three arguments: error, data, response
26312632
* data is of type: {@link module:model/BrandResources}
26322633
*/
2633-
this.updateBrandResourcesByContentType = function(accountId, brandId, resourceContentType, callback) {
2634+
this.updateBrandResourcesByContentType = function(accountId, brandId, resourceContentType, fileXml, callback) {
26342635
var postBody = null;
26352636

26362637
// verify the required parameter 'accountId' is set
@@ -2648,6 +2649,11 @@ Users with account administration privileges can retrieve shared access informat
26482649
throw new Error("Missing the required parameter 'resourceContentType' when calling updateBrandResourcesByContentType");
26492650
}
26502651

2652+
// verify the required parameter 'fileXml' is set
2653+
if (fileXml === undefined || fileXml === null) {
2654+
throw new Error("Missing the required parameter 'fileXml' when calling updateBrandResourcesByContentType");
2655+
}
2656+
26512657
if (typeof callback !== 'function' && arguments.length && typeof arguments[arguments.length-1] === 'function'){
26522658
if (typeof optsOrCallback !== 'undefined') {
26532659
optsOrCallback = callback;
@@ -2665,10 +2671,11 @@ Users with account administration privileges can retrieve shared access informat
26652671
var headerParams = {
26662672
};
26672673
var formParams = {
2674+
'file.xml': fileXml
26682675
};
26692676

26702677
var authNames = ['docusignAccessCode'];
2671-
var contentTypes = [];
2678+
var contentTypes = ['multipart/form-data'];
26722679
var accepts = ['application/json'];
26732680
var returnType = BrandResources;
26742681

test/SdkUnitTests.js

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ var assert = require('assert');
1111
var path = require('path');
1212
var superagent = require('superagent');
1313
var csvStringify = require('csv-stringify');
14-
14+
var brandXmlPath = 'docs/brand.xml';
1515
var Buffer = global.Buffer.from ? global.Buffer : require('safe-buffer').Buffer;
1616
var fs = require('fs');
1717

@@ -28,6 +28,7 @@ var basePath = restApi.BasePath.DEMO;
2828
var oAuthBasePath = oAuth.BasePath.DEMO;
2929

3030
var SignTest1File = 'docs/SignTest1.pdf';
31+
var LargeTestDocument1 = 'docs/LargeTestDocument1.pdf';
3132
var brandLogoPath = 'img/docusign-lgo.png';
3233
var accountId = '';
3334
var envelopeId = '';
@@ -678,7 +679,7 @@ describe('SDK Unit Tests:', function (done) {
678679
try {
679680
var fs = require('fs');
680681
// read file from a local directory
681-
fileBytes = fs.readFileSync(path.resolve(__dirname, SignTest1File));
682+
fileBytes = fs.readFileSync(path.resolve(__dirname, LargeTestDocument1));
682683
} catch (ex) {
683684
// handle error
684685
console.log('Exception: ' + ex);
@@ -1132,4 +1133,113 @@ describe('SDK Unit Tests:', function (done) {
11321133
}
11331134
});
11341135
});
1136+
1137+
it('it updateBrandResourcesByContentType', function (done) {
1138+
var accountsApi = new docusign.AccountsApi(apiClient);
1139+
accountsApi.listBrands(accountId, { includeLogos: true })
1140+
.then(function (brandsData) {
1141+
var currentBrand = brandsData.brands[0];
1142+
var brandXmlBuffer = fs.readFileSync(path.resolve(__dirname, brandXmlPath));
1143+
accountsApi.updateBrandResourcesByContentType(accountId, currentBrand.brandId, 'email', brandXmlBuffer)
1144+
.then(function (data) {
1145+
assert.notEqual(data.createdByUserInfo, undefined);
1146+
assert.notEqual(data.resourcesContentUri, undefined);
1147+
return done();
1148+
})
1149+
.catch(function (error) {
1150+
return done(error);
1151+
});
1152+
})
1153+
.catch(function (error) {
1154+
return done(error);
1155+
});
1156+
});
1157+
1158+
it('resend envelope with envelope update', function (done) {
1159+
var fileBytes = null;
1160+
try {
1161+
var fs = require('fs');
1162+
// read file from a local directory
1163+
fileBytes = fs.readFileSync(path.resolve(__dirname, SignTest1File));
1164+
} catch (ex) {
1165+
// handle error
1166+
console.log('Exception: ' + ex);
1167+
}
1168+
1169+
// create an envelope to be signed
1170+
var envDef = new docusign.EnvelopeDefinition();
1171+
envDef.emailSubject = 'Please Sign my Node SDK Envelope';
1172+
envDef.emailBlurb = 'Hello, Please sign my Node SDK Envelope.';
1173+
1174+
// add a document to the envelope
1175+
var doc = new docusign.Document();
1176+
var base64Doc = Buffer.from(fileBytes).toString('base64');
1177+
doc.documentBase64 = base64Doc;
1178+
doc.name = 'TestFile.pdf';
1179+
doc.documentId = '1';
1180+
1181+
var docs = [];
1182+
docs.push(doc);
1183+
envDef.documents = docs;
1184+
1185+
// Add a recipient to sign the document
1186+
var signer = new docusign.Signer();
1187+
signer.email = userName;
1188+
var name = 'Pat Developer';
1189+
signer.name = name;
1190+
signer.recipientId = '1';
1191+
1192+
// this value represents the client's unique identifier for the signer
1193+
var clientUserId = '2939';
1194+
signer.clientUserId = clientUserId;
1195+
1196+
// create a signHere tab somewhere on the document for the signer to sign
1197+
// default unit of measurement is pixels, can be mms, cms, inches also
1198+
var signHere = new docusign.SignHere();
1199+
signHere.documentId = '1';
1200+
signHere.pageNumber = '1';
1201+
signHere.recipientId = '1';
1202+
signHere.xPosition = '100';
1203+
signHere.yPosition = '100';
1204+
1205+
// can have multiple tabs, so need to add to envelope as a single element list
1206+
var signHereTabs = [];
1207+
signHereTabs.push(signHere);
1208+
var tabs = new docusign.Tabs();
1209+
tabs.signHereTabs = signHereTabs;
1210+
signer.tabs = tabs;
1211+
1212+
// Above causes issue
1213+
envDef.recipients = new docusign.Recipients();
1214+
envDef.recipients.signers = [];
1215+
envDef.recipients.signers.push(signer);
1216+
1217+
// send the envelope (otherwise it will be "created" in the Draft folder
1218+
envDef.status = 'sent';
1219+
1220+
var envelopesApi = new docusign.EnvelopesApi(apiClient);
1221+
1222+
envelopesApi.createEnvelope(accountId, { envelopeDefinition: envDef })
1223+
.then(function (envelopeSummary) {
1224+
if (envelopeSummary) {
1225+
envelopesApi.update(accountId, envelopeSummary.envelopeId, { resendEnvelope: true })
1226+
.then(function (envelopeUpdateSummary) {
1227+
if (envelopeUpdateSummary) {
1228+
console.log('envelopeUpdateSummary: ' + JSON.stringify(envelopeUpdateSummary));
1229+
done();
1230+
}
1231+
})
1232+
.catch(function (error) {
1233+
if (error) {
1234+
return done(error);
1235+
}
1236+
});
1237+
}
1238+
})
1239+
.catch(function (error) {
1240+
if (error) {
1241+
return done(error);
1242+
}
1243+
});
1244+
});
11351245
});

0 commit comments

Comments
 (0)