Skip to content

Commit 0cb429c

Browse files
authored
Fixed issue with attachments in Bulk (#58)
1 parent 8021f66 commit 0cb429c

File tree

11 files changed

+1339
-802
lines changed

11 files changed

+1339
-802
lines changed

.circleci/config.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ jobs:
7777
- checkout
7878
- node/install:
7979
node-version: << pipeline.parameters.node-version >>
80-
- run:
81-
name: Audit Dependencies
82-
command: npm audit --production --audit-level=high
8380
- node/install-packages:
8481
cache-path: ./node_modules
8582
override-ci-command: npm install
83+
- run:
84+
name: Audit Dependencies
85+
command: npm run audit
8686
- run:
8787
name: Running Mocha Tests
8888
command: npm test
@@ -118,6 +118,8 @@ workflows:
118118
jobs:
119119
- build:
120120
name: "Build and publish docker image"
121+
context:
122+
- componentspusher
121123
filters:
122124
branches:
123125
ignore: /.*/

.grype-ignore.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ignore:
2+
- vulnerability: CVE-2022-3996
3+
package:
4+
name: libssl3
5+
version: 3.0.7-r0
6+
7+
- vulnerability: CVE-2022-3996
8+
package:
9+
name: libcrypto3
10+
version: 3.0.7-r0

.nsprc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"GHSA-27h2-hvpr-p74q": {
3+
"active": true,
4+
"notes": "We don't use verify function from jsonwebtoken, so not affected"
5+
}
6+
}

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 2.5.0 (January 13, 2023)
2+
* Fixed issue with attachments in `Bulk Create/Update/Delete/Upsert` action
3+
* Added ability to directly provide url to csv file in `Bulk Create/Update/Delete/Upsert` action
4+
* Update Sailor version to 2.7.1
5+
* Update component-commons-library version to 3.1.5
6+
17
## 2.4.2 (November 18, 2022)
28
* Improved error handling in `Lookup Objects` action
39

component.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"description": "Customer relationship management (CRM) software & cloud computing from the leader in CRM solutions for businesses large & small.",
44
"docsUrl": "https://github.com/elasticio/salesforce-component-v2",
55
"url": "http://www.salesforce.com/",
6-
"version": "2.4.2",
6+
"version": "2.5.0",
77
"authClientTypes": [
88
"oauth2"
99
],

lib/actions/bulk_cud.js

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
const { messages } = require('elasticio-node');
2-
const { Readable } = require('stream');
3-
const util = require('../util');
2+
const { AttachmentProcessor } = require('@elastic.io/component-commons-library');
3+
const { getUserAgent } = require('../util');
44
const { callJSForceMethod } = require('../helpers/wrapper');
55

66
const DEFAULT_TIMEOUT = 600; // 10 min
77

8-
exports.objectTypes = async function objectTypes(configuration) {
8+
module.exports.objectTypes = async function objectTypes(configuration) {
99
switch (configuration.operation) {
1010
case 'insert': {
1111
return callJSForceMethod.call(this, configuration, 'getCreateableObjectTypes');
@@ -20,27 +20,26 @@ exports.objectTypes = async function objectTypes(configuration) {
2020
}
2121
};
2222

23-
exports.process = async function bulkCUD(message, configuration) {
23+
module.exports.process = async function bulkCUD(message, configuration) {
2424
this.logger.info('Starting Bulk %s action', configuration.operation);
2525
// Get CSV from attachment
26-
if (!message.attachments || Object.keys(message.attachments).length === 0) {
27-
this.logger.error('Attachment not found');
28-
return messages.newMessageWithBody({ });
29-
}
30-
31-
const key = Object.keys(message.attachments)[0];
3226

3327
let timeout = parseInt(configuration.timeout, 10);
3428
if (Number.isNaN(timeout) || (timeout < 0)) {
3529
this.logger.warn(`Timeout is incorrect. Set default value: ${DEFAULT_TIMEOUT} sec.`);
3630
timeout = DEFAULT_TIMEOUT;
3731
}
32+
let { attachmentUrl } = message.body;
33+
if (!attachmentUrl) {
34+
if (!message.attachments || Object.keys(message.attachments).length === 0 || !message.attachments[Object.keys(message.attachments)[0]].url) {
35+
this.logger.error('Attachment not found');
36+
return messages.newMessageWithBody({});
37+
}
38+
attachmentUrl = message.attachments[Object.keys(message.attachments)[0]].url;
39+
}
3840

39-
const result = await util.downloadAttachment(message.attachments[key].url);
40-
41-
const csvStream = new Readable();
42-
csvStream.push(result);
43-
csvStream.push(null);
41+
const attachmentProcessor = new AttachmentProcessor(getUserAgent(), message.id);
42+
const { data: csvStream } = await attachmentProcessor.getAttachment(attachmentUrl, 'stream');
4443

4544
let extra;
4645
if (configuration.operation === 'upsert') {
@@ -54,33 +53,36 @@ exports.process = async function bulkCUD(message, configuration) {
5453
};
5554
const job = await callJSForceMethod.call(this, configuration, 'bulkCreateJob', batchOptions);
5655
const batch = job.createBatch();
57-
return new Promise((resolve, reject) => {
58-
// Upload CSV to SF
59-
batch.execute(csvStream)
60-
// eslint-disable-next-line no-unused-vars
61-
.on('queue', () => {
62-
// Check while job status become JobComplete or Failed, Aborted
63-
batch.poll(1000, timeout * 1000);
64-
}).on('response', (rets) => {
65-
// Retrieve the results of the completed job
66-
// emit results
67-
this.logger.debug('Result receiver. Records count:', rets.length);
68-
const out = messages.newEmptyMessage();
69-
out.body = { result: rets };
70-
resolve(out);
71-
}).on('error', (err) => {
72-
this.logger.error('Job error');
73-
reject(new Error(err.message));
74-
throw Error(`Job error: ${err.message}`);
75-
});
76-
});
56+
try {
57+
const result = await new Promise((resolve, reject) => {
58+
batch.execute(csvStream)
59+
.on('queue', () => {
60+
batch.poll(1000, timeout * 1000);
61+
}).on('response', (rets) => {
62+
resolve(rets);
63+
}).on('error', (err) => {
64+
reject(err);
65+
});
66+
});
67+
this.logger.debug(`Result receiver. Records count: ${result.length}`);
68+
return messages.newMessageWithBody({ result });
69+
} catch (err) {
70+
this.logger.error(`Job error: ${err.message}`);
71+
throw err;
72+
}
7773
};
7874

79-
exports.getMetaModel = async function getMetaModel(configuration) {
75+
module.exports.getMetaModel = async function getMetaModel(configuration) {
8076
const meta = {
8177
in: {
8278
type: 'object',
83-
properties: {},
79+
properties: {
80+
attachmentUrl: {
81+
type: 'string',
82+
required: false,
83+
title: 'Attachment Url',
84+
},
85+
},
8486
},
8587
out: {
8688
type: 'object',

lib/util.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,6 @@ module.exports.uploadAttachment = async (url, payload) => {
4747
});
4848
};
4949

50-
module.exports.downloadAttachment = async (url) => {
51-
const ax = axios.create();
52-
addRetryCountInterceptorToAxios(ax);
53-
const response = await ax.get(url, {
54-
method: 'GET',
55-
timeout: REQUEST_TIMEOUT,
56-
retry: REQUEST_MAX_RETRY,
57-
delay: REQUEST_RETRY_DELAY,
58-
});
59-
return response.data;
60-
};
61-
6250
function getSecretUri(secretId, isRefresh) {
6351
const parsedUrl = new URL(process.env.ELASTICIO_API_URI);
6452
parsedUrl.username = process.env.ELASTICIO_API_USERNAME;

0 commit comments

Comments
 (0)