@pipedream/salesforce_rest_api 1.6.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/add-contact-to-campaign/add-contact-to-campaign.mjs +1 -1
- package/actions/add-lead-to-campaign/add-lead-to-campaign.mjs +1 -1
- package/actions/common/batch-operation.mjs +86 -0
- package/actions/convert-soap-xml-to-json/convert-soap-xml-to-json.mjs +1 -1
- package/actions/create-account/create-account.mjs +1 -1
- package/actions/create-accounts-batch/create-accounts-batch.mjs +22 -0
- package/actions/create-attachment/create-attachment.mjs +1 -1
- package/actions/create-campaign/create-campaign.mjs +1 -1
- package/actions/create-case/create-case.mjs +1 -1
- package/actions/create-casecomment/create-casecomment.mjs +1 -1
- package/actions/create-contact/create-contact.mjs +1 -1
- package/actions/create-content-note/create-content-note.mjs +1 -1
- package/actions/create-event/create-event.mjs +1 -1
- package/actions/create-lead/create-lead.mjs +1 -1
- package/actions/create-note/create-note.mjs +1 -1
- package/actions/create-opportunities-batch/create-opportunities-batch.mjs +22 -0
- package/actions/create-opportunity/create-opportunity.mjs +1 -1
- package/actions/create-record/create-record.mjs +1 -1
- package/actions/create-task/create-task.mjs +1 -1
- package/actions/create-user/create-user.mjs +1 -1
- package/actions/delete-opportunity/delete-opportunity.mjs +1 -1
- package/actions/delete-record/delete-record.mjs +1 -1
- package/actions/find-records/find-records.mjs +1 -1
- package/actions/get-case/get-case.mjs +36 -0
- package/actions/get-user/get-user.mjs +34 -0
- package/actions/insert-blob-data/insert-blob-data.mjs +1 -1
- package/actions/list-case-comments/list-case-comments.mjs +32 -0
- package/actions/list-email-messages/list-email-messages.mjs +38 -0
- package/actions/list-email-templates/list-email-templates.mjs +23 -0
- package/actions/list-knowledge-articles/list-knowledge-articles.mjs +23 -0
- package/actions/post-feed-to-chatter/post-feed-to-chatter.mjs +1 -1
- package/actions/search-string/search-string.mjs +1 -1
- package/actions/send-email/send-email.mjs +60 -0
- package/actions/soql-search/soql-search.mjs +1 -1
- package/actions/sosl-search/sosl-search.mjs +1 -1
- package/actions/update-account/update-account.mjs +1 -1
- package/actions/update-accounts-batch/update-accounts-batch.mjs +22 -0
- package/actions/update-contact/update-contact.mjs +1 -1
- package/actions/update-email-template/update-email-template.mjs +81 -0
- package/actions/update-opportunities-batch/update-opportunities-batch.mjs +22 -0
- package/actions/update-opportunity/update-opportunity.mjs +1 -1
- package/actions/update-record/update-record.mjs +1 -1
- package/actions/upsert-record/upsert-record.mjs +1 -1
- package/package.json +1 -1
- package/salesforce_rest_api.app.mjs +43 -0
- package/sources/case-updated-instant/case-updated-instant.mjs +43 -0
- package/sources/common/common-new-record.mjs +157 -0
- package/sources/common/common-updated-record.mjs +198 -0
- package/sources/{common.mjs → common/common.mjs} +2 -2
- package/sources/email-template-updated-instant/email-template-updated-instant.mjs +43 -0
- package/sources/knowledge-article-updated-instant/knowledge-article-updated-instant.mjs +43 -0
- package/sources/new-case-instant/new-case-instant.mjs +43 -0
- package/sources/new-email-template-instant/new-email-template-instant.mjs +43 -0
- package/sources/new-knowledge-article-instant/new-knowledge-article-instant.mjs +43 -0
- package/sources/new-outbound-message/new-outbound-message.mjs +1 -1
- package/sources/new-record-instant/new-record-instant.mjs +4 -118
- package/sources/record-deleted-instant/record-deleted-instant.mjs +2 -2
- package/sources/record-updated-instant/record-updated-instant.mjs +4 -138
- /package/sources/{common-webhook-methods.mjs → common/common-webhook-methods.mjs} +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import common from "../common/batch-operation.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
...common,
|
|
5
|
+
key: "salesforce_rest_api-update-accounts-batch",
|
|
6
|
+
name: "Update Accounts (Batch)",
|
|
7
|
+
description: "Update multiple Accounts in Salesforce using Bulk API 2.0. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/datafiles_understanding_bulk2_ingest.htm)",
|
|
8
|
+
version: "0.0.1",
|
|
9
|
+
type: "action",
|
|
10
|
+
methods: {
|
|
11
|
+
...common.methods,
|
|
12
|
+
getObject() {
|
|
13
|
+
return "Account";
|
|
14
|
+
},
|
|
15
|
+
getOperation() {
|
|
16
|
+
return "update";
|
|
17
|
+
},
|
|
18
|
+
getSummary() {
|
|
19
|
+
return "Successfully updated Accounts";
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
key: "salesforce_rest_api-update-contact",
|
|
17
17
|
name: "Update Contact",
|
|
18
18
|
description: `Updates a contact. [See the documentation](${docsLink})`,
|
|
19
|
-
version: "0.3.
|
|
19
|
+
version: "0.3.2",
|
|
20
20
|
type: "action",
|
|
21
21
|
methods: {
|
|
22
22
|
...common.methods,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
convertFieldsToProps, getAdditionalFields,
|
|
3
|
+
} from "../../common/props-utils.mjs";
|
|
4
|
+
import salesforce from "../../salesforce_rest_api.app.mjs";
|
|
5
|
+
import { additionalFields } from "../common/base-create-update.mjs";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
key: "salesforce_rest_api-update-email-template",
|
|
9
|
+
name: "Update Email Template",
|
|
10
|
+
description: "Updates an email template. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_update_fields.htm)",
|
|
11
|
+
version: "0.0.2",
|
|
12
|
+
type: "action",
|
|
13
|
+
props: {
|
|
14
|
+
salesforce,
|
|
15
|
+
recordId: {
|
|
16
|
+
propDefinition: [
|
|
17
|
+
salesforce,
|
|
18
|
+
"recordId",
|
|
19
|
+
() => ({
|
|
20
|
+
objType: "EmailTemplate",
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
description: "The email template to update.",
|
|
24
|
+
},
|
|
25
|
+
fieldsToUpdate: {
|
|
26
|
+
propDefinition: [
|
|
27
|
+
salesforce,
|
|
28
|
+
"fieldsToUpdate",
|
|
29
|
+
() => ({
|
|
30
|
+
objType: "EmailTemplate",
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
reloadProps: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
methods: {
|
|
37
|
+
getAdditionalFields,
|
|
38
|
+
convertFieldsToProps,
|
|
39
|
+
},
|
|
40
|
+
async additionalProps() {
|
|
41
|
+
const { fieldsToUpdate } = this;
|
|
42
|
+
const fields = await this.salesforce.getFieldsForObjectType("EmailTemplate");
|
|
43
|
+
|
|
44
|
+
const selectedFields = fields.filter(({ name }) => fieldsToUpdate.includes(name));
|
|
45
|
+
const selectedFieldProps = this.convertFieldsToProps(selectedFields);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
docsInfo: {
|
|
49
|
+
type: "alert",
|
|
50
|
+
alertType: "info",
|
|
51
|
+
content: "[See the documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_emailtemplate.htm) for information on all available fields.",
|
|
52
|
+
},
|
|
53
|
+
...selectedFieldProps,
|
|
54
|
+
additionalFields,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
async run({ $ }) {
|
|
58
|
+
/* eslint-disable no-unused-vars */
|
|
59
|
+
const {
|
|
60
|
+
salesforce,
|
|
61
|
+
recordId,
|
|
62
|
+
fieldsToUpdate,
|
|
63
|
+
getAdditionalFields: getData,
|
|
64
|
+
convertFieldsToProps,
|
|
65
|
+
docsInfo,
|
|
66
|
+
additionalFields,
|
|
67
|
+
...data
|
|
68
|
+
} = this;
|
|
69
|
+
/* eslint-enable no-unused-vars */
|
|
70
|
+
const response = await this.salesforce.updateRecord("EmailTemplate", {
|
|
71
|
+
$,
|
|
72
|
+
id: recordId,
|
|
73
|
+
data: {
|
|
74
|
+
...data,
|
|
75
|
+
...getData(),
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
$.export("$summary", `Successfully updated Email Template record (ID: ${recordId})`);
|
|
79
|
+
return response;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import common from "../common/batch-operation.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
...common,
|
|
5
|
+
key: "salesforce_rest_api-update-opportunities-batch",
|
|
6
|
+
name: "Update Opportunities (Batch)",
|
|
7
|
+
description: "Update multiple Opportunities in Salesforce using Bulk API 2.0. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/datafiles_understanding_bulk2_ingest.htm)",
|
|
8
|
+
version: "0.0.1",
|
|
9
|
+
type: "action",
|
|
10
|
+
methods: {
|
|
11
|
+
...common.methods,
|
|
12
|
+
getObject() {
|
|
13
|
+
return "Opportunity";
|
|
14
|
+
},
|
|
15
|
+
getOperation() {
|
|
16
|
+
return "update";
|
|
17
|
+
},
|
|
18
|
+
getSummary() {
|
|
19
|
+
return "Successfully updated Opportunities";
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
};
|
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
key: "salesforce_rest_api-update-opportunity",
|
|
17
17
|
name: "Update Opportunity",
|
|
18
18
|
description: `Updates an opportunity. [See the documentation](${docsLink})`,
|
|
19
|
-
version: "0.3.
|
|
19
|
+
version: "0.3.2",
|
|
20
20
|
type: "action",
|
|
21
21
|
methods: {
|
|
22
22
|
...common.methods,
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
key: "salesforce_rest_api-update-record",
|
|
9
9
|
name: "Update Record",
|
|
10
10
|
description: "Update fields of a record. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_update_fields.htm)",
|
|
11
|
-
version: "0.3.
|
|
11
|
+
version: "0.3.2",
|
|
12
12
|
type: "action",
|
|
13
13
|
props: {
|
|
14
14
|
salesforce,
|
|
@@ -8,7 +8,7 @@ export default {
|
|
|
8
8
|
key: "salesforce_rest_api-upsert-record",
|
|
9
9
|
name: "Upsert Record",
|
|
10
10
|
description: "Create or update a record of a given object. [See the documentation](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_upsert.htm)",
|
|
11
|
-
version: "0.0.
|
|
11
|
+
version: "0.0.3",
|
|
12
12
|
type: "action",
|
|
13
13
|
props: {
|
|
14
14
|
salesforce,
|
package/package.json
CHANGED
|
@@ -366,5 +366,48 @@ export default {
|
|
|
366
366
|
...args,
|
|
367
367
|
});
|
|
368
368
|
},
|
|
369
|
+
createBulkJob(args = {}) {
|
|
370
|
+
return this._makeRequest({
|
|
371
|
+
...args,
|
|
372
|
+
method: "POST",
|
|
373
|
+
url: `${this._baseApiVersionUrl()}/jobs/ingest`,
|
|
374
|
+
data: {
|
|
375
|
+
contentType: "CSV",
|
|
376
|
+
columnDelimiter: "COMMA",
|
|
377
|
+
lineEnding: "LF",
|
|
378
|
+
...args?.data,
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
},
|
|
382
|
+
uploadBulkJobData({
|
|
383
|
+
jobId, ...args
|
|
384
|
+
} = {}) {
|
|
385
|
+
return this._makeRequest({
|
|
386
|
+
...args,
|
|
387
|
+
method: "PUT",
|
|
388
|
+
url: `${this._baseApiVersionUrl()}/jobs/ingest/${jobId}/batches`,
|
|
389
|
+
headers: {
|
|
390
|
+
...this._makeRequestHeaders(),
|
|
391
|
+
"Content-Type": "text/csv",
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
},
|
|
395
|
+
patchBulkJob({
|
|
396
|
+
jobId, ...args
|
|
397
|
+
} = {}) {
|
|
398
|
+
return this._makeRequest({
|
|
399
|
+
...args,
|
|
400
|
+
method: "PATCH",
|
|
401
|
+
url: `${this._baseApiVersionUrl()}/jobs/ingest/${jobId}`,
|
|
402
|
+
});
|
|
403
|
+
},
|
|
404
|
+
getBulkJobInfo({
|
|
405
|
+
jobId, ...args
|
|
406
|
+
} = {}) {
|
|
407
|
+
return this._makeRequest({
|
|
408
|
+
...args,
|
|
409
|
+
url: `${this._baseApiVersionUrl()}/jobs/ingest/${jobId}`,
|
|
410
|
+
});
|
|
411
|
+
},
|
|
369
412
|
},
|
|
370
413
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import common from "../common/common-updated-record.mjs";
|
|
2
|
+
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
...common,
|
|
6
|
+
type: "source",
|
|
7
|
+
name: "Case Updated (Instant, of Selectable Type)",
|
|
8
|
+
key: "salesforce_rest_api-case-updated-instant",
|
|
9
|
+
description: "Emit new event when a case is updated. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
10
|
+
version: "0.0.2",
|
|
11
|
+
props: {
|
|
12
|
+
salesforce: common.props.salesforce,
|
|
13
|
+
db: "$.service.db",
|
|
14
|
+
http: {
|
|
15
|
+
type: "$.interface.http",
|
|
16
|
+
customResponse: true,
|
|
17
|
+
},
|
|
18
|
+
timer: {
|
|
19
|
+
type: "$.interface.timer",
|
|
20
|
+
description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
|
|
21
|
+
default: {
|
|
22
|
+
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
fieldsToObtain: {
|
|
26
|
+
propDefinition: [
|
|
27
|
+
common.props.salesforce,
|
|
28
|
+
"fieldsToObtain",
|
|
29
|
+
() => ({
|
|
30
|
+
objType: "Case",
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
optional: true,
|
|
34
|
+
description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
methods: {
|
|
38
|
+
...common.methods,
|
|
39
|
+
getObjectType() {
|
|
40
|
+
return "Case";
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import startCase from "lodash/startCase.js";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import common from "../common/common.mjs";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
...common,
|
|
7
|
+
hooks: {
|
|
8
|
+
...common.hooks,
|
|
9
|
+
async deploy() {
|
|
10
|
+
const objectType = this.getObjectType();
|
|
11
|
+
const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
|
|
12
|
+
this.setNameField(nameField);
|
|
13
|
+
|
|
14
|
+
// emit historical events
|
|
15
|
+
const { recentItems } = await this.salesforce.listSObjectTypeIds(objectType);
|
|
16
|
+
const ids = recentItems.map((item) => item.Id);
|
|
17
|
+
for (const id of ids.slice(-25)) {
|
|
18
|
+
const object = await this.salesforce.getSObject(objectType, id);
|
|
19
|
+
const event = {
|
|
20
|
+
body: {
|
|
21
|
+
"New": object,
|
|
22
|
+
"UserId": id,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
this.processWebhookEvent(event);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
async activate() {
|
|
29
|
+
// Attempt to create the webhook
|
|
30
|
+
const secretToken = uuidv4();
|
|
31
|
+
let webhookData;
|
|
32
|
+
const objectType = this.getObjectType();
|
|
33
|
+
try {
|
|
34
|
+
webhookData = await this.createWebhook({
|
|
35
|
+
endpointUrl: this.http.endpoint,
|
|
36
|
+
sObjectType: objectType,
|
|
37
|
+
event: this.getEventType(),
|
|
38
|
+
secretToken,
|
|
39
|
+
fieldsToCheck: this.getFieldsToCheck(),
|
|
40
|
+
fieldsToCheckMode: this.getFieldsToCheckMode(),
|
|
41
|
+
skipValidation: true, // neccessary for custom objects
|
|
42
|
+
});
|
|
43
|
+
console.log("Webhook created successfully");
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.log("Error creating webhook:", err);
|
|
46
|
+
console.log("The source will operate on the polling schedule instead.");
|
|
47
|
+
|
|
48
|
+
const latestDateCovered = this.getLatestDateCovered();
|
|
49
|
+
if (!latestDateCovered) {
|
|
50
|
+
const now = new Date().toISOString();
|
|
51
|
+
this.setLatestDateCovered(now);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await this.timerActivateHook?.();
|
|
55
|
+
}
|
|
56
|
+
this._setSecretToken(secretToken);
|
|
57
|
+
this._setWebhookData(webhookData);
|
|
58
|
+
|
|
59
|
+
const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
|
|
60
|
+
this.setNameField(nameField);
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
methods: {
|
|
64
|
+
...common.methods,
|
|
65
|
+
generateTimerMeta(item, fieldName) {
|
|
66
|
+
const { objectType } = this;
|
|
67
|
+
const {
|
|
68
|
+
CreatedDate: createdDate,
|
|
69
|
+
[fieldName]: name,
|
|
70
|
+
Id: id,
|
|
71
|
+
} = item;
|
|
72
|
+
const entityType = startCase(objectType);
|
|
73
|
+
const summary = `New ${entityType} created: ${name ?? id}`;
|
|
74
|
+
const ts = Date.parse(createdDate);
|
|
75
|
+
return {
|
|
76
|
+
id,
|
|
77
|
+
summary,
|
|
78
|
+
ts,
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
generateWebhookMeta(data) {
|
|
82
|
+
const nameField = this.getNameField();
|
|
83
|
+
const { New: newObject } = data.body;
|
|
84
|
+
const {
|
|
85
|
+
CreatedDate: createdDate,
|
|
86
|
+
Id: id,
|
|
87
|
+
[nameField]: name,
|
|
88
|
+
} = newObject;
|
|
89
|
+
const summary = `New ${this.getObjectType()} created: ${name ?? id}`;
|
|
90
|
+
const ts = Date.parse(createdDate);
|
|
91
|
+
return {
|
|
92
|
+
id,
|
|
93
|
+
summary,
|
|
94
|
+
ts,
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
getEventType() {
|
|
98
|
+
return "new";
|
|
99
|
+
},
|
|
100
|
+
async processTimerEvent(eventData) {
|
|
101
|
+
const {
|
|
102
|
+
paginate,
|
|
103
|
+
setLatestDateCovered,
|
|
104
|
+
getObjectTypeColumns,
|
|
105
|
+
getNameField,
|
|
106
|
+
generateTimerMeta,
|
|
107
|
+
$emit: emit,
|
|
108
|
+
} = this;
|
|
109
|
+
|
|
110
|
+
const {
|
|
111
|
+
startTimestamp,
|
|
112
|
+
endTimestamp,
|
|
113
|
+
} = eventData;
|
|
114
|
+
|
|
115
|
+
const fieldName = getNameField();
|
|
116
|
+
const columns = getObjectTypeColumns();
|
|
117
|
+
|
|
118
|
+
const events = await paginate({
|
|
119
|
+
objectType: this.getObjectType(),
|
|
120
|
+
startTimestamp,
|
|
121
|
+
endTimestamp,
|
|
122
|
+
columns,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const [
|
|
126
|
+
latestEvent,
|
|
127
|
+
] = events;
|
|
128
|
+
|
|
129
|
+
if (latestEvent?.CreatedDate) {
|
|
130
|
+
const latestDateCovered = new Date(latestEvent.CreatedDate);
|
|
131
|
+
latestDateCovered.setSeconds(0);
|
|
132
|
+
setLatestDateCovered(latestDateCovered.toISOString());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Array.from(events)
|
|
136
|
+
.reverse()
|
|
137
|
+
.forEach((item) => {
|
|
138
|
+
const meta = generateTimerMeta(item, fieldName);
|
|
139
|
+
emit(item, meta);
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
async timerActivateHook() {
|
|
143
|
+
const {
|
|
144
|
+
getObjectTypeDescription,
|
|
145
|
+
setObjectTypeColumns,
|
|
146
|
+
} = this;
|
|
147
|
+
|
|
148
|
+
let columns = this.fieldsToObtain;
|
|
149
|
+
if (!columns?.length) {
|
|
150
|
+
const { fields } = await getObjectTypeDescription(this.getObjectType());
|
|
151
|
+
columns = fields.map(({ name }) => name);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
setObjectTypeColumns(columns);
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import startCase from "lodash/startCase.js";
|
|
2
|
+
import common from "../common/common.mjs";
|
|
3
|
+
import constants from "../../common/constants.mjs";
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
...common,
|
|
8
|
+
hooks: {
|
|
9
|
+
...common.hooks,
|
|
10
|
+
async deploy() {
|
|
11
|
+
const objectType = this.getObjectType();
|
|
12
|
+
const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
|
|
13
|
+
this.setNameField(nameField);
|
|
14
|
+
|
|
15
|
+
// emit historical events
|
|
16
|
+
const { recentItems } = await this.salesforce.listSObjectTypeIds(objectType);
|
|
17
|
+
const ids = recentItems.map((item) => item.Id);
|
|
18
|
+
for (const id of ids.slice(-25)) {
|
|
19
|
+
const object = await this.salesforce.getSObject(objectType, id);
|
|
20
|
+
const event = {
|
|
21
|
+
body: {
|
|
22
|
+
"New": object,
|
|
23
|
+
"UserId": id,
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
const meta = this.generateWebhookMeta(event);
|
|
27
|
+
this.$emit(event.body, meta);
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
async activate() {
|
|
31
|
+
// Attempt to create the webhook
|
|
32
|
+
const secretToken = uuidv4();
|
|
33
|
+
let webhookData;
|
|
34
|
+
const objectType = this.getObjectType();
|
|
35
|
+
try {
|
|
36
|
+
webhookData = await this.createWebhook({
|
|
37
|
+
endpointUrl: this.http.endpoint,
|
|
38
|
+
sObjectType: objectType,
|
|
39
|
+
event: this.getEventType(),
|
|
40
|
+
secretToken,
|
|
41
|
+
fieldsToCheck: this.getFieldsToCheck(),
|
|
42
|
+
fieldsToCheckMode: this.getFieldsToCheckMode(),
|
|
43
|
+
skipValidation: true, // neccessary for custom objects
|
|
44
|
+
});
|
|
45
|
+
console.log("Webhook created successfully");
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.log("Error creating webhook:", err);
|
|
48
|
+
console.log("The source will operate on the polling schedule instead.");
|
|
49
|
+
|
|
50
|
+
const latestDateCovered = this.getLatestDateCovered();
|
|
51
|
+
if (!latestDateCovered) {
|
|
52
|
+
const now = new Date().toISOString();
|
|
53
|
+
this.setLatestDateCovered(now);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await this.timerActivateHook?.();
|
|
57
|
+
}
|
|
58
|
+
this._setSecretToken(secretToken);
|
|
59
|
+
this._setWebhookData(webhookData);
|
|
60
|
+
|
|
61
|
+
const nameField = await this.salesforce.getNameFieldForObjectType(objectType);
|
|
62
|
+
this.setNameField(nameField);
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
methods: {
|
|
66
|
+
...common.methods,
|
|
67
|
+
generateWebhookMeta(data) {
|
|
68
|
+
const nameField = this.getNameField();
|
|
69
|
+
const { New: newObject } = data.body;
|
|
70
|
+
const {
|
|
71
|
+
LastModifiedDate: lastModifiedDate,
|
|
72
|
+
Id: id,
|
|
73
|
+
[nameField]: name,
|
|
74
|
+
} = newObject;
|
|
75
|
+
const summary = `${this.getObjectType()} updated: ${name}`;
|
|
76
|
+
const ts = Date.parse(lastModifiedDate);
|
|
77
|
+
const compositeId = `${id}-${ts}`;
|
|
78
|
+
return {
|
|
79
|
+
id: compositeId,
|
|
80
|
+
summary,
|
|
81
|
+
ts,
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
generateTimerMeta(item, fieldName) {
|
|
85
|
+
const {
|
|
86
|
+
LastModifiedDate: lastModifiedDate,
|
|
87
|
+
[fieldName]: name,
|
|
88
|
+
Id: id,
|
|
89
|
+
} = item;
|
|
90
|
+
|
|
91
|
+
const entityType = startCase(this.getObjectType());
|
|
92
|
+
const summary = `${entityType} updated: ${name}`;
|
|
93
|
+
const ts = Date.parse(lastModifiedDate);
|
|
94
|
+
return {
|
|
95
|
+
id: `${id}-${ts}`,
|
|
96
|
+
summary,
|
|
97
|
+
ts,
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
getEventType() {
|
|
101
|
+
return "updated";
|
|
102
|
+
},
|
|
103
|
+
isEventRelevant(changedFields) {
|
|
104
|
+
const { fields } = this;
|
|
105
|
+
return fields?.length
|
|
106
|
+
? Object.keys(changedFields).some((key) => fields.includes(key))
|
|
107
|
+
: true;
|
|
108
|
+
},
|
|
109
|
+
getChangedFields(body) {
|
|
110
|
+
return Object.entries(body.New).filter(([
|
|
111
|
+
key,
|
|
112
|
+
value,
|
|
113
|
+
]) => {
|
|
114
|
+
const oldValue = body.Old[key];
|
|
115
|
+
return (
|
|
116
|
+
value !== undefined
|
|
117
|
+
&& oldValue !== undefined
|
|
118
|
+
&& JSON.stringify(value) !== JSON.stringify(oldValue)
|
|
119
|
+
);
|
|
120
|
+
})
|
|
121
|
+
.reduce((obj, [
|
|
122
|
+
key,
|
|
123
|
+
value,
|
|
124
|
+
]) => {
|
|
125
|
+
obj[key] = {
|
|
126
|
+
old: body.Old[key],
|
|
127
|
+
new: value,
|
|
128
|
+
};
|
|
129
|
+
return obj;
|
|
130
|
+
}, {});
|
|
131
|
+
},
|
|
132
|
+
processWebhookEvent(event) {
|
|
133
|
+
const { body } = event;
|
|
134
|
+
const changedFields = this.getChangedFields(body);
|
|
135
|
+
if (this.isEventRelevant(changedFields)) {
|
|
136
|
+
const meta = this.generateWebhookMeta(event);
|
|
137
|
+
this.$emit({
|
|
138
|
+
...body,
|
|
139
|
+
changedFields,
|
|
140
|
+
}, meta);
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
async processTimerEvent(eventData) {
|
|
144
|
+
const {
|
|
145
|
+
getNameField,
|
|
146
|
+
getObjectTypeColumns,
|
|
147
|
+
paginate,
|
|
148
|
+
setLatestDateCovered,
|
|
149
|
+
generateTimerMeta,
|
|
150
|
+
$emit: emit,
|
|
151
|
+
} = this;
|
|
152
|
+
|
|
153
|
+
const {
|
|
154
|
+
startTimestamp,
|
|
155
|
+
endTimestamp,
|
|
156
|
+
} = eventData;
|
|
157
|
+
|
|
158
|
+
const fieldName = getNameField();
|
|
159
|
+
const columns = getObjectTypeColumns();
|
|
160
|
+
|
|
161
|
+
const events = await paginate({
|
|
162
|
+
objectType: this.getObjectType(),
|
|
163
|
+
startTimestamp,
|
|
164
|
+
endTimestamp,
|
|
165
|
+
columns,
|
|
166
|
+
dateFieldName: constants.FIELD_NAME.LAST_MODIFIED_DATE,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const [
|
|
170
|
+
latestEvent,
|
|
171
|
+
] = events;
|
|
172
|
+
|
|
173
|
+
if (latestEvent?.LastModifiedDate) {
|
|
174
|
+
const latestDateCovered = new Date(latestEvent.LastModifiedDate);
|
|
175
|
+
latestDateCovered.setSeconds(0);
|
|
176
|
+
setLatestDateCovered(latestDateCovered.toISOString());
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
Array.from(events)
|
|
180
|
+
.reverse()
|
|
181
|
+
.forEach((item) => {
|
|
182
|
+
const meta = generateTimerMeta(item, fieldName);
|
|
183
|
+
emit(item, meta);
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
async timerActivateHook() {
|
|
187
|
+
const {
|
|
188
|
+
getObjectTypeDescription,
|
|
189
|
+
setObjectTypeColumns,
|
|
190
|
+
} = this;
|
|
191
|
+
|
|
192
|
+
const { fields } = await getObjectTypeDescription(this.getObjectType());
|
|
193
|
+
const columns = fields.map(({ name }) => name);
|
|
194
|
+
|
|
195
|
+
setObjectTypeColumns(columns);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
|
|
2
|
-
import salesforce from "
|
|
3
|
-
import constants from "
|
|
2
|
+
import salesforce from "../../salesforce_rest_api.app.mjs";
|
|
3
|
+
import constants from "../../common/constants.mjs";
|
|
4
4
|
import { v4 as uuidv4 } from "uuid";
|
|
5
5
|
import commonWebhookMethods from "./common-webhook-methods.mjs";
|
|
6
6
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import common from "../common/common-updated-record.mjs";
|
|
2
|
+
import { DEFAULT_POLLING_SOURCE_TIMER_INTERVAL } from "@pipedream/platform";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
...common,
|
|
6
|
+
type: "source",
|
|
7
|
+
name: "Email Template Updated (Instant, of Selectable Type)",
|
|
8
|
+
key: "salesforce_rest_api-email-template-updated-instant",
|
|
9
|
+
description: "Emit new event when an email template is updated. [See the documentation](https://sforce.co/3yPSJZy)",
|
|
10
|
+
version: "0.0.2",
|
|
11
|
+
props: {
|
|
12
|
+
salesforce: common.props.salesforce,
|
|
13
|
+
db: "$.service.db",
|
|
14
|
+
http: {
|
|
15
|
+
type: "$.interface.http",
|
|
16
|
+
customResponse: true,
|
|
17
|
+
},
|
|
18
|
+
timer: {
|
|
19
|
+
type: "$.interface.timer",
|
|
20
|
+
description: "The timer is only used as a fallback if instant event delivery (webhook) is not available.",
|
|
21
|
+
default: {
|
|
22
|
+
intervalSeconds: DEFAULT_POLLING_SOURCE_TIMER_INTERVAL,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
fieldsToObtain: {
|
|
26
|
+
propDefinition: [
|
|
27
|
+
common.props.salesforce,
|
|
28
|
+
"fieldsToObtain",
|
|
29
|
+
() => ({
|
|
30
|
+
objType: "EmailTemplate",
|
|
31
|
+
}),
|
|
32
|
+
],
|
|
33
|
+
optional: true,
|
|
34
|
+
description: "Select the field(s) to be retrieved for the records. Only applicable if the source is running on a timer. If running on a webhook, or if not specified, all fields will be retrieved.",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
methods: {
|
|
38
|
+
...common.methods,
|
|
39
|
+
getObjectType() {
|
|
40
|
+
return "EmailTemplate";
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|