Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/appmixer/hubspot/bundle.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "appmixer.hubspot",
"version": "4.5.0",
"version": "4.6.0",
"engine": ">=6.0.0",
"changelog": {
"1.0.0": [
Expand Down Expand Up @@ -88,6 +88,11 @@
"Added Pipeline and Stage filter inputs to ListDeals action using CRM Search API filterGroups.",
"Replaced hard-coded deal stages in UpdateDeal action with dynamic ListPipelineStages cascade."
],
"4.6.0": [
"Added new component `CreateTask` for creating tasks (engagements of type TASK) associated with HubSpot objects.",
"Added new component `EnrollContactInWorkflow` for enrolling a contact in a HubSpot workflow by email.",
"Added new helper component `ListWorkflows` for listing available HubSpot workflows."
],
"4.5.0": [
"Fixed UpdatedContact and UpdatedDeal triggers not firing for property changes outside the default watched list (e.g. lifecyclestage and custom properties). All propertyChange events now pass through to listeners; deduplication against creation events is handled internally.",
"Fixed triggerListenersDelayed dropping the entire payload when any single object in a batch matched a creation event — now filters per-objectId."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';
const Hubspot = require('../../Hubspot');

module.exports = {
async receive(context) {

const {
workflowId,
email
} = context.messages.in.content;

const { auth } = context;
const hs = new Hubspot(auth.accessToken, context.config);

context.log({ stage: 'CRM - EnrollContactInWorkflow', workflowId, email });

// https://developers.hubspot.com/docs/reference/api/automation/workflows/v2
await hs.call(
'post',
`automation/v2/workflows/${encodeURIComponent(workflowId)}/enrollments/contacts/${encodeURIComponent(email)}`,
{}
);

return context.sendJson({ workflowId, email }, 'out');
}
};
71 changes: 71 additions & 0 deletions src/appmixer/hubspot/crm/EnrollContactInWorkflow/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"name": "appmixer.hubspot.crm.EnrollContactInWorkflow",
"author": "Appmixer <info@appmixer.com>",
"description": "Enroll a contact in a HubSpot workflow by their email address.",
"version": "1.0.0",
"private": false,
"auth": {
"service": "appmixer:hubspot"
},
"quota": {
"manager": "appmixer:hubspot",
"resources": "requests"
},
"inPorts": [
{
"name": "in",
"schema": {
"type": "object",
"properties": {
"workflowId": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": [ "workflowId", "email" ]
},
"inspector": {
"inputs": {
"workflowId": {
"type": "select",
"tooltip": "The HubSpot workflow to enroll the contact in.",
"label": "Workflow",
"source": {
"url": "/component/appmixer/hubspot/crm/ListWorkflows?outPort=out",
"data": {
"transform": "./transformers#workflowsToSelectArray"
}
},
"index": 0
},
"email": {
"type": "text",
"tooltip": "Email address of the contact to enroll.",
"label": "Contact Email",
"index": 1
}
}
}
}
],
"outPorts": [
{
"name": "out",
"options": [
{
"label": "Workflow Id",
"value": "workflowId",
"schema": {
"type": "string"
}
},
{
"label": "Email",
"value": "email",
"schema": {
"type": "string"
}
}
]
}
],
"icon": "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9IjYuMjA4NTYyODMgLjY0NDk4ODI0IDI0NC4yNjk0MzcxNyAyNTEuMjQ3MDExNzYiIHdpZHRoPSIyNTAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0xOTEuMzg1IDg1LjY5NHYtMjkuNTA2YTIyLjcyMiAyMi43MjIgMCAwIDAgMTMuMTAxLTIwLjQ4di0uNjc3YzAtMTIuNTQ5LTEwLjE3My0yMi43MjItMjIuNzIxLTIyLjcyMmgtLjY3OGMtMTIuNTQ5IDAtMjIuNzIyIDEwLjE3My0yMi43MjIgMjIuNzIydi42NzdhMjIuNzIyIDIyLjcyMiAwIDAgMCAxMy4xMDEgMjAuNDh2MjkuNTA2YTY0LjM0MiA2NC4zNDIgMCAwIDAgLTMwLjU5NCAxMy40N2wtODAuOTIyLTYzLjAzYy41NzctMi4wODMuODc4LTQuMjI1LjkxMi02LjM3NWEyNS42IDI1LjYgMCAxIDAgLTI1LjYzMyAyNS41NSAyNS4zMjMgMjUuMzIzIDAgMCAwIDEyLjYwNy0zLjQzbDc5LjY4NSA2Mi4wMDdjLTE0LjY1IDIyLjEzMS0xNC4yNTggNTAuOTc0Ljk4NyA3Mi43bC0yNC4yMzYgMjQuMjQzYy0xLjk2LS42MjYtNC0uOTU5LTYuMDU3LS45ODctMTEuNjA3LjAxLTIxLjAxIDkuNDIzLTIxLjAwNyAyMS4wMy4wMDMgMTEuNjA2IDkuNDEyIDIxLjAxNCAyMS4wMTggMjEuMDE3IDExLjYwNy4wMDMgMjEuMDItOS40IDIxLjAzLTIxLjAwN2EyMC43NDcgMjAuNzQ3IDAgMCAwIC0uOTg4LTYuMDU2bDIzLjk3Ni0yMy45ODVjMjEuNDIzIDE2LjQ5MiA1MC44NDYgMTcuOTEzIDczLjc1OSAzLjU2MiAyMi45MTItMTQuMzUyIDM0LjQ3NS00MS40NDYgMjguOTg1LTY3LjkxOC01LjQ5LTI2LjQ3My0yNi44NzMtNDYuNzM0LTUzLjYwMy01MC43OTJtLTkuOTM4IDk3LjA0NGEzMy4xNyAzMy4xNyAwIDEgMSAwLTY2LjMxNmMxNy44NS42MjUgMzIgMTUuMjcyIDMyLjAxIDMzLjEzNC4wMDggMTcuODYtMTQuMTI3IDMyLjUyMi0zMS45NzcgMzMuMTY1IiBmaWxsPSIjZmY3YTU5Ii8+PC9zdmc+"
}
15 changes: 15 additions & 0 deletions src/appmixer/hubspot/crm/EnrollContactInWorkflow/transformers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

module.exports = {

workflowsToSelectArray({ workflows }) {

if (!Array.isArray(workflows)) {
return [];
}
return workflows.map(wf => ({
label: wf.name || String(wf.id),
value: String(wf.id)
}));
}
};
16 changes: 16 additions & 0 deletions src/appmixer/hubspot/crm/ListWorkflows/ListWorkflows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';
const Hubspot = require('../../Hubspot');

module.exports = {
async receive(context) {

const { auth } = context;
const hs = new Hubspot(auth.accessToken, context.config);

// https://developers.hubspot.com/docs/reference/api/automation/workflows/v3
const { data } = await hs.call('get', 'automation/v3/workflows', {});
const workflows = (data && data.workflows) ? data.workflows : [];

return context.sendJson({ workflows }, 'out');
}
};
35 changes: 35 additions & 0 deletions src/appmixer/hubspot/crm/ListWorkflows/component.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "appmixer.hubspot.crm.ListWorkflows",
"author": "Appmixer <info@appmixer.com>",
"description": "List all HubSpot workflows available in the account.",
"version": "1.0.0",
"private": true,
"auth": {
"service": "appmixer:hubspot"
},
"quota": {
"manager": "appmixer:hubspot",
"resources": "requests"
},
"inPorts": [
{
"name": "in",
"schema": {
"type": "object",
"properties": {}
}
}
],
"outPorts": [
{
"name": "out",
"options": [
{
"label": "Workflows",
"value": "workflows"
}
]
}
],
"icon": "data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1MDAiIHZpZXdCb3g9IjYuMjA4NTYyODMgLjY0NDk4ODI0IDI0NC4yNjk0MzcxNyAyNTEuMjQ3MDExNzYiIHdpZHRoPSIyNTAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Im0xOTEuMzg1IDg1LjY5NHYtMjkuNTA2YTIyLjcyMiAyMi43MjIgMCAwIDAgMTMuMTAxLTIwLjQ4di0uNjc3YzAtMTIuNTQ5LTEwLjE3My0yMi43MjItMjIuNzIxLTIyLjcyMmgtLjY3OGMtMTIuNTQ5IDAtMjIuNzIyIDEwLjE3My0yMi43MjIgMjIuNzIydi42NzdhMjIuNzIyIDIyLjcyMiAwIDAgMCAxMy4xMDEgMjAuNDh2MjkuNTA2YTY0LjM0MiA2NC4zNDIgMCAwIDAgLTMwLjU5NCAxMy40N2wtODAuOTIyLTYzLjAzYy41NzctMi4wODMuODc4LTQuMjI1LjkxMi02LjM3NWEyNS42IDI1LjYgMCAxIDAgLTI1LjYzMyAyNS41NSAyNS4zMjMgMjUuMzIzIDAgMCAwIDEyLjYwNy0zLjQzbDc5LjY4NSA2Mi4wMDdjLTE0LjY1IDIyLjEzMS0xNC4yNTggNTAuOTc0Ljk4NyA3Mi43bC0yNC4yMzYgMjQuMjQzYy0xLjk2LS42MjYtNC0uOTU5LTYuMDU3LS45ODctMTEuNjA3LjAxLTIxLjAxIDkuNDIzLTIxLjAwNyAyMS4wMy4wMDMgMTEuNjA2IDkuNDEyIDIxLjAxNCAyMS4wMTggMjEuMDE3IDExLjYwNy4wMDMgMjEuMDItOS40IDIxLjAzLTIxLjAwN2EyMC43NDcgMjAuNzQ3IDAgMCAwIC0uOTg4LTYuMDU2bDIzLjk3Ni0yMy45ODVjMjEuNDIzIDE2LjQ5MiA1MC44NDYgMTcuOTEzIDczLjc1OSAzLjU2MiAyMi45MTItMTQuMzUyIDM0LjQ3NS00MS40NDYgMjguOTg1LTY3LjkxOC01LjQ5LTI2LjQ3My0yNi44NzMtNDYuNzM0LTUzLjYwMy01MC43OTJtLTkuOTM4IDk3LjA0NGEzMy4xNyAzMy4xNyAwIDEgMSAwLTY2LjMxNmMxNy44NS42MjUgMzIgMTUuMjcyIDMyLjAxIDMzLjEzNC4wMDggMTcuODYtMTQuMTI3IDMyLjUyMi0zMS45NzcgMzMuMTY1IiBmaWxsPSIjZmY3YTU5Ii8+PC9zdmc+"
}
52 changes: 52 additions & 0 deletions src/appmixer/hubspot/engagements/CreateTask/CreateTask.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';
const Hubspot = require('../../Hubspot');

module.exports = {
async receive(context) {

const {
associationTypeId,
objectId,
hsTaskSubject,
hsTaskBody,
hsTaskStatus = 'NOT_STARTED',
hsTaskType = 'TODO',
hsTimestamp
} = context.messages.in.content;

const { auth } = context;
const hs = new Hubspot(auth.accessToken, context.config);

const payload = {
properties: {
hs_timestamp: hsTimestamp || new Date().toISOString(),
hs_task_subject: hsTaskSubject,
hs_task_body: hsTaskBody || '',
hs_task_status: hsTaskStatus,
hs_task_type: hsTaskType
},
associations: [
{
to: { id: objectId },
types: [
{
associationCategory: 'HUBSPOT_DEFINED',
// https://developers.hubspot.com/docs/api/crm/associations#association-type-id-values
associationTypeId
}
]
}
]
};

context.log({ stage: 'Engagements - CreateTask payload', payload });

const { data } = await hs.call(
'post',
'crm/v3/objects/tasks',
payload
);

return context.sendJson(data, 'out');
}
};
Loading