From e615d62f9e9d4865366c2164e1e7940e35b34c26 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 18 Dec 2024 16:57:42 +0530 Subject: [PATCH 01/60] feat(hubspot): add get contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/create-deal.ts | 2 +- .../hubspot/src/lib/actions/get-contact.ts | 39 ++ .../hubspot/src/lib/actions/update-deal.ts | 2 +- .../hubspot/src/lib/common/client.ts | 2 +- .../hubspot/src/lib/common/constants.ts | 34 ++ .../community/hubspot/src/lib/common/index.ts | 450 ++++++++++-------- .../community/hubspot/src/lib/common/props.ts | 152 ++++-- .../src/lib/common/{models.ts => types.ts} | 24 + .../src/lib/triggers/deal-stage-updated.ts | 2 +- 10 files changed, 448 insertions(+), 261 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-contact.ts create mode 100644 packages/pieces/community/hubspot/src/lib/common/constants.ts rename packages/pieces/community/hubspot/src/lib/common/{models.ts => types.ts} (84%) diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index d19b17cae3..4cad3e5ed7 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -13,6 +13,7 @@ import { newTicketAdded } from './lib/triggers/new-ticket-added'; import { createDealAction } from './lib/actions/create-deal'; import { updateDealAction } from './lib/actions/update-deal'; import { dealStageUpdatedTrigger } from './lib/triggers/deal-stage-updated'; +import { getContactAction } from './lib/actions/get-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -50,6 +51,7 @@ export const hubspot = createPiece({ hubSpotContactsCreateOrUpdateAction, hubSpotListsAddContactAction, hubSpotGetOwnerByEmailAction, + getContactAction, createDealAction, updateDealAction, createCustomApiCallAction({ diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts index edafb3661f..6b9ae38125 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts @@ -20,7 +20,7 @@ import { ListPipelineStagesResponse, ListPropertiesResponse, PropertyResponse, -} from '../common/models'; +} from '../common/types'; export const createDealAction = createAction({ auth: hubspotAuth, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts new file mode 100644 index 0000000000..b249709520 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -0,0 +1,39 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; + +export const getContactAction = createAction({ + auth: hubspotAuth, + name: 'get-contact', + displayName: 'Get Contact', + description: 'Gets a contact.', + props: { + contactId : Property.ShortText({ + displayName: 'Contact ID', + description: 'The ID of the contact to get.', + required: true, + }), + additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.CONTACT) + + }, + async run(context) { + const contactId = context.propsValue.contactId; + const additionalProperties = context.propsValue.additionalProperties ?? []; + + const defaultProperties = getDefaultProperties(OBJECT_TYPE.CONTACT) + + // https://developers.hubspot.com/docs/reference/api/crm/objects/contacts#get-%2Fcrm%2Fv3%2Fobjects%2Fcontacts%2F%7Bcontactid%7D + const contactResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri:`/crm/v3/objects/contacts/${contactId}`, + query:{ + properties: [...defaultProperties, ...additionalProperties].join(',') + } + }) + + return contactResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts index c266f79745..6bce8b92ec 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts @@ -21,7 +21,7 @@ import { ListPropertiesResponse, PropertyResponse, SearchDealsResponse, -} from '../common/models'; +} from '../common/types'; export const updateDealAction = createAction({ auth: hubspotAuth, diff --git a/packages/pieces/community/hubspot/src/lib/common/client.ts b/packages/pieces/community/hubspot/src/lib/common/client.ts index 8e0d4569a4..a9bdd435b6 100644 --- a/packages/pieces/community/hubspot/src/lib/common/client.ts +++ b/packages/pieces/community/hubspot/src/lib/common/client.ts @@ -11,7 +11,7 @@ import { HubSpotContactsCreateOrUpdateResponse, HubSpotListsResponse, HubSpotRequest, -} from './models'; +} from './types'; const API = 'https://api.hubapi.com'; diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts new file mode 100644 index 0000000000..ffd09dc1ec --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -0,0 +1,34 @@ +const OBJECT_TYPE = { + CONTACT: 'contact', + COMPANY: 'company', + DEAL: 'deal', +}; + +const DEFAULT_CONTACT_PROPERTIES = [ + 'firstname', + 'lastname', + 'email', + 'company', + 'website', + 'mobilephone', + 'phone', + 'fax', + 'address', + 'city', + 'state', + 'zip', + 'salutation', + 'country', + 'jobtitle', + 'hs_createdate', + 'hs_email_domain', + 'hs_object_id', + 'lastmodifieddate', + 'hs_persona', + 'hs_language', + 'lifecyclestage', + 'createdate', + 'numemployees', + 'annualrevenue', + 'industry', +]; diff --git a/packages/pieces/community/hubspot/src/lib/common/index.ts b/packages/pieces/community/hubspot/src/lib/common/index.ts index 4f99b071c2..5fe2deeb4b 100644 --- a/packages/pieces/community/hubspot/src/lib/common/index.ts +++ b/packages/pieces/community/hubspot/src/lib/common/index.ts @@ -1,227 +1,265 @@ import { - AuthenticationType, - HttpMethod, - HttpRequest, - httpClient, + AuthenticationType, + HttpMessageBody, + HttpMethod, + HttpRequest, + QueryParams, + httpClient, } from '@activepieces/pieces-common'; import { - CheckboxProperty, - DateTimeProperty, - FileProperty, - LongTextProperty, - NumberProperty, - OAuth2PropertyValue, - Property, - ShortTextProperty, + CheckboxProperty, + DateTimeProperty, + FileProperty, + LongTextProperty, + NumberProperty, + OAuth2PropertyValue, + Property, + ShortTextProperty, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; enum HubspotFieldType { - BooleanCheckBox = 'booleancheckbox', - Date = 'date', - File = 'file', - Number = 'number', - CalculationEquation = 'calculation_equation', - PhoneNumber = 'phonenumber', - Text = 'text', - TextArea = 'textarea', - Html = 'html', - CheckBox = 'checkbox', - Select = 'select', - Radio = 'radio', + BooleanCheckBox = 'booleancheckbox', + Date = 'date', + File = 'file', + Number = 'number', + CalculationEquation = 'calculation_equation', + PhoneNumber = 'phonenumber', + Text = 'text', + TextArea = 'textarea', + Html = 'html', + CheckBox = 'checkbox', + Select = 'select', + Radio = 'radio', } -interface ContactProperty { - name: string; - label: string; - description: string; - type: string; - fieldType: HubspotFieldType; - options: []; +interface HubspotProperty { + name: string; + label: string; + description: string; + type: string; + fieldType: HubspotFieldType; + options: []; } type DynamicPropsValue = - | ShortTextProperty - | LongTextProperty - | CheckboxProperty - | DateTimeProperty - | FileProperty - | NumberProperty; + | ShortTextProperty + | LongTextProperty + | CheckboxProperty + | DateTimeProperty + | FileProperty + | NumberProperty; export const hubspotCommon = { - choose_props: Property.MultiSelectDropdown({ - displayName: 'Properties', - description: 'Choose extra properties to add to the contact', - required: false, - refreshers: ['auth'], - options: async ({ auth }) => { - const connection = auth as OAuth2PropertyValue; - if (!connection) { - return { - disabled: true, - options: [], - placeholder: - 'please authenticate your account first before selecting properties', - }; - } - try { - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/properties/v1/contacts/properties', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: connection.access_token, - }, - }; - const result = await httpClient.sendRequest(request); + choose_props: Property.MultiSelectDropdown({ + displayName: 'Properties', + description: 'Choose extra properties to add to the contact', + required: false, + refreshers: ['auth'], + options: async ({ auth }) => { + const connection = auth as OAuth2PropertyValue; + if (!connection) { + return { + disabled: true, + options: [], + placeholder: 'please authenticate your account first before selecting properties', + }; + } + try { + const request: HttpRequest = { + method: HttpMethod.GET, + url: 'https://api.hubapi.com/properties/v1/contacts/properties', + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: connection.access_token, + }, + }; + const result = await httpClient.sendRequest(request); - const properties = result.body.map((property: any) => { - return { - label: property.label, - value: property, - }; - }); + const properties = result.body.map((property: any) => { + return { + label: property.label, + value: property, + }; + }); - return { - disabled: false, - options: properties, - }; - } catch (error) { - return { - disabled: true, - options: [], - placeholder: 'An error occurred while fetching properties', - }; - } - }, - }), - dynamicProperties: Property.DynamicProperties({ - displayName: 'Dynamic Properties', - description: 'Extra properties to add to the contact', - required: false, - refreshers: ['choose_props'], - props: async ({ auth, choose_props }) => { - const all_props = choose_props as ContactProperty[]; + return { + disabled: false, + options: properties, + }; + } catch (error) { + return { + disabled: true, + options: [], + placeholder: 'An error occurred while fetching properties', + }; + } + }, + }), + dynamicProperties: Property.DynamicProperties({ + displayName: 'Dynamic Properties', + description: 'Extra properties to add to the contact', + required: false, + refreshers: ['choose_props'], + props: async ({ auth, choose_props }) => { + const all_props = choose_props as HubspotProperty[]; - if (!all_props) { - return {}; - } + if (!all_props) { + return {}; + } - const fields: any = {}; + const fields: any = {}; - for (const prop of all_props) { - switch (prop.fieldType) { - case HubspotFieldType.BooleanCheckBox: - fields[prop.name] = Property.Checkbox({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.Date: - fields[prop.name] = Property.DateTime({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.File: - fields[prop.name] = Property.File({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.Number: - fields[prop.name] = Property.Number({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.CalculationEquation: - case HubspotFieldType.PhoneNumber: - case HubspotFieldType.Text: - fields[prop.name] = Property.ShortText({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.TextArea: - case HubspotFieldType.Html: - fields[prop.name] = Property.LongText({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.CheckBox: - fields[prop.name] = Property.StaticMultiSelectDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: prop.options.map((option: any) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case HubspotFieldType.Select: - case HubspotFieldType.Radio: - if (prop.name === 'hubspot_owner_id') { - try { - const res = - ( - await hubSpotClient.listContactOwners( - auth.access_token as string - ) - ).results ?? []; - fields[prop.name] = Property.StaticDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: res.map((owner: { id: string; email: string }) => { - return { - label: owner.email, - value: owner.id, - }; - }), - }, - }); - } catch (error) { - return { - disabled: true, - options: [], - placeholder: - 'An error occurred while fetching contact owner list.', - }; - } - } else { - fields[prop.name] = Property.StaticDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: prop.options.map((option: any) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - } - break; - } - } + for (const prop of all_props) { + switch (prop.fieldType) { + case HubspotFieldType.BooleanCheckBox: + fields[prop.name] = Property.Checkbox({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.Date: + fields[prop.name] = Property.DateTime({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.File: + fields[prop.name] = Property.File({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.Number: + fields[prop.name] = Property.Number({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.CalculationEquation: + case HubspotFieldType.PhoneNumber: + case HubspotFieldType.Text: + fields[prop.name] = Property.ShortText({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.TextArea: + case HubspotFieldType.Html: + fields[prop.name] = Property.LongText({ + displayName: prop.label, + description: prop.description, + required: false, + }); + break; + case HubspotFieldType.CheckBox: + fields[prop.name] = Property.StaticMultiSelectDropdown({ + displayName: prop.label, + description: prop.description, + required: false, + options: { + options: prop.options.map((option: any) => { + return { + label: option.label, + value: option.value, + }; + }), + }, + }); + break; + case HubspotFieldType.Select: + case HubspotFieldType.Radio: + if (prop.name === 'hubspot_owner_id') { + try { + const res = + (await hubSpotClient.listContactOwners(auth.access_token as string)).results ?? + []; + fields[prop.name] = Property.StaticDropdown({ + displayName: prop.label, + description: prop.description, + required: false, + options: { + options: res.map((owner: { id: string; email: string }) => { + return { + label: owner.email, + value: owner.id, + }; + }), + }, + }); + } catch (error) { + return { + disabled: true, + options: [], + placeholder: 'An error occurred while fetching contact owner list.', + }; + } + } else { + fields[prop.name] = Property.StaticDropdown({ + displayName: prop.label, + description: prop.description, + required: false, + options: { + options: prop.options.map((option: any) => { + return { + label: option.label, + value: option.value, + }; + }), + }, + }); + } + break; + } + } - return fields; - }, - }), + return fields; + }, + }), }; + +export type RequestParams = Record; + +export type HubspotApiCallParams = { + accessToken: string; + method: HttpMethod; + resourceUri: string; + query?: RequestParams; + body?: any; +}; + +export async function hubspotApiCall({ + accessToken, + method, + resourceUri, + query, + body, +}: HubspotApiCallParams): Promise { + const baseUrl = 'https://api.hubapi.com'; + const qs: QueryParams = {}; + + if (query) { + for (const [key, value] of Object.entries(query)) { + if (value !== null && value !== undefined) { + qs[key] = String(value); + } + } + } + const request: HttpRequest = { + method, + url: baseUrl + resourceUri, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: accessToken, + }, + queryParams: qs, + body, + }; + const response = await httpClient.sendRequest(request); + return response.body; +} diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index f8cf2018da..ddb5aaf85a 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -1,63 +1,113 @@ import { - OAuth2PropertyValue, - PieceAuth, - Property, + DropdownOption, + OAuth2PropertyValue, + PieceAuth, + Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; +import { hubspotApiCall } from '.'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { HubspotProperty } from './types'; export const hubSpotAuthentication = PieceAuth.OAuth2({ - authUrl: 'https://app.hubspot.com/oauth/authorize', - tokenUrl: 'https://api.hubapi.com/oauth/v1/token', - required: true, - scope: [ - 'crm.lists.read', - 'crm.lists.write', - 'crm.objects.contacts.read', - 'crm.objects.contacts.write', - 'crm.objects.companies.read', - 'crm.objects.deals.read', - 'tickets', - 'forms', - ], + authUrl: 'https://app.hubspot.com/oauth/authorize', + tokenUrl: 'https://api.hubapi.com/oauth/v1/token', + required: true, + scope: [ + 'crm.lists.read', + 'crm.lists.write', + 'crm.objects.contacts.read', + 'crm.objects.contacts.write', + 'crm.objects.companies.read', + 'crm.objects.deals.read', + 'tickets', + 'forms', + ], }); const buildEmptyList = ({ placeholder }: { placeholder: string }) => { - return { - disabled: true, - options: [], - placeholder, - }; + return { + disabled: true, + options: [], + placeholder, + }; }; export const hubSpotListIdDropdown = Property.Dropdown({ - displayName: 'List', - refreshers: [], - description: 'List to add contact to', - required: true, - options: async ({ auth }) => { - if (!auth) { - return buildEmptyList({ - placeholder: 'Please select an authentication', - }); - } - - const token = (auth as OAuth2PropertyValue).access_token; - const listsResponse = await hubSpotClient.lists.getStaticLists({ token }); - - if (listsResponse.lists.length === 0) { - return buildEmptyList({ - placeholder: 'No lists found! Please create a list.', - }); - } - - const options = listsResponse.lists.map((list) => ({ - label: list.name, - value: list.listId, - })); - - return { - disabled: false, - options, - }; - }, + displayName: 'List', + refreshers: [], + description: 'List to add contact to', + required: true, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please select an authentication', + }); + } + + const token = (auth as OAuth2PropertyValue).access_token; + const listsResponse = await hubSpotClient.lists.getStaticLists({ token }); + + if (listsResponse.lists.length === 0) { + return buildEmptyList({ + placeholder: 'No lists found! Please create a list.', + }); + } + + const options = listsResponse.lists.map((list) => ({ + label: list.name, + value: list.listId, + })); + + return { + disabled: false, + options, + }; + }, }); + +export function getDefaultProperties(objectType:string) { + if (objectType === "contact") { + return DEFAULT_CONTACT_PROPERTIES; + } else { + return []; + } +} + +export const additionalPropertyNamesDropdown = (objectType: string) => + Property.MultiSelectDropdown({ + displayName: 'Additional Properties', + refreshers: [], + required: false, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + const token = (auth as OAuth2PropertyValue).access_token; + const propertiesResponse = await hubspotApiCall<{ results: HubspotProperty[] }>({ + accessToken: token, + method: HttpMethod.GET, + resourceUri: `/crm/v3/properties/${objectType}`, + }); + + const defaultProperties = getDefaultProperties(objectType); + + const options: DropdownOption[] = []; + for (const property of propertiesResponse.results) { + if(defaultProperties.includes(property.name)) { + continue; + } + options.push({ + label: property.label, + value: property.name, + }); + } + + return { + disabled: false, + options, + }; + }, + }); diff --git a/packages/pieces/community/hubspot/src/lib/common/models.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts similarity index 84% rename from packages/pieces/community/hubspot/src/lib/common/models.ts rename to packages/pieces/community/hubspot/src/lib/common/types.ts index 31be55be4e..faf9ea600f 100644 --- a/packages/pieces/community/hubspot/src/lib/common/models.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -131,3 +131,27 @@ export type SearchDealsResponse = { }; }; }; + +enum HubspotFieldType { + BooleanCheckBox = 'booleancheckbox', + Date = 'date', + File = 'file', + Number = 'number', + CalculationEquation = 'calculation_equation', + PhoneNumber = 'phonenumber', + Text = 'text', + TextArea = 'textarea', + Html = 'html', + CheckBox = 'checkbox', + Select = 'select', + Radio = 'radio', +} + +export type HubspotProperty= { + name: string; + label: string; + description: string; + type: string; + fieldType: HubspotFieldType; + options: []; +} \ No newline at end of file diff --git a/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts b/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts index 5366489daf..e59394dbd3 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts @@ -23,7 +23,7 @@ import { ListDealPipelinesResponse, ListPipelineStagesResponse, SearchDealsResponse, -} from '../common/models'; +} from '../common/types'; const polling: Polling< PiecePropValueSchema, From 28351b661371a87b6f71370b919c838be9ab2677 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 19 Dec 2024 12:20:00 +0530 Subject: [PATCH 02/60] feat(hubspot): add get deal action --- .../pieces/community/hubspot/src/index.ts | 4 + .../hubspot/src/lib/actions/get-contact.ts | 1 + .../hubspot/src/lib/actions/get-deal.ts | 40 ++++++++ .../hubspot/src/lib/actions/get-ticket.ts | 40 ++++++++ .../hubspot/src/lib/common/constants.ts | 99 +++++++++++++------ .../community/hubspot/src/lib/common/props.ts | 11 ++- 6 files changed, 161 insertions(+), 34 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-deal.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 4cad3e5ed7..a8813b690f 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -14,6 +14,8 @@ import { createDealAction } from './lib/actions/create-deal'; import { updateDealAction } from './lib/actions/update-deal'; import { dealStageUpdatedTrigger } from './lib/triggers/deal-stage-updated'; import { getContactAction } from './lib/actions/get-contact'; +import { getDealAction } from './lib/actions/get-deal'; +import { getTicketAction } from './lib/actions/get-ticket'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -52,6 +54,8 @@ export const hubspot = createPiece({ hubSpotListsAddContactAction, hubSpotGetOwnerByEmailAction, getContactAction, + getDealAction, + getTicketAction, createDealAction, updateDealAction, createCustomApiCallAction({ diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts index b249709520..1332dc2650 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -3,6 +3,7 @@ import { createAction, Property } from '@activepieces/pieces-framework'; import { hubspotApiCall } from '../common'; import { HttpMethod } from '@activepieces/pieces-common'; import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const getContactAction = createAction({ auth: hubspotAuth, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts new file mode 100644 index 0000000000..8bafa8cece --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts @@ -0,0 +1,40 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; + +export const getDealAction = createAction({ + auth: hubspotAuth, + name: 'get-deal', + displayName: 'Get Deal', + description: 'Gets a deal.', + props: { + dealId : Property.ShortText({ + displayName: 'Deal ID', + description: 'The ID of the deal to get.', + required: true, + }), + additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.DEAL) + + }, + async run(context) { + const dealId = context.propsValue.dealId; + const additionalProperties = context.propsValue.additionalProperties ?? []; + + const defaultProperties = getDefaultProperties(OBJECT_TYPE.DEAL) + + // https://developers.hubspot.com/docs/reference/api/crm/objects/deals#get-%2Fcrm%2Fv3%2Fobjects%2Fdeals%2F%7Bdealid%7D + const dealResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri:`/crm/v3/objects/deals/${dealId}`, + query:{ + properties: [...defaultProperties, ...additionalProperties].join(',') + } + }) + + return dealResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts new file mode 100644 index 0000000000..a258628be5 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts @@ -0,0 +1,40 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; + +export const getTicketAction = createAction({ + auth: hubspotAuth, + name: 'get-ticket', + displayName: 'Get Ticket', + description: 'Gets a ticket.', + props: { + ticketId : Property.ShortText({ + displayName: 'Ticket ID', + description: 'The ID of the ticket to get.', + required: true, + }), + additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.TICKET) + + }, + async run(context) { + const ticketId = context.propsValue.ticketId; + const additionalProperties = context.propsValue.additionalProperties ?? []; + + const defaultProperties = getDefaultProperties(OBJECT_TYPE.TICKET) + + // https://developers.hubspot.com/docs/reference/api/crm/objects/tickets#get-%2Fcrm%2Fv3%2Fobjects%2Ftickets%2F%7Bticketid%7D + const ticketResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri:`/crm/v3/objects/tickets/${ticketId}`, + query:{ + properties: [...defaultProperties, ...additionalProperties].join(',') + } + }) + + return ticketResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index ffd09dc1ec..1587e5e0a2 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -1,34 +1,69 @@ -const OBJECT_TYPE = { - CONTACT: 'contact', - COMPANY: 'company', - DEAL: 'deal', -}; +export const enum OBJECT_TYPE { + CONTACT = 'contact', + COMPANY = 'company', + DEAL = 'deal', + TICKET = 'ticket', +} -const DEFAULT_CONTACT_PROPERTIES = [ - 'firstname', - 'lastname', - 'email', - 'company', - 'website', - 'mobilephone', - 'phone', - 'fax', - 'address', - 'city', - 'state', - 'zip', - 'salutation', - 'country', - 'jobtitle', - 'hs_createdate', - 'hs_email_domain', - 'hs_object_id', - 'lastmodifieddate', - 'hs_persona', - 'hs_language', - 'lifecyclestage', - 'createdate', - 'numemployees', - 'annualrevenue', - 'industry', +export const DEFAULT_CONTACT_PROPERTIES = [ + 'firstname', + 'lastname', + 'email', + 'company', + 'website', + 'mobilephone', + 'phone', + 'fax', + 'address', + 'city', + 'state', + 'zip', + 'salutation', + 'country', + 'jobtitle', + 'hs_createdate', + 'hs_email_domain', + 'hs_object_id', + 'lastmodifieddate', + 'hs_persona', + 'hs_language', + 'lifecyclestage', + 'createdate', + 'numemployees', + 'annualrevenue', + 'industry', +]; + +export const DEFAULT_DEAL_PROPERTIES = [ + 'dealtype', + 'dealname', + 'amount', + 'description', + 'closedate', + 'createdate', + 'num_associated_contacts', + 'hs_forecast_amount', + 'hs_forecast_probability', + 'hs_manual_forecast_category', + 'hs_next_step', + 'hs_object_id', + 'hs_lastmodifieddate', + 'hubspot_owner_id', + 'hubspot_team_id', +]; + +export const DEFAULT_TICKET_PROPERTIES = [ + 'subject', + 'content', + 'source_type', + 'createdate', + 'hs_pipeline', + 'hs_pipeline_stage', + 'hs_resolution', + 'hs_ticket_category', + 'hs_ticket_id', + 'hs_ticket_priority', + 'hs_lastmodifieddate', + 'hubspot_owner_id', + 'hubspot_team_id', ]; diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index ddb5aaf85a..ff30463e83 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -8,6 +8,7 @@ import { hubSpotClient } from './client'; import { hubspotApiCall } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; import { HubspotProperty } from './types'; +import { DEFAULT_CONTACT_PROPERTIES, DEFAULT_DEAL_PROPERTIES, DEFAULT_TICKET_PROPERTIES } from './constants'; export const hubSpotAuthentication = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -68,8 +69,14 @@ export const hubSpotListIdDropdown = Property.Dropdown({ export function getDefaultProperties(objectType:string) { if (objectType === "contact") { - return DEFAULT_CONTACT_PROPERTIES; - } else { + return DEFAULT_CONTACT_PROPERTIES;} + else if (objectType === "deal") { + return DEFAULT_DEAL_PROPERTIES; + } + else if(objectType === "ticket") { + return DEFAULT_TICKET_PROPERTIES; + } + else { return []; } } From 6c7d34203001239bb658346a2404a8b87d4a14c7 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 20 Dec 2024 18:17:35 +0530 Subject: [PATCH 03/60] feat(hubspot): add contact to workflow action --- .../lib/actions/add-contact-to-workflow.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts new file mode 100644 index 0000000000..b76f74b260 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts @@ -0,0 +1,32 @@ +import { hubspotAuth } from "../../"; +import { createAction, Property } from "@activepieces/pieces-framework"; +import { workflowIdDropdown } from "../common/props"; +import { hubspotApiCall } from "../common"; +import { HttpMethod } from "@activepieces/pieces-common"; + +export const addContactToWorkflowAction = createAction({ + auth:hubspotAuth, + name:'add-contact-to-workflow', + displayName:'Add Contact to Workflow', + description:'Adds a contact to a specified workflow.', + props:{ + workflowId : workflowIdDropdown, + email:Property.ShortText({ + displayName:"Contact's Email", + description:'The email of the contact to add to the workflow.', + required:true + }), + }, + async run(context) { + const contactEmail = context.propsValue.email; + const workflowId = context.propsValue.workflowId; + + const response = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.POST, + resourceUri:`/automation/v2/workflows/${workflowId}/enrollments/contacts/${contactEmail}`, + }) + + return response; + }, +}) \ No newline at end of file From 87a61bd5e4229242b63a76e62f775ab8e9bb9c34 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 20 Dec 2024 18:18:16 +0530 Subject: [PATCH 04/60] feat(hubspot): get company action --- .../hubspot/src/lib/actions/get-company.ts | 39 ++++++++++ .../community/hubspot/src/lib/common/props.ts | 73 +++++++++++++++---- .../community/hubspot/src/lib/common/types.ts | 9 +++ 3 files changed, 107 insertions(+), 14 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-company.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts new file mode 100644 index 0000000000..18fef6f653 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts @@ -0,0 +1,39 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; + +export const getCompanyAction = createAction({ + auth: hubspotAuth, + name: 'get-company', + displayName: 'Get Company', + description: 'Gets a company.', + props: { + companyId : Property.ShortText({ + displayName: 'Company ID', + description: 'The ID of the company to get.', + required: true, + }), + additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.COMPANY) + + }, + async run(context) { + const companyId = context.propsValue.companyId; + const additionalProperties = context.propsValue.additionalProperties ?? []; + + const defaultProperties = getDefaultProperties(OBJECT_TYPE.COMPANY) + + const companyResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri:`/crm/v3/objects/companies/${companyId}`, + query:{ + properties: [...defaultProperties, ...additionalProperties].join(',') + } + }) + + return companyResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index ff30463e83..e054047bb8 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -7,8 +7,14 @@ import { import { hubSpotClient } from './client'; import { hubspotApiCall } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; -import { HubspotProperty } from './types'; -import { DEFAULT_CONTACT_PROPERTIES, DEFAULT_DEAL_PROPERTIES, DEFAULT_TICKET_PROPERTIES } from './constants'; +import { HubspotProperty, WorkflowResponse } from './types'; +import { + DEFAULT_COMPANY_PROPERTIES, + DEFAULT_CONTACT_PROPERTIES, + DEFAULT_DEAL_PROPERTIES, + DEFAULT_PRODUCT_PROPERTIES, + DEFAULT_TICKET_PROPERTIES, +} from './constants'; export const hubSpotAuthentication = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -67,17 +73,19 @@ export const hubSpotListIdDropdown = Property.Dropdown({ }, }); -export function getDefaultProperties(objectType:string) { - if (objectType === "contact") { - return DEFAULT_CONTACT_PROPERTIES;} - else if (objectType === "deal") { - return DEFAULT_DEAL_PROPERTIES; - } - else if(objectType === "ticket") { - return DEFAULT_TICKET_PROPERTIES; - } - else { - return []; +export function getDefaultProperties(objectType: string) { + if (objectType === 'contact') { + return DEFAULT_CONTACT_PROPERTIES; + } else if (objectType === 'deal') { + return DEFAULT_DEAL_PROPERTIES; + } else if (objectType === 'ticket') { + return DEFAULT_TICKET_PROPERTIES; + } else if (objectType === 'company') { + return DEFAULT_COMPANY_PROPERTIES; + } else if (objectType === 'product') { + return DEFAULT_PRODUCT_PROPERTIES; + } else { + return []; } } @@ -103,7 +111,7 @@ export const additionalPropertyNamesDropdown = (objectType: string) => const options: DropdownOption[] = []; for (const property of propertiesResponse.results) { - if(defaultProperties.includes(property.name)) { + if (defaultProperties.includes(property.name)) { continue; } options.push({ @@ -118,3 +126,40 @@ export const additionalPropertyNamesDropdown = (objectType: string) => }; }, }); + +export const workflowIdDropdown = Property.Dropdown({ + displayName: 'Workflow', + refreshers: [], + // description: 'Workflow to add contact to', + required: true, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const token = (auth as OAuth2PropertyValue).access_token; + const workflowsResponse = await hubspotApiCall<{ workflows: WorkflowResponse[] }>({ + accessToken: token, + method: HttpMethod.GET, + resourceUri: `/automation/v2/workflows`, + }); + + const options: DropdownOption[] = []; + + for (const workflow of workflowsResponse.workflows) { + if (workflow.enabled) { + options.push({ + label: workflow.name, + value: workflow.id, + }); + } + } + + return { + disabled: false, + options, + }; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index faf9ea600f..1889909f8d 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -154,4 +154,13 @@ export type HubspotProperty= { type: string; fieldType: HubspotFieldType; options: []; +} + +export type WorkflowResponse = +{ + id:number; + insertAt:number; + updatedAt:number; + name:string; + enabled:boolean } \ No newline at end of file From bc652dc45e5eafecda122513b8a46fd16ade8349 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 20 Dec 2024 18:18:52 +0530 Subject: [PATCH 05/60] feat(hubspot): get pipeline stage action --- .../lib/actions/get-pipeline-stage-details.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts b/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts new file mode 100644 index 0000000000..df5a640a77 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts @@ -0,0 +1,51 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; + +export const getPipelineStageDeatilsAction = createAction({ + auth: hubspotAuth, + name: 'get-pipeline-stage-details', + displayName: 'Get Pipeline Stage Details', + description: 'Finds and retrives CRM object pipeline stage details.', + props: { + objectType: Property.StaticDropdown({ + displayName: 'Object Type', + required: true, + options: { + disabled: false, + options: [ + { + label: 'Tickets', + value: 'ticket', + }, + { + label: 'Deal', + value: 'deal', + }, + ], + }, + }), + pipelineId: Property.ShortText({ + displayName: 'Pipeline ID', + required: true, + }), + stageId: Property.ShortText({ + displayName: 'Stage ID', + required: true, + }), + }, + async run(context) { + const objectType = context.propsValue.objectType; + const pipelineId = context.propsValue.pipelineId; + const stageId = context.propsValue.stageId; + + const stageResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri: `/crm/v3/pipelines/${objectType}/${pipelineId}/stages/${stageId}`, + }); + + return stageResponse; + }, +}); From e0f2d6b99c53da62db6b780acea3286134ba1534 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 20 Dec 2024 18:19:17 +0530 Subject: [PATCH 06/60] feat(hubspot): get product action --- .../pieces/community/hubspot/src/index.ts | 21 ++++++++-- .../hubspot/src/lib/actions/get-product.ts | 39 +++++++++++++++++ .../hubspot/src/lib/common/constants.ts | 42 +++++++++++++++++++ 3 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-product.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index a8813b690f..4199a338b3 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -16,6 +16,10 @@ import { dealStageUpdatedTrigger } from './lib/triggers/deal-stage-updated'; import { getContactAction } from './lib/actions/get-contact'; import { getDealAction } from './lib/actions/get-deal'; import { getTicketAction } from './lib/actions/get-ticket'; +import { getCompanyAction } from './lib/actions/get-company'; +import { getPipelineStageDeatilsAction } from './lib/actions/get-pipeline-stage-details'; +import { getProductAction } from './lib/actions/get-product'; +import { addContactToWorkflowAction } from './lib/actions/add-contact-to-workflow'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -24,18 +28,23 @@ export const hubspotAuth = PieceAuth.OAuth2({ scope: [ 'crm.lists.read', 'crm.lists.write', - 'crm.objects.contacts.read', - 'crm.objects.contacts.write', - 'crm.objects.owners.read', 'crm.objects.companies.read', 'crm.objects.companies.write', + 'crm.objects.contacts.read', + 'crm.objects.contacts.write', + 'crm.objects.custom.read', + 'crm.objects.custom.write', 'crm.objects.deals.read', 'crm.objects.deals.write', 'crm.objects.line_items.read', - 'crm.schemas.line_items.read', + 'crm.objects.owners.read', 'crm.schemas.companies.read', 'crm.schemas.contacts.read', + 'crm.schemas.custom.read', 'crm.schemas.deals.read', + 'crm.schemas.line_items.read', + 'automation', + 'e-commerce', 'tickets', ], }); @@ -55,7 +64,11 @@ export const hubspot = createPiece({ hubSpotGetOwnerByEmailAction, getContactAction, getDealAction, + getCompanyAction, getTicketAction, + getProductAction, + getPipelineStageDeatilsAction, + addContactToWorkflowAction, createDealAction, updateDealAction, createCustomApiCallAction({ diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts new file mode 100644 index 0000000000..2e21f7da67 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts @@ -0,0 +1,39 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotApiCall } from '../common'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; + +export const getProductAction = createAction({ + auth: hubspotAuth, + name: 'get-product', + displayName: 'Get Product', + description: 'Gets a product.', + props: { + productId : Property.ShortText({ + displayName: 'Product ID', + description: 'The ID of the product to get.', + required: true, + }), + additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.PRODUCT) + + }, + async run(context) { + const productId = context.propsValue.productId; + const additionalProperties = context.propsValue.additionalProperties ?? []; + + const defaultProperties = getDefaultProperties(OBJECT_TYPE.PRODUCT) + + const productResponse = await hubspotApiCall({ + accessToken: context.auth.access_token, + method: HttpMethod.GET, + resourceUri:`/crm/v3/objects/products/${productId}`, + query:{ + properties: [...defaultProperties, ...additionalProperties].join(',') + } + }) + + return productResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index 1587e5e0a2..84efcdf77f 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -3,6 +3,7 @@ export const enum OBJECT_TYPE { COMPANY = 'company', DEAL = 'deal', TICKET = 'ticket', + PRODUCT = 'product' } export const DEFAULT_CONTACT_PROPERTIES = [ @@ -67,3 +68,44 @@ export const DEFAULT_TICKET_PROPERTIES = [ 'hubspot_owner_id', 'hubspot_team_id', ]; + +export const DEFAULT_COMPANY_PROPERTIES = [ + "name", + "domain", + "industry", + "about_us", + "phone", + "address", + "address2", + "city", + "state", + "zip", + "country", + "website", + "type", + "description", + "founded_year", + "hs_createdate", + "hs_lastmodifieddate", + "hs_object_id", + "is_public", + "timezone", + "total_money_raised", + "total_revenue", + "owneremail", + "ownername", + "numberofemployees", + "annualrevenue", + "lifecyclestage", + "createdate", + "web_technologies", +]; + +export const DEFAULT_PRODUCT_PROPERTIES = [ + "createdate", + "description", + "name", + "price", + "tax", + "hs_lastmodifieddate", +]; \ No newline at end of file From 12624d064e8d7dfff20a7089b7d80a43374400d7 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 20 Dec 2024 22:06:40 +0530 Subject: [PATCH 07/60] fix(hubspot): add props and client --- package-lock.json | 87 ++++++++++++- package.json | 3 +- .../hubspot/src/lib/actions/get-contact.ts | 36 +++-- .../hubspot/src/lib/actions/get-deal.ts | 4 +- .../community/hubspot/src/lib/common/index.ts | 2 +- .../community/hubspot/src/lib/common/props.ts | 123 +++++++++++++++++- .../community/hubspot/src/lib/common/types.ts | 21 ++- 7 files changed, 252 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 188899690a..36f8bbe0bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "activepieces", - "version": "0.38.0", + "version": "0.38.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "activepieces", - "version": "0.38.0", + "version": "0.38.1", "dependencies": { "@activepieces/import-fresh-webpack": "3.3.0", "@actual-app/api": "6.8.1", @@ -276,6 +276,7 @@ "@commitlint/cli": "17.7.1", "@commitlint/config-conventional": "17.7.0", "@faker-js/faker": "8.2.0", + "@hubspot/api-client": "12.0.1", "@nx/esbuild": "20.0.1", "@nx/eslint": "20.0.1", "@nx/eslint-plugin": "20.0.1", @@ -5905,6 +5906,81 @@ "react-hook-form": "^7.0.0" } }, + "node_modules/@hubspot/api-client": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@hubspot/api-client/-/api-client-12.0.1.tgz", + "integrity": "sha512-lMxDEuhaP1KDxo0Z/t+3xAT/wzVaQCZ9ThSewj9qCMkhBMYA2ABWLOY/I+huQCERuMqkqwmMBx/NOCspBlGQGg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@types/node-fetch": "^2.5.7", + "bottleneck": "^2.19.5", + "es6-promise": "^4.2.4", + "form-data": "^2.5.0", + "lodash.get": "^4.4.2", + "lodash.merge": "^4.6.2", + "node-fetch": "^2.6.0", + "url-parse": "^1.4.3" + } + }, + "node_modules/@hubspot/api-client/node_modules/form-data": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", + "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@hubspot/api-client/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@hubspot/api-client/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -23857,6 +23933,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.19.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz", diff --git a/package.json b/package.json index 4d3b36f46f..1c0b34be44 100644 --- a/package.json +++ b/package.json @@ -292,6 +292,7 @@ "@commitlint/cli": "17.7.1", "@commitlint/config-conventional": "17.7.0", "@faker-js/faker": "8.2.0", + "@hubspot/api-client": "12.0.1", "@nx/esbuild": "20.0.1", "@nx/eslint": "20.0.1", "@nx/eslint-plugin": "20.0.1", @@ -435,4 +436,4 @@ "rollup": "npm:@rollup/wasm-node" } } -} \ No newline at end of file +} diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts index 1332dc2650..69eceda435 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -2,8 +2,9 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { hubspotApiCall } from '../common'; import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { additionalPropertyToRetriveDropdown, getDefaultProperties } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; +import { Client } from "@hubspot/api-client"; export const getContactAction = createAction({ auth: hubspotAuth, @@ -16,7 +17,7 @@ export const getContactAction = createAction({ description: 'The ID of the contact to get.', required: true, }), - additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.CONTACT) + additionalProperties:additionalPropertyToRetriveDropdown(OBJECT_TYPE.CONTACT) }, async run(context) { @@ -25,16 +26,25 @@ export const getContactAction = createAction({ const defaultProperties = getDefaultProperties(OBJECT_TYPE.CONTACT) - // https://developers.hubspot.com/docs/reference/api/crm/objects/contacts#get-%2Fcrm%2Fv3%2Fobjects%2Fcontacts%2F%7Bcontactid%7D - const contactResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri:`/crm/v3/objects/contacts/${contactId}`, - query:{ - properties: [...defaultProperties, ...additionalProperties].join(',') - } - }) - - return contactResponse; + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.crm.contacts.basicApi.getById(contactId,[...defaultProperties, ...additionalProperties]); + + return response; + + + + + // // https://developers.hubspot.com/docs/reference/api/crm/objects/contacts#get-%2Fcrm%2Fv3%2Fobjects%2Fcontacts%2F%7Bcontactid%7D + // const contactResponse = await hubspotApiCall({ + // accessToken: context.auth.access_token, + // method: HttpMethod.GET, + // resourceUri:`/crm/v3/objects/contacts/${contactId}`, + // query:{ + // properties: [...defaultProperties, ...additionalProperties].join(',') + // } + // }) + + // return contactResponse; }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts index 8bafa8cece..3cbc30755f 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts @@ -2,7 +2,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { hubspotApiCall } from '../common'; import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { additionalPropertyToRetriveDropdown, getDefaultProperties } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; export const getDealAction = createAction({ @@ -16,7 +16,7 @@ export const getDealAction = createAction({ description: 'The ID of the deal to get.', required: true, }), - additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.DEAL) + additionalProperties:additionalPropertyToRetriveDropdown(OBJECT_TYPE.DEAL) }, async run(context) { diff --git a/packages/pieces/community/hubspot/src/lib/common/index.ts b/packages/pieces/community/hubspot/src/lib/common/index.ts index 5fe2deeb4b..f9b979c8bf 100644 --- a/packages/pieces/community/hubspot/src/lib/common/index.ts +++ b/packages/pieces/community/hubspot/src/lib/common/index.ts @@ -18,7 +18,7 @@ import { } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; -enum HubspotFieldType { +export enum HubspotFieldType { BooleanCheckBox = 'booleancheckbox', Date = 'date', File = 'file', diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index e054047bb8..9dcc0d2eaa 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -1,13 +1,14 @@ import { DropdownOption, + DynamicPropsValue, OAuth2PropertyValue, PieceAuth, Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; -import { hubspotApiCall } from '.'; +import { hubspotApiCall, HubspotFieldType } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; -import { HubspotProperty, WorkflowResponse } from './types'; +import { HubspotProperty, HubspotPropertyGroup, WorkflowResponse } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, @@ -15,6 +16,7 @@ import { DEFAULT_PRODUCT_PROPERTIES, DEFAULT_TICKET_PROPERTIES, } from './constants'; +import { Record } from '@sinclair/typebox'; export const hubSpotAuthentication = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -89,7 +91,122 @@ export function getDefaultProperties(objectType: string) { } } -export const additionalPropertyNamesDropdown = (objectType: string) => +export const objectPropertiesDropdown = (objectType: string, existingProperties: string[]) => + Property.DynamicProperties({ + displayName: 'Object Properties', + refreshers: [], + required: false, + props: async ({ auth }) => { + if (!auth) return {}; + + const props: DynamicPropsValue = {}; + const token = (auth as OAuth2PropertyValue).access_token; + + const propertiyGroupsResponse = await hubspotApiCall<{ results: HubspotPropertyGroup[] }>({ + accessToken: token, + method: HttpMethod.GET, + resourceUri: `/crm/v3/properties/${objectType}/groups`, + }); + + const groupFlatMap = propertiyGroupsResponse.results.reduce((map, item) => { + map[item.name] = item.label; + return map; + }, {} as Record); + + const propertiesResponse = await hubspotApiCall<{ results: HubspotProperty[] }>({ + accessToken: token, + method: HttpMethod.GET, + resourceUri: `/crm/v3/properties/${objectType}`, + }); + + for (const property of propertiesResponse.results) { + if ( + existingProperties.includes(property.name) || + property.modificationMetadata?.readOnlyValue || + property.hidden + ) { + continue; + } + + const propertyName = `${groupFlatMap[property.groupName] ?? ''}: ${property.name}`; + + switch (property.fieldType) { + case HubspotFieldType.BooleanCheckBox: + props[property.name] = Property.Checkbox({ + displayName: propertyName, + description: property.description ?? '', + required: false, + }); + break; + case HubspotFieldType.Date: + props[property.name] = Property.DateTime({ + displayName: propertyName, + description: property.description ?? '', + required: false, + }); + break; + case HubspotFieldType.Number: + props[property.name] = Property.Number({ + displayName: propertyName, + description: property.description ?? '', + required: false, + }); + break; + case HubspotFieldType.PhoneNumber: + case HubspotFieldType.Text: + props[property.name] = Property.ShortText({ + displayName: propertyName, + description: property.description ?? '', + required: false, + }); + break; + case HubspotFieldType.TextArea: + case HubspotFieldType.Html: + props[property.name] = Property.LongText({ + displayName: propertyName, + description: property.description ?? '', + required: false, + }); + break; + case HubspotFieldType.CheckBox: + props[property.name]=Property.StaticMultiSelectDropdown({ + displayName:propertyName, + description:property.description ?? '', + required:false, + options:{ + disabled:false, + options:property.options ? property.options.map((option) => { + return { + label: option.label, + value: option.value, + }; + }):[] + } + }); + break; + case HubspotFieldType.Select: + case HubspotFieldType.Radio: + props[property.name] = Property.StaticDropdown({ + displayName: propertyName, + description: property.description ?? '', + required: false, + options: { + options: property.options ? property.options.map((option) => { + return { + label: option.label, + value: option.value, + }; + }):[] + }, + }); + break; + } + } + return props; + }, + }); + +export const additionalPropertyToRetriveDropdown = (objectType: string) => Property.MultiSelectDropdown({ displayName: 'Additional Properties', refreshers: [], diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 1889909f8d..85c4aefb7c 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -131,6 +131,7 @@ export type SearchDealsResponse = { }; }; }; +// ["date","textarea","number","select","file","calculation_equation","checkbox","calculation_rollup","text","calculation_read_time","booleancheckbox","radio","phonenumber","html"] enum HubspotFieldType { BooleanCheckBox = 'booleancheckbox', @@ -151,11 +152,27 @@ export type HubspotProperty= { name: string; label: string; description: string; + hidden:boolean; type: string; + groupName:string; fieldType: HubspotFieldType; - options: []; + referencedObjectType?:string; + modificationMetadata?:{ + archivable: boolean; + readOnlyDefinition: boolean; + readOnlyValue: boolean; + } + options: Array<{label:string,value:string}>; + } +export type HubspotPropertyGroup = { + name: string; + label: string; + displayOrder: number; + archived: boolean; +}; + export type WorkflowResponse = { id:number; @@ -163,4 +180,4 @@ export type WorkflowResponse = updatedAt:number; name:string; enabled:boolean -} \ No newline at end of file +} From 69e2a94157f9ce9221807406b5633b9def4e89ad Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 20:20:22 +0530 Subject: [PATCH 08/60] feat(hubspot): create ticket action --- .../pieces/community/hubspot/src/index.ts | 5 + .../hubspot/src/lib/actions/create-ticket.ts | 91 +++++++++++++++++++ .../community/hubspot/src/lib/common/types.ts | 4 +- 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 4199a338b3..7704309cb0 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -20,6 +20,7 @@ import { getCompanyAction } from './lib/actions/get-company'; import { getPipelineStageDeatilsAction } from './lib/actions/get-pipeline-stage-details'; import { getProductAction } from './lib/actions/get-product'; import { addContactToWorkflowAction } from './lib/actions/add-contact-to-workflow'; +import { createTicketAction } from './lib/actions/create-ticket'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -46,6 +47,9 @@ export const hubspotAuth = PieceAuth.OAuth2({ 'automation', 'e-commerce', 'tickets', + 'settings.users.read', + 'settings.users.teams.read', + // 'business_units_view.read' ], }); @@ -65,6 +69,7 @@ export const hubspot = createPiece({ getContactAction, getDealAction, getCompanyAction, + createTicketAction, getTicketAction, getProductAction, getPipelineStageDeatilsAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts new file mode 100644 index 0000000000..a0ddba845e --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts @@ -0,0 +1,91 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; +import { OBJECT_TYPE } from '../common/constants'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, + objectPropertiesDropdown, + pipelineDropdown, + pipelineStageDropdown, +} from '../common/props'; +import { MarkdownVariant } from '@activepieces/shared'; + +export const createTicketAction = createAction({ + auth: hubspotAuth, + name: 'create-ticket', + displayName: 'Create Ticket', + description: 'Creates a ticket in HubSpot.', + props: { + ticketName: Property.ShortText({ + displayName: 'Ticket Name', + description: 'The name of the ticket to create.', + required: true, + }), + pipelineId: pipelineDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Ticket Pipeline', + required: true, + }), + pipelineStageId: pipelineStageDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Ticket Pipeline Stage', + required: true, + }), + objectProperites: objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ + 'subject', + 'hs_pipeline', + 'hs_pipeline_stage', + ]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + ticketName, + pipelineId, + pipelineStageId, + objectProperites = {}, + additionalPropertiesToRetrieve = [], + } = context.propsValue; + + const ticketProperties: Record = { + subject: ticketName, + hs_pipeline: pipelineId!, + hs_pipeline_stage: pipelineStageId!, + }; + + // Add additional properties to the ticketProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + ticketProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdTicket = await client.crm.tickets.basicApi.create({ + properties: ticketProperties, + }); + + // Retrieve default properties for the ticket and merge with additional properties to retrieve + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); + + const ticketDetails = await client.crm.tickets.basicApi.getById(createdTicket.id, [ + ...defaultTicketProperties, + ...additionalPropertiesToRetrieve, + ]); + + return ticketDetails; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 85c4aefb7c..8b2ed8aa85 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -152,10 +152,10 @@ export type HubspotProperty= { name: string; label: string; description: string; - hidden:boolean; + hidden?:boolean; type: string; groupName:string; - fieldType: HubspotFieldType; + fieldType: string; referencedObjectType?:string; modificationMetadata?:{ archivable: boolean; From 8f59ccd6464331ac21b9d629bb4cc54d2a2cb775 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 20:48:35 +0530 Subject: [PATCH 09/60] fix(hubspot): fix markdown and dropdown props --- .../hubspot/src/lib/actions/get-company.ts | 69 +-- .../hubspot/src/lib/actions/get-contact.ts | 54 +-- .../hubspot/src/lib/actions/get-deal.ts | 71 +-- .../hubspot/src/lib/actions/get-product.ts | 69 +-- .../hubspot/src/lib/actions/get-ticket.ts | 70 +-- .../community/hubspot/src/lib/common/props.ts | 446 +++++++++++++----- 6 files changed, 518 insertions(+), 261 deletions(-) diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts index 18fef6f653..aa24508ad2 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts @@ -1,39 +1,50 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; export const getCompanyAction = createAction({ - auth: hubspotAuth, - name: 'get-company', - displayName: 'Get Company', - description: 'Gets a company.', - props: { - companyId : Property.ShortText({ - displayName: 'Company ID', - description: 'The ID of the company to get.', - required: true, - }), - additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.COMPANY) + auth: hubspotAuth, + name: 'get-company', + displayName: 'Get Company', + description: 'Gets a company.', + props: { + companyId: Property.ShortText({ + displayName: 'Company ID', + description: 'The ID of the company to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { companyId, additionalPropertiesToRetrieve = [] } = context.propsValue; - }, - async run(context) { - const companyId = context.propsValue.companyId; - const additionalProperties = context.propsValue.additionalProperties ?? []; + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); - const defaultProperties = getDefaultProperties(OBJECT_TYPE.COMPANY) + const client = new Client({ accessToken: context.auth.access_token }); - const companyResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri:`/crm/v3/objects/companies/${companyId}`, - query:{ - properties: [...defaultProperties, ...additionalProperties].join(',') - } - }) + const companyDetails = await client.crm.companies.basicApi.getById(companyId, [ + ...defaultCompanyProperties, + ...additionalPropertiesToRetrieve, + ]); - return companyResponse; - }, + return companyDetails; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts index 69eceda435..7bba5bb0ac 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -1,10 +1,12 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyToRetriveDropdown, getDefaultProperties } from '../common/props'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; -import { Client } from "@hubspot/api-client"; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; export const getContactAction = createAction({ auth: hubspotAuth, @@ -12,39 +14,37 @@ export const getContactAction = createAction({ displayName: 'Get Contact', description: 'Gets a contact.', props: { - contactId : Property.ShortText({ + contactId: Property.ShortText({ displayName: 'Contact ID', description: 'The ID of the contact to get.', required: true, }), - additionalProperties:additionalPropertyToRetriveDropdown(OBJECT_TYPE.CONTACT) - + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), }, async run(context) { - const contactId = context.propsValue.contactId; - const additionalProperties = context.propsValue.additionalProperties ?? []; + const { contactId, additionalPropertiesToRetrieve = [] } = context.propsValue; - const defaultProperties = getDefaultProperties(OBJECT_TYPE.CONTACT) + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); const client = new Client({ accessToken: context.auth.access_token }); - const response = await client.crm.contacts.basicApi.getById(contactId,[...defaultProperties, ...additionalProperties]); - - return response; - - - - - // // https://developers.hubspot.com/docs/reference/api/crm/objects/contacts#get-%2Fcrm%2Fv3%2Fobjects%2Fcontacts%2F%7Bcontactid%7D - // const contactResponse = await hubspotApiCall({ - // accessToken: context.auth.access_token, - // method: HttpMethod.GET, - // resourceUri:`/crm/v3/objects/contacts/${contactId}`, - // query:{ - // properties: [...defaultProperties, ...additionalProperties].join(',') - // } - // }) + const contactDetails = await client.crm.contacts.basicApi.getById(contactId, [ + ...defaultContactProperties, + ...additionalPropertiesToRetrieve, + ]); - // return contactResponse; + return contactDetails; }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts index 3cbc30755f..fa85358901 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts @@ -1,40 +1,49 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyToRetriveDropdown, getDefaultProperties } from '../common/props'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; export const getDealAction = createAction({ - auth: hubspotAuth, - name: 'get-deal', - displayName: 'Get Deal', - description: 'Gets a deal.', - props: { - dealId : Property.ShortText({ - displayName: 'Deal ID', - description: 'The ID of the deal to get.', - required: true, - }), - additionalProperties:additionalPropertyToRetriveDropdown(OBJECT_TYPE.DEAL) + auth: hubspotAuth, + name: 'get-deal', + displayName: 'Get Deal', + description: 'Gets a deal.', + props: { + dealId: Property.ShortText({ + displayName: 'Deal ID', + description: 'The ID of the deal to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { dealId, additionalPropertiesToRetrieve = [] } = context.propsValue; - }, - async run(context) { - const dealId = context.propsValue.dealId; - const additionalProperties = context.propsValue.additionalProperties ?? []; + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); - const defaultProperties = getDefaultProperties(OBJECT_TYPE.DEAL) + const client = new Client({ accessToken: context.auth.access_token }); - // https://developers.hubspot.com/docs/reference/api/crm/objects/deals#get-%2Fcrm%2Fv3%2Fobjects%2Fdeals%2F%7Bdealid%7D - const dealResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri:`/crm/v3/objects/deals/${dealId}`, - query:{ - properties: [...defaultProperties, ...additionalProperties].join(',') - } - }) - - return dealResponse; - }, + const dealDeatils = await client.crm.deals.basicApi.getById(dealId, [ + ...defaultDealProperties, + ...additionalPropertiesToRetrieve, + ]); + return dealDeatils; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts index 2e21f7da67..c2d2b708fc 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts @@ -1,39 +1,50 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; export const getProductAction = createAction({ - auth: hubspotAuth, - name: 'get-product', - displayName: 'Get Product', - description: 'Gets a product.', - props: { - productId : Property.ShortText({ - displayName: 'Product ID', - description: 'The ID of the product to get.', - required: true, - }), - additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.PRODUCT) + auth: hubspotAuth, + name: 'get-product', + displayName: 'Get Product', + description: 'Gets a product.', + props: { + productId: Property.ShortText({ + displayName: 'Product ID', + description: 'The ID of the product to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { productId, additionalPropertiesToRetrieve = [] } = context.propsValue; - }, - async run(context) { - const productId = context.propsValue.productId; - const additionalProperties = context.propsValue.additionalProperties ?? []; + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); - const defaultProperties = getDefaultProperties(OBJECT_TYPE.PRODUCT) + const client = new Client({ accessToken: context.auth.access_token }); - const productResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri:`/crm/v3/objects/products/${productId}`, - query:{ - properties: [...defaultProperties, ...additionalProperties].join(',') - } - }) + const productDetails = await client.crm.products.basicApi.getById(productId, [ + ...defaultProductProperties, + ...additionalPropertiesToRetrieve, + ]); - return productResponse; - }, + return productDetails; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts index a258628be5..dc66cf115b 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts @@ -1,40 +1,50 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; -import { additionalPropertyNamesDropdown, getDefaultProperties } from '../common/props'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; export const getTicketAction = createAction({ - auth: hubspotAuth, - name: 'get-ticket', - displayName: 'Get Ticket', - description: 'Gets a ticket.', - props: { - ticketId : Property.ShortText({ - displayName: 'Ticket ID', - description: 'The ID of the ticket to get.', - required: true, - }), - additionalProperties:additionalPropertyNamesDropdown(OBJECT_TYPE.TICKET) + auth: hubspotAuth, + name: 'get-ticket', + displayName: 'Get Ticket', + description: 'Gets a ticket.', + props: { + ticketId: Property.ShortText({ + displayName: 'Ticket ID', + description: 'The ID of the ticket to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { ticketId, additionalPropertiesToRetrieve = [] } = context.propsValue; - }, - async run(context) { - const ticketId = context.propsValue.ticketId; - const additionalProperties = context.propsValue.additionalProperties ?? []; + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); - const defaultProperties = getDefaultProperties(OBJECT_TYPE.TICKET) + const client = new Client({ accessToken: context.auth.access_token }); - // https://developers.hubspot.com/docs/reference/api/crm/objects/tickets#get-%2Fcrm%2Fv3%2Fobjects%2Ftickets%2F%7Bticketid%7D - const ticketResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri:`/crm/v3/objects/tickets/${ticketId}`, - query:{ - properties: [...defaultProperties, ...additionalProperties].join(',') - } - }) + const ticketDeatils = await client.crm.tickets.basicApi.getById(ticketId, [ + ...defaultTicketProperties, + ...additionalPropertiesToRetrieve, + ]); - return ticketResponse; - }, + return ticketDeatils; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 9dcc0d2eaa..9ec11e73ff 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -3,20 +3,23 @@ import { DynamicPropsValue, OAuth2PropertyValue, PieceAuth, + PiecePropValueSchema, Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; import { hubspotApiCall, HubspotFieldType } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; -import { HubspotProperty, HubspotPropertyGroup, WorkflowResponse } from './types'; +import { HubspotPropertyGroup, WorkflowResponse, HubspotProperty } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, DEFAULT_DEAL_PROPERTIES, DEFAULT_PRODUCT_PROPERTIES, DEFAULT_TICKET_PROPERTIES, + OBJECT_TYPE, } from './constants'; -import { Record } from '@sinclair/typebox'; +import { Client } from '@hubspot/api-client'; +import { hubspotAuth } from '@activepieces/piece-hubspot'; export const hubSpotAuthentication = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -75,23 +78,189 @@ export const hubSpotListIdDropdown = Property.Dropdown({ }, }); -export function getDefaultProperties(objectType: string) { - if (objectType === 'contact') { - return DEFAULT_CONTACT_PROPERTIES; - } else if (objectType === 'deal') { - return DEFAULT_DEAL_PROPERTIES; - } else if (objectType === 'ticket') { - return DEFAULT_TICKET_PROPERTIES; - } else if (objectType === 'company') { - return DEFAULT_COMPANY_PROPERTIES; - } else if (objectType === 'product') { - return DEFAULT_PRODUCT_PROPERTIES; - } else { - return []; +export function getDefaultPropertiesForObject(objectType: OBJECT_TYPE): string[] { + switch (objectType) { + case OBJECT_TYPE.CONTACT: + return DEFAULT_CONTACT_PROPERTIES; + case OBJECT_TYPE.DEAL: + return DEFAULT_DEAL_PROPERTIES; + case OBJECT_TYPE.TICKET: + return DEFAULT_TICKET_PROPERTIES; + case OBJECT_TYPE.COMPANY: + return DEFAULT_COMPANY_PROPERTIES; + case OBJECT_TYPE.PRODUCT: + return DEFAULT_PRODUCT_PROPERTIES; + default: + return []; } } -export const objectPropertiesDropdown = (objectType: string, existingProperties: string[]) => +async function fetchOwnersOptions(accessToken: string): Promise[]> { + const client = new Client({ accessToken: accessToken }); + const limit = 100; + const options: DropdownOption[] = []; + + let after: string | undefined; + do { + const response = await client.crm.owners.ownersApi.getPage(undefined, after, limit); + for (const owner of response.results) + if (owner.email) { + options.push({ + label: owner.email, + value: owner.id, + }); + } + after = response.paging?.next?.after; + } while (after); + return options; +} + +async function fetchUsersOptions(accessToken: string): Promise[]> { + const client = new Client({ accessToken: accessToken }); + const limit = 100; + const options: DropdownOption[] = []; + + let after: string | undefined; + do { + const response = await client.settings.users.usersApi.getPage(limit, after); + for (const user of response.results) { + if (user.email) { + options.push({ + label: user.email, + value: user.id, + }); + } + } + after = response.paging?.next?.after; + } while (after); + return options; +} + +async function fetchTeamsOptions(accessToken: string): Promise[]> { + const client = new Client({ accessToken: accessToken }); + const options: DropdownOption[] = []; + + const response = await client.settings.users.teamsApi.getAll(); + for (const team of response.results) { + if (team.name) { + options.push({ + label: team.name, + value: team.id, + }); + } + } + return options; +} + +// async function fetchBusinessUnitsOptions(accessToken: string): Promise[]> { +// const client = new Client({ accessToken: accessToken }); +// const options: DropdownOption[] = []; + +// const response = await client.settings.businessUnits.businessUnitApi.getByUserID() +// for (const businessUnit of response.results) { +// if (businessUnit.name) { +// options.push({ +// label: businessUnit.name, +// value: businessUnit.id, +// }); +// } +// } +// return options; +// } + +async function createReferencedPropertyDefinition( + property: HubspotProperty, + propertyDisplayName: string, + accessToken: string, +) { + let options: DropdownOption[] = []; + + switch (property.referencedObjectType) { + case 'OWNER': + options = await fetchOwnersOptions(accessToken); + break; + default: + return null; + } + + return Property.StaticDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options, + }, + }); +} + +function createPropertyDefinition(property: HubspotProperty, propertyDisplayName: string) { + switch (property.fieldType) { + case HubspotFieldType.BooleanCheckBox: + return Property.Checkbox({ + displayName: propertyDisplayName, + required: false, + }); + case HubspotFieldType.Date: + return Property.DateTime({ + displayName: propertyDisplayName, + description: property.type === 'date' ? 'Provide date in YYYY-MM-DD format' : '', + required: false, + }); + case HubspotFieldType.Number: + return Property.Number({ + displayName: propertyDisplayName, + required: false, + }); + case HubspotFieldType.PhoneNumber: + case HubspotFieldType.Text: + return Property.ShortText({ + displayName: propertyDisplayName, + required: false, + }); + case HubspotFieldType.TextArea: + case HubspotFieldType.Html: + return Property.LongText({ + displayName: propertyDisplayName, + required: false, + }); + case HubspotFieldType.CheckBox: + return Property.StaticMultiSelectDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: property.options + ? property.options.map((option) => { + return { + label: option.label, + value: option.value, + }; + }) + : [], + }, + }); + case HubspotFieldType.Select: + case HubspotFieldType.Radio: + return Property.StaticDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + options: property.options + ? property.options.map((option) => { + return { + label: option.label, + value: option.value, + }; + }) + : [], + }, + }); + default: + return null; + } +} + +export const objectPropertiesDropdown = (objectType: string, excludedProperties: string[]) => Property.DynamicProperties({ displayName: 'Object Properties', refreshers: [], @@ -100,134 +269,108 @@ export const objectPropertiesDropdown = (objectType: string, existingProperties: if (!auth) return {}; const props: DynamicPropsValue = {}; - const token = (auth as OAuth2PropertyValue).access_token; + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); - const propertiyGroupsResponse = await hubspotApiCall<{ results: HubspotPropertyGroup[] }>({ - accessToken: token, - method: HttpMethod.GET, - resourceUri: `/crm/v3/properties/${objectType}/groups`, - }); + const propertyGroups = await client.crm.properties.groupsApi.getAll(objectType); - const groupFlatMap = propertiyGroupsResponse.results.reduce((map, item) => { - map[item.name] = item.label; + const groupLabels = propertyGroups.results.reduce((map, group) => { + map[group.name] = group.label; return map; }, {} as Record); - const propertiesResponse = await hubspotApiCall<{ results: HubspotProperty[] }>({ - accessToken: token, - method: HttpMethod.GET, - resourceUri: `/crm/v3/properties/${objectType}`, - }); + const allProperties = await client.crm.properties.coreApi.getAll(objectType); - for (const property of propertiesResponse.results) { + for (const property of allProperties.results) { + // skip read only properties if ( - existingProperties.includes(property.name) || + excludedProperties.includes(property.name) || property.modificationMetadata?.readOnlyValue || property.hidden ) { continue; } - const propertyName = `${groupFlatMap[property.groupName] ?? ''}: ${property.name}`; - - switch (property.fieldType) { - case HubspotFieldType.BooleanCheckBox: - props[property.name] = Property.Checkbox({ - displayName: propertyName, - description: property.description ?? '', - required: false, - }); - break; - case HubspotFieldType.Date: - props[property.name] = Property.DateTime({ - displayName: propertyName, - description: property.description ?? '', - required: false, - }); - break; - case HubspotFieldType.Number: - props[property.name] = Property.Number({ - displayName: propertyName, - description: property.description ?? '', - required: false, - }); - break; - case HubspotFieldType.PhoneNumber: - case HubspotFieldType.Text: - props[property.name] = Property.ShortText({ - displayName: propertyName, - description: property.description ?? '', - required: false, - }); - break; - case HubspotFieldType.TextArea: - case HubspotFieldType.Html: - props[property.name] = Property.LongText({ - displayName: propertyName, - description: property.description ?? '', - required: false, - }); - break; - case HubspotFieldType.CheckBox: - props[property.name]=Property.StaticMultiSelectDropdown({ - displayName:propertyName, - description:property.description ?? '', - required:false, - options:{ - disabled:false, - options:property.options ? property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }):[] - } - }); - break; - case HubspotFieldType.Select: - case HubspotFieldType.Radio: - props[property.name] = Property.StaticDropdown({ - displayName: propertyName, - description: property.description ?? '', - required: false, - options: { - options: property.options ? property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }):[] - }, - }); - break; + // create property name with property group name + const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; + + if (property.referencedObjectType) { + props[property.name] = await createReferencedPropertyDefinition( + property, + propertyDisplayName, + authValue.access_token, + ); + continue; } + if (property.name === 'hs_shared_user_ids') { + const userOptions = await fetchUsersOptions(authValue.access_token); + props[property.name] = Property.StaticMultiSelectDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: userOptions, + }, + }); + continue; + } + if (property.name === 'hs_shared_team_ids') { + const teamOptions = await fetchTeamsOptions(authValue.access_token); + props[property.name] = Property.StaticMultiSelectDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: teamOptions, + }, + }); + continue; + } + if(property.name ==="hs_all_assigned_business_unit_ids") + { + // TO DO : Add business unit options + // const businessUnitOptions = await fetchBusinessUnitsOptions(authValue.access_token); + // props[property.name] = Property.StaticMultiSelectDropdown({ + // displayName: propertyDisplayName, + // required: false, + // options: { + // disabled: false, + // options: businessUnitOptions, + // }, + // }); + continue; + } + + props[property.name] = createPropertyDefinition(property, propertyDisplayName); } - return props; + // Remove null props + return Object.fromEntries(Object.entries(props).filter(([_, prop]) => prop !== null)); }, }); -export const additionalPropertyToRetriveDropdown = (objectType: string) => +export const additionalPropertiesToRetriveDropdown = (params: DropdownParams) => Property.MultiSelectDropdown({ - displayName: 'Additional Properties', + displayName: params.displayName, refreshers: [], - required: false, + required: params.required, + description: params.description, options: async ({ auth }) => { if (!auth) { return buildEmptyList({ placeholder: 'Please connect your account.', }); } - const token = (auth as OAuth2PropertyValue).access_token; - const propertiesResponse = await hubspotApiCall<{ results: HubspotProperty[] }>({ - accessToken: token, - method: HttpMethod.GET, - resourceUri: `/crm/v3/properties/${objectType}`, - }); + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); - const defaultProperties = getDefaultProperties(objectType); + // Fetch all properties for the given object type + const allProperties = await client.crm.properties.coreApi.getAll(params.objectType); + const defaultProperties = getDefaultPropertiesForObject(params.objectType); + + // Filter and create options for properties that are not default const options: DropdownOption[] = []; - for (const property of propertiesResponse.results) { + for (const property of allProperties.results) { if (defaultProperties.includes(property.name)) { continue; } @@ -280,3 +423,76 @@ export const workflowIdDropdown = Property.Dropdown({ }; }, }); + +export const pipelineDropdown = (params: DropdownParams) => + Property.Dropdown({ + displayName: params.displayName, + refreshers: [], + required: params.required, + description: params.description, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const pipelinesResponse = await client.crm.pipelines.pipelinesApi.getAll(params.objectType); + + const options = pipelinesResponse.results.map((pipeline) => { + return { + label: pipeline.label, + value: pipeline.id, + }; + }); + return { + disabled: false, + options, + }; + }, + }); + +export const pipelineStageDropdown = (params: DropdownParams) => + Property.Dropdown({ + displayName: params.displayName, + refreshers: ['pipelineId'], + required: params.required, + description: params.description, + options: async ({ auth, pipelineId }) => { + if (!auth || !pipelineId) { + return buildEmptyList({ + placeholder: 'Please connect your account and select a pipeline.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const pipelineStagesResponse = await client.crm.pipelines.pipelineStagesApi.getAll( + params.objectType, + pipelineId as string, + ); + + const options = pipelineStagesResponse.results.map((stage) => { + return { + label: stage.label, + value: stage.id, + }; + }); + + return { + disabled: false, + options, + }; + }, + }); + +type DropdownParams = { + objectType: OBJECT_TYPE; + displayName: string; + required: boolean; + description?: string; +}; From ac78d68a3a3f9822ad7b70b3171d9c03557c47cf Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 21:12:56 +0530 Subject: [PATCH 10/60] feat(hubspot): update ticket action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/update-ticket.ts | 107 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 7704309cb0..f9d8aa0032 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -21,6 +21,7 @@ import { getPipelineStageDeatilsAction } from './lib/actions/get-pipeline-stage- import { getProductAction } from './lib/actions/get-product'; import { addContactToWorkflowAction } from './lib/actions/add-contact-to-workflow'; import { createTicketAction } from './lib/actions/create-ticket'; +import { updateTicketAction } from './lib/actions/update-ticket'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -70,6 +71,7 @@ export const hubspot = createPiece({ getDealAction, getCompanyAction, createTicketAction, + updateTicketAction, getTicketAction, getProductAction, getPipelineStageDeatilsAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts new file mode 100644 index 0000000000..5c2238c378 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts @@ -0,0 +1,107 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; +import { OBJECT_TYPE } from '../common/constants'; +import { + additionalPropertiesToRetriveDropdown, + getDefaultPropertiesForObject, + objectPropertiesDropdown, + pipelineDropdown, + pipelineStageDropdown, +} from '../common/props'; +import { MarkdownVariant } from '@activepieces/shared'; + +export const updateTicketAction = createAction({ + auth: hubspotAuth, + name: 'update-ticket', + displayName: 'Update Ticket', + description: 'Updates a ticket in HubSpot.', + props: { + ticketId: Property.ShortText({ + displayName: 'Ticket ID', + description: 'The ID of the ticket to update.', + required: true, + }), + ticketName: Property.ShortText({ + displayName: 'Ticket Name', + description: 'The name of the ticket to create.', + required: false, + }), + pipelineId: pipelineDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Ticket Pipeline', + required: false, + }), + pipelineStageId: pipelineStageDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Ticket Pipeline Stage', + required: false, + }), + objectProperites: objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ + 'subject', + 'hs_pipeline', + 'hs_pipeline_stage', + ]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + ticketId, + ticketName, + pipelineId, + pipelineStageId, + objectProperites = {}, + additionalPropertiesToRetrieve = [], + } = context.propsValue; + + const ticketProperties: Record = { + }; + + if(ticketName) + { + ticketProperties['subject'] = ticketName; + } + if(pipelineId) + { + ticketProperties['hs_pipeline'] = pipelineId; + } + if(pipelineStageId) + { + ticketProperties['hs_pipeline_stage'] = pipelineStageId; + } + + // Add additional properties to the ticketProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + ticketProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedTicket = await client.crm.tickets.basicApi.update(ticketId,{ + properties: ticketProperties, + }); + + // Retrieve default properties for the ticket and merge with additional properties to retrieve + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); + + const ticketDetails = await client.crm.tickets.basicApi.getById(updatedTicket.id, [ + ...defaultTicketProperties, + ...additionalPropertiesToRetrieve, + ]); + + return ticketDetails; + }, +}); From 9c564703223589b11593f0e15c2968eeefdbdcbb Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 23:09:01 +0530 Subject: [PATCH 11/60] feat(hubspot): find ticket action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/create-ticket.ts | 7 +- .../hubspot/src/lib/actions/find-ticket.ts | 93 +++++++++++++++++++ .../hubspot/src/lib/actions/get-company.ts | 8 +- .../hubspot/src/lib/actions/get-contact.ts | 8 +- .../hubspot/src/lib/actions/get-deal.ts | 8 +- .../hubspot/src/lib/actions/get-product.ts | 8 +- .../hubspot/src/lib/actions/get-ticket.ts | 8 +- .../hubspot/src/lib/actions/update-ticket.ts | 7 +- .../community/hubspot/src/lib/common/props.ts | 29 ++++-- .../community/hubspot/src/lib/common/types.ts | 16 ++++ 11 files changed, 166 insertions(+), 28 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index f9d8aa0032..3343427c9c 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -22,6 +22,7 @@ import { getProductAction } from './lib/actions/get-product'; import { addContactToWorkflowAction } from './lib/actions/add-contact-to-workflow'; import { createTicketAction } from './lib/actions/create-ticket'; import { updateTicketAction } from './lib/actions/update-ticket'; +import { findTicketAction } from './lib/actions/find-ticket'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -73,6 +74,7 @@ export const hubspot = createPiece({ createTicketAction, updateTicketAction, getTicketAction, + findTicketAction, getProductAction, getPipelineStageDeatilsAction, addContactToWorkflowAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts index a0ddba845e..35055ffeea 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts @@ -3,7 +3,7 @@ import { createAction, Property } from '@activepieces/pieces-framework'; import { Client } from '@hubspot/api-client'; import { OBJECT_TYPE } from '../common/constants'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, objectPropertiesDropdown, pipelineDropdown, @@ -45,7 +45,7 @@ export const createTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, @@ -57,8 +57,9 @@ export const createTicketAction = createAction({ pipelineId, pipelineStageId, objectProperites = {}, - additionalPropertiesToRetrieve = [], } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const ticketProperties: Record = { subject: ticketName, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts new file mode 100644 index 0000000000..f01c0b631f --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts @@ -0,0 +1,93 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +export const findTicketAction = createAction({ + auth: hubspotAuth, + name: 'find-ticket', + displayName: 'Find Ticket', + description: 'Finds a ticket by searching.', + props: { + firstSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.TICKET, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.TICKET, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); + + const response = client.crm.tickets.searchApi.doSearch({ + limit: 100, + properties: [...defaultTicketProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts index aa24508ad2..dfb8f54e17 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts @@ -1,7 +1,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -27,14 +27,16 @@ export const getCompanyAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.COMPANY, displayName: 'Additional properties to retrieve', required: false, }), }, async run(context) { - const { companyId, additionalPropertiesToRetrieve = [] } = context.propsValue; + const { companyId } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts index 7bba5bb0ac..531882eb94 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -1,7 +1,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -27,14 +27,16 @@ export const getContactAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', required: false, }), }, async run(context) { - const { contactId, additionalPropertiesToRetrieve = [] } = context.propsValue; + const { contactId } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts index fa85358901..4137cb6c04 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts @@ -1,7 +1,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -27,14 +27,16 @@ export const getDealAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.DEAL, displayName: 'Additional properties to retrieve', required: false, }), }, async run(context) { - const { dealId, additionalPropertiesToRetrieve = [] } = context.propsValue; + const { dealId } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts index c2d2b708fc..4680d00bd7 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts @@ -1,7 +1,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -27,14 +27,16 @@ export const getProductAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.PRODUCT, displayName: 'Additional properties to retrieve', required: false, }), }, async run(context) { - const { productId, additionalPropertiesToRetrieve = [] } = context.propsValue; + const { productId } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts index dc66cf115b..f48c3397e2 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts @@ -1,7 +1,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -27,14 +27,16 @@ export const getTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, }), }, async run(context) { - const { ticketId, additionalPropertiesToRetrieve = [] } = context.propsValue; + const { ticketId, } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts index 5c2238c378..f3c8ca53aa 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts @@ -3,7 +3,7 @@ import { createAction, Property } from '@activepieces/pieces-framework'; import { Client } from '@hubspot/api-client'; import { OBJECT_TYPE } from '../common/constants'; import { - additionalPropertiesToRetriveDropdown, + propertiesDropdown, getDefaultPropertiesForObject, objectPropertiesDropdown, pipelineDropdown, @@ -50,7 +50,7 @@ export const updateTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: additionalPropertiesToRetriveDropdown({ + additionalPropertiesToRetrieve: propertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, @@ -63,8 +63,9 @@ export const updateTicketAction = createAction({ pipelineId, pipelineStageId, objectProperites = {}, - additionalPropertiesToRetrieve = [], } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; + const ticketProperties: Record = { }; diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 9ec11e73ff..3dc69cc81e 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -326,8 +326,7 @@ export const objectPropertiesDropdown = (objectType: string, excludedProperties: }); continue; } - if(property.name ==="hs_all_assigned_business_unit_ids") - { + if (property.name === 'hs_all_assigned_business_unit_ids') { // TO DO : Add business unit options // const businessUnitOptions = await fetchBusinessUnitsOptions(authValue.access_token); // props[property.name] = Property.StaticMultiSelectDropdown({ @@ -348,8 +347,13 @@ export const objectPropertiesDropdown = (objectType: string, excludedProperties: }, }); -export const additionalPropertiesToRetriveDropdown = (params: DropdownParams) => - Property.MultiSelectDropdown({ +export const propertiesDropdown = ( + params: DropdownParams, + includeDefaultProperties: boolean = false, + isSingleSelect: boolean = false, +) => { + const dropdownFunction = isSingleSelect ? Property.Dropdown : Property.MultiSelectDropdown; + return dropdownFunction({ displayName: params.displayName, refreshers: [], required: params.required, @@ -366,16 +370,26 @@ export const additionalPropertiesToRetriveDropdown = (params: DropdownParams) => // Fetch all properties for the given object type const allProperties = await client.crm.properties.coreApi.getAll(params.objectType); - const defaultProperties = getDefaultPropertiesForObject(params.objectType); + const propertyGroups = await client.crm.properties.groupsApi.getAll(params.objectType); + + const groupLabels = propertyGroups.results.reduce((map, group) => { + map[group.name] = group.label; + return map; + }, {} as Record); + + const defaultProperties = includeDefaultProperties + ? [] + : getDefaultPropertiesForObject(params.objectType); // Filter and create options for properties that are not default const options: DropdownOption[] = []; for (const property of allProperties.results) { - if (defaultProperties.includes(property.name)) { + if (!includeDefaultProperties && defaultProperties.includes(property.name)) { continue; } + const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; options.push({ - label: property.label, + label: propertyDisplayName, value: property.name, }); } @@ -386,6 +400,7 @@ export const additionalPropertiesToRetriveDropdown = (params: DropdownParams) => }; }, }); +}; export const workflowIdDropdown = Property.Dropdown({ displayName: 'Workflow', diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 8b2ed8aa85..6ff04bfc02 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -181,3 +181,19 @@ export type WorkflowResponse = name:string; enabled:boolean } + +export enum FilterOperatorEnum { + Eq = "EQ", + Neq = "NEQ", + Lt = "LT", + Lte = "LTE", + Gt = "GT", + Gte = "GTE", + Between = "BETWEEN", + In = "IN", + NotIn = "NOT_IN", + HasProperty = "HAS_PROPERTY", + NotHasProperty = "NOT_HAS_PROPERTY", + ContainsToken = "CONTAINS_TOKEN", + NotContainsToken = "NOT_CONTAINS_TOKEN", +} \ No newline at end of file From c53697beecc74cf9808951d1e5673ce62e16de24 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 23:13:57 +0530 Subject: [PATCH 12/60] fix(hubspot): fix lint issue --- packages/pieces/community/hubspot/src/lib/common/props.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 3dc69cc81e..b4dbfdd87f 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -9,7 +9,7 @@ import { import { hubSpotClient } from './client'; import { hubspotApiCall, HubspotFieldType } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; -import { HubspotPropertyGroup, WorkflowResponse, HubspotProperty } from './types'; +import { WorkflowResponse, HubspotProperty } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, @@ -19,7 +19,7 @@ import { OBJECT_TYPE, } from './constants'; import { Client } from '@hubspot/api-client'; -import { hubspotAuth } from '@activepieces/piece-hubspot'; +import { hubspotAuth } from '../../'; export const hubSpotAuthentication = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -349,8 +349,8 @@ export const objectPropertiesDropdown = (objectType: string, excludedProperties: export const propertiesDropdown = ( params: DropdownParams, - includeDefaultProperties: boolean = false, - isSingleSelect: boolean = false, + includeDefaultProperties = false, + isSingleSelect = false, ) => { const dropdownFunction = isSingleSelect ? Property.Dropdown : Property.MultiSelectDropdown; return dropdownFunction({ From cacb75a2c25f423cb6150d8a56384873a87f73d9 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sat, 21 Dec 2024 23:14:48 +0530 Subject: [PATCH 13/60] chore: bump piece version --- packages/pieces/community/hubspot/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pieces/community/hubspot/package.json b/packages/pieces/community/hubspot/package.json index c15d2690ca..eada8f401e 100644 --- a/packages/pieces/community/hubspot/package.json +++ b/packages/pieces/community/hubspot/package.json @@ -1,4 +1,4 @@ { "name": "@activepieces/piece-hubspot", - "version": "0.5.8" + "version": "0.5.9" } From 1ea54cee4cbf23a5dc8fa8b84087beac6be60f23 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 12:23:00 +0530 Subject: [PATCH 14/60] feat(hubspot): create contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/create-contact.ts | 60 +++++++++++++++++++ .../hubspot/src/lib/actions/create-ticket.ts | 4 +- .../hubspot/src/lib/actions/update-ticket.ts | 2 +- 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-contact.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 3343427c9c..e3939c5856 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -23,6 +23,7 @@ import { addContactToWorkflowAction } from './lib/actions/add-contact-to-workflo import { createTicketAction } from './lib/actions/create-ticket'; import { updateTicketAction } from './lib/actions/update-ticket'; import { findTicketAction } from './lib/actions/find-ticket'; +import { createContactAction } from './lib/actions/create-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -68,6 +69,7 @@ export const hubspot = createPiece({ hubSpotContactsCreateOrUpdateAction, hubSpotListsAddContactAction, hubSpotGetOwnerByEmailAction, + createContactAction, getContactAction, getDealAction, getCompanyAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts new file mode 100644 index 0000000000..426d18ac0b --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts @@ -0,0 +1,60 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + objectPropertiesDropdown, + propertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const createContactAction = createAction({ + auth: hubspotAuth, + name: 'create-contact', + displayName: 'Create Contact', + description: 'Creates a contact in Hubspot.', + props: { + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, []), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const contactProperties: Record = {}; + + // Add additional properties to the contactProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + contactProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdContact = await client.crm.contacts.basicApi.create({ + properties: contactProperties, + }); + // Retrieve default properties for the contact and merge with additional properties to retrieve + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + + const contactDetails = await client.crm.contacts.basicApi.getById(createdContact.id, [ + ...defaultContactProperties, + ...additionalPropertiesToRetrieve, + ]); + + return contactDetails; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts index 35055ffeea..14a20bdc1f 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts @@ -32,7 +32,7 @@ export const createTicketAction = createAction({ displayName: 'Ticket Pipeline Stage', required: true, }), - objectProperites: objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ + objectProperties : objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ 'subject', 'hs_pipeline', 'hs_pipeline_stage', @@ -56,8 +56,8 @@ export const createTicketAction = createAction({ ticketName, pipelineId, pipelineStageId, - objectProperites = {}, } = context.propsValue; + const objectProperites = context.propsValue.objectProperties??{}; const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts index f3c8ca53aa..3d748372c1 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts @@ -62,8 +62,8 @@ export const updateTicketAction = createAction({ ticketName, pipelineId, pipelineStageId, - objectProperites = {}, } = context.propsValue; + const objectProperites = context.propsValue.objectProperites??{}; const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve??[]; From 0d5063677f431db3e58c12e71fa6564dae190ed6 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 12:44:58 +0530 Subject: [PATCH 15/60] feat(hubspot): update contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/update-contact.ts | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/update-contact.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index e3939c5856..0494f9438e 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -24,6 +24,7 @@ import { createTicketAction } from './lib/actions/create-ticket'; import { updateTicketAction } from './lib/actions/update-ticket'; import { findTicketAction } from './lib/actions/find-ticket'; import { createContactAction } from './lib/actions/create-contact'; +import { updateContactAction } from './lib/actions/update-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -70,6 +71,7 @@ export const hubspot = createPiece({ hubSpotListsAddContactAction, hubSpotGetOwnerByEmailAction, createContactAction, + updateContactAction, getContactAction, getDealAction, getCompanyAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts new file mode 100644 index 0000000000..98cb5bfd6e --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts @@ -0,0 +1,66 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + objectPropertiesDropdown, + propertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const updateContactAction = createAction({ + auth: hubspotAuth, + name: 'update-contact', + displayName: 'Update Contact', + description: 'Updates a contact in Hubspot.', + props: { + contactId: Property.ShortText({ + displayName: 'Contact ID', + description: 'The ID of the contact to update.', + required: true, + }), + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, []), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const {contactId} = context.propsValue; + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const contactProperties: Record = {}; + + // Add additional properties to the contactProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + contactProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedContact = await client.crm.contacts.basicApi.update(contactId, { + properties: contactProperties, + }); + // Retrieve default properties for the contact and merge with additional properties to retrieve + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + + const contactDetails = await client.crm.contacts.basicApi.getById(updatedContact.id, [ + ...defaultContactProperties, + ...additionalPropertiesToRetrieve, + ]); + + return contactDetails; + }, +}); From 7a1eecc6e1ea2aaf72de6104c70d7f0c2c3a8919 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 13:11:46 +0530 Subject: [PATCH 16/60] feat(hubspot): find contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/find-contact.ts | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-contact.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 0494f9438e..8dd48b9cf4 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -25,6 +25,7 @@ import { updateTicketAction } from './lib/actions/update-ticket'; import { findTicketAction } from './lib/actions/find-ticket'; import { createContactAction } from './lib/actions/create-contact'; import { updateContactAction } from './lib/actions/update-contact'; +import { findContactAction } from './lib/actions/find-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -78,6 +79,7 @@ export const hubspot = createPiece({ createTicketAction, updateTicketAction, getTicketAction, + findContactAction, findTicketAction, getProductAction, getPipelineStageDeatilsAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts new file mode 100644 index 0000000000..24bd02e4d0 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts @@ -0,0 +1,93 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +export const findContactAction = createAction({ + auth: hubspotAuth, + name: 'find-contact', + displayName: 'Find Contact', + description: 'Finds a contact by searching.', + props: { + firstSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.CONTACT, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + + const response = client.crm.contacts.searchApi.doSearch({ + limit: 100, + properties: [...defaultContactProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + + return response; + }, +}); From 41a3ee09f6e435097a9998b4648fd760ce3fb749 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 14:21:42 +0530 Subject: [PATCH 17/60] feat(hubspot): create or update contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../lib/actions/create-or-update-contact.ts | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 8dd48b9cf4..61b1fa80ff 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -26,6 +26,7 @@ import { findTicketAction } from './lib/actions/find-ticket'; import { createContactAction } from './lib/actions/create-contact'; import { updateContactAction } from './lib/actions/update-contact'; import { findContactAction } from './lib/actions/find-contact'; +import { createOrUpdateContactAction } from './lib/actions/create-or-update-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -80,6 +81,7 @@ export const hubspot = createPiece({ updateTicketAction, getTicketAction, findContactAction, + createOrUpdateContactAction, findTicketAction, getProductAction, getPipelineStageDeatilsAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts new file mode 100644 index 0000000000..7c5a4407ba --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts @@ -0,0 +1,56 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { objectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +export const createOrUpdateContactAction = createAction({ + auth: hubspotAuth, + name: 'create-or-update-contact', + displayName: 'Create or Update Contact', + description: 'Creates a new contact or updates an existing contact based on email address.', + props: { + email: Property.ShortText({ + displayName: 'Contact Email', + required: true, + }), + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, ['email']), + }, + async run(context) { + const email = context.propsValue.email; + const objectProperties = context.propsValue.objectProperties ?? {}; + + const contactProperties: Record = {}; + + // Add additional properties to the contactProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + contactProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const searchResponse = await client.crm.contacts.searchApi.doSearch({ + limit: 1, + filterGroups: [ + { filters: [{ propertyName: 'email', operator: FilterOperatorEnum.Eq, value: email }] }, + ], + }); + + if (searchResponse.results.length > 0) { + const updatedContact = await client.crm.contacts.basicApi.update( + searchResponse.results[0].id, + { + properties: contactProperties, + }, + ); + return updatedContact; + } else { + const createdContact = await client.crm.contacts.basicApi.create({ + properties: { ...contactProperties, email }, + }); + return createdContact; + } + }, +}); From 2c4408fdbd62e02036c8e89d84edd71b3d36f087 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 16:37:38 +0530 Subject: [PATCH 18/60] feat(hubspot): create product action --- .../hubspot/src/lib/actions/create-product.ts | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-product.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-product.ts b/packages/pieces/community/hubspot/src/lib/actions/create-product.ts new file mode 100644 index 0000000000..08785384a5 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-product.ts @@ -0,0 +1,60 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + objectPropertiesDropdown, + propertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const createProductAction = createAction({ + auth: hubspotAuth, + name: 'create-product', + displayName: 'Create Product', + description: 'Creates a product in Hubspot.', + props: { + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.PRODUCT,[]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const productProperties: Record = {}; + + // Add additional properties to the productProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + productProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdProduct = await client.crm.products.basicApi.create({ + properties: productProperties, + }); + // Retrieve default properties for the product and merge with additional properties to retrieve + const defaultproductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); + + const productDetails = await client.crm.products.basicApi.getById(createdProduct.id, [ + ...defaultproductProperties, + ...additionalPropertiesToRetrieve, + ]); + + return productDetails; + }, +}); From 8457986025796a5ed35f140823e87d8f628f7511 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 16:37:53 +0530 Subject: [PATCH 19/60] feat(hubspot): update product action --- .../hubspot/src/lib/actions/update-product.ts | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/update-product.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-product.ts b/packages/pieces/community/hubspot/src/lib/actions/update-product.ts new file mode 100644 index 0000000000..4d0753c381 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/update-product.ts @@ -0,0 +1,66 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + objectPropertiesDropdown, + propertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const updateProductAction = createAction({ + auth: hubspotAuth, + name: 'update-product', + displayName: 'Update Product', + description: 'Updates a product in Hubspot.', + props: { + productId:Property.ShortText({ + displayName:'Product ID', + description:'The ID of the product to update.', + required:true + }), + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.PRODUCT,[]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const productId = context.propsValue.productId; + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const productProperties: Record = {}; + + // Add additional properties to the productProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + productProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedProduct = await client.crm.products.basicApi.update(productId, { + properties: productProperties, + }); + // Retrieve default properties for the product and merge with additional properties to retrieve + const defaultproductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); + + const productDetails = await client.crm.products.basicApi.getById(updatedProduct.id, [ + ...defaultproductProperties, + ...additionalPropertiesToRetrieve, + ]); + + return productDetails; + }, +}); From 0ce3f1e6c3791adcd6a9f0e50c72233972307661 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 16:38:07 +0530 Subject: [PATCH 20/60] feat(hubspot): find product action --- .../pieces/community/hubspot/src/index.ts | 6 ++ .../hubspot/src/lib/actions/find-product.ts | 93 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-product.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 61b1fa80ff..0791d0a8a8 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -27,6 +27,9 @@ import { createContactAction } from './lib/actions/create-contact'; import { updateContactAction } from './lib/actions/update-contact'; import { findContactAction } from './lib/actions/find-contact'; import { createOrUpdateContactAction } from './lib/actions/create-or-update-contact'; +import { createProductAction } from './lib/actions/create-product'; +import { updateProductAction } from './lib/actions/update-product'; +import { findProductAction } from './lib/actions/find-product'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -83,6 +86,9 @@ export const hubspot = createPiece({ findContactAction, createOrUpdateContactAction, findTicketAction, + createProductAction, + updateProductAction, + findProductAction, getProductAction, getPipelineStageDeatilsAction, addContactToWorkflowAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-product.ts b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts new file mode 100644 index 0000000000..1fca8a7c1f --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts @@ -0,0 +1,93 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +export const findProductAction = createAction({ + auth: hubspotAuth, + name: 'find-product', + displayName: 'Find Product', + description: 'Finds a product by searching.', + props: { + firstSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); + + const response = client.crm.products.searchApi.doSearch({ + limit: 100, + properties: [...defaultProductProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + + return response; + }, +}); From f103e8fd4d6b4240f239312c3e2d2211bff96ba3 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 17:32:14 +0530 Subject: [PATCH 21/60] feat(hubspot): create company action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/create-company.ts | 56 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-company.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 0791d0a8a8..221b66de3e 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -30,6 +30,7 @@ import { createOrUpdateContactAction } from './lib/actions/create-or-update-cont import { createProductAction } from './lib/actions/create-product'; import { updateProductAction } from './lib/actions/update-product'; import { findProductAction } from './lib/actions/find-product'; +import { createCompanyAction } from './lib/actions/create-company'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -79,6 +80,7 @@ export const hubspot = createPiece({ updateContactAction, getContactAction, getDealAction, + createCompanyAction, getCompanyAction, createTicketAction, updateTicketAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-company.ts b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts new file mode 100644 index 0000000000..e55e8c920a --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts @@ -0,0 +1,56 @@ +import { hubspotAuth } from '@activepieces/piece-hubspot'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { objectPropertiesDropdown, propertiesDropdown ,getDefaultPropertiesForObject} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const createCompanyAction = createAction({ + auth: hubspotAuth, + name: 'create-company', + displayName: 'Create Company', + description: 'Creates a company in Hubspot.', + props: { + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.COMPANY, []), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const companyProperties: Record = {}; + + // Add additional properties to the companyProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + companyProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdCompany = await client.crm.companies.basicApi.create({ + properties: companyProperties, + }); + // Retrieve default properties for the comapny and merge with additional properties to retrieve + const defaultcompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); + + const companyDetails = await client.crm.companies.basicApi.getById(createdCompany.id, [ + ...defaultcompanyProperties, + ...additionalPropertiesToRetrieve, + ]); + + return companyDetails; + }, +}); From 665ee5d7b895d9ddbf0d62eba56772c85e515c3d Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 17:32:58 +0530 Subject: [PATCH 22/60] feat(hubspot): find company action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/find-company.ts | 94 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-company.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 221b66de3e..09e191c97c 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -31,6 +31,7 @@ import { createProductAction } from './lib/actions/create-product'; import { updateProductAction } from './lib/actions/update-product'; import { findProductAction } from './lib/actions/find-product'; import { createCompanyAction } from './lib/actions/create-company'; +import { findCompanyAction } from './lib/actions/find-company'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -81,6 +82,7 @@ export const hubspot = createPiece({ getContactAction, getDealAction, createCompanyAction, + findCompanyAction, getCompanyAction, createTicketAction, updateTicketAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-company.ts b/packages/pieces/community/hubspot/src/lib/actions/find-company.ts new file mode 100644 index 0000000000..3e4f05417d --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-company.ts @@ -0,0 +1,94 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + propertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +export const findCompanyAction = createAction({ + auth: hubspotAuth, + name: 'find-company', + displayName: 'Find Company', + description: 'Finds a company by searching.', + props: { + firstSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.COMPANY, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); + + const response = await client.crm.companies.searchApi.doSearch({ + limit: 100, + properties: [...defaultCompanyProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + return response; + }, +}); From c577039282ea3edbaa6cf1e3686b9208bc40bfdd Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 17:33:53 +0530 Subject: [PATCH 23/60] feat(hubspot): update company action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/update-company.ts | 66 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/update-company.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 09e191c97c..7e801fbbe3 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -32,6 +32,7 @@ import { updateProductAction } from './lib/actions/update-product'; import { findProductAction } from './lib/actions/find-product'; import { createCompanyAction } from './lib/actions/create-company'; import { findCompanyAction } from './lib/actions/find-company'; +import { updateCompanyAction } from './lib/actions/update-company'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -82,6 +83,7 @@ export const hubspot = createPiece({ getContactAction, getDealAction, createCompanyAction, + updateCompanyAction, findCompanyAction, getCompanyAction, createTicketAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-company.ts b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts new file mode 100644 index 0000000000..e4f7886e40 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts @@ -0,0 +1,66 @@ +import { hubspotAuth } from '@activepieces/piece-hubspot'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + objectPropertiesDropdown, + propertiesDropdown, + getDefaultPropertiesForObject, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; + +export const updateCompanyAction = createAction({ + auth: hubspotAuth, + name: 'update-company', + displayName: 'Update Company', + description: 'Updates a company in Hubspot.', + props: { + companyId: Property.ShortText({ + displayName: 'Company ID', + description: 'The ID of the company to update.', + required: true, + }), + objectProperties: objectPropertiesDropdown(OBJECT_TYPE.COMPANY, []), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const companyId = context.propsValue.companyId; + const objectProperties = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const companyProperties: Record = {}; + + // Add additional properties to the companyProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + companyProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedCompany = await client.crm.companies.basicApi.update(companyId, { + properties: companyProperties, + }); + // Retrieve default properties for the comapny and merge with additional properties to retrieve + const defaultcompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); + + const companyDetails = await client.crm.companies.basicApi.getById(updatedCompany.id, [ + ...defaultcompanyProperties, + ...additionalPropertiesToRetrieve, + ]); + + return companyDetails; + }, +}); From 41bb5b050c9f21435948aa77a1c80d0a16cfd9f3 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 17:34:58 +0530 Subject: [PATCH 24/60] fix: fixes product function --- .../hubspot/src/lib/actions/find-product.ts | 146 +++++++++--------- .../community/hubspot/src/lib/common/props.ts | 6 +- 2 files changed, 77 insertions(+), 75 deletions(-) diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-product.ts b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts index 1fca8a7c1f..eb665152e9 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts @@ -7,87 +7,85 @@ import { Client } from '@hubspot/api-client'; import { FilterOperatorEnum } from '../common/types'; export const findProductAction = createAction({ - auth: hubspotAuth, - name: 'find-product', - displayName: 'Find Product', - description: 'Finds a product by searching.', - props: { - firstSearchPropertyName: propertiesDropdown( - { - objectType: OBJECT_TYPE.PRODUCT, - displayName: 'First search property name', - required: true, - }, - true, - true, - ), - firstSearchPropertyValue: Property.ShortText({ - displayName: 'First search property value', - required: true, - }), - secondSearchPropertyName: propertiesDropdown( - { - objectType: OBJECT_TYPE.PRODUCT, - displayName: 'Second search property name', - required: false, - }, - true, - true, - ), - secondSearchPropertyValue: Property.ShortText({ - displayName: 'Second search property value', - required: false, - }), - markdown: Property.MarkDown({ - variant: MarkdownVariant.INFO, - value: `### Properties to retrieve: + auth: hubspotAuth, + name: 'find-product', + displayName: 'Find Product', + description: 'Finds a product by searching.', + props: { + firstSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: propertiesDropdown( + { + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: createdate, description, name, price, tax, hs_lastmodifieddate **Specify here a list of additional properties to retrieve**`, - }), - additionalPropertiesToRetrieve: propertiesDropdown({ - objectType: OBJECT_TYPE.PRODUCT, - displayName: 'Additional properties to retrieve', - required: false, - }), - }, - async run(context) { - const { - firstSearchPropertyName, - firstSearchPropertyValue, - secondSearchPropertyName, - secondSearchPropertyValue, - } = context.propsValue; + }), + additionalPropertiesToRetrieve: propertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; - const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; - const filters = [ - { - propertyName: firstSearchPropertyName as string, - operator: FilterOperatorEnum.Eq, - value: firstSearchPropertyValue, - }, - ]; + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } - if (secondSearchPropertyName && secondSearchPropertyValue) { - filters.push({ - propertyName: secondSearchPropertyName as string, - operator: FilterOperatorEnum.Eq, - value: secondSearchPropertyValue, - }); - } + const client = new Client({ accessToken: context.auth.access_token }); - const client = new Client({ accessToken: context.auth.access_token }); + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); - const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); - - const response = client.crm.products.searchApi.doSearch({ - limit: 100, - properties: [...defaultProductProperties, ...additionalPropertiesToRetrieve], - filterGroups: [{ filters }], - }); - - return response; - }, + const response = await client.crm.products.searchApi.doSearch({ + limit: 100, + properties: [...defaultProductProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + return response; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index b4dbfdd87f..4d22aafff8 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -9,7 +9,7 @@ import { import { hubSpotClient } from './client'; import { hubspotApiCall, HubspotFieldType } from '.'; import { HttpMethod } from '@activepieces/pieces-common'; -import { WorkflowResponse, HubspotProperty } from './types'; +import { WorkflowResponse, HubspotProperty } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, @@ -267,6 +267,10 @@ export const objectPropertiesDropdown = (objectType: string, excludedProperties: required: false, props: async ({ auth }) => { if (!auth) return {}; + // Useful for Find actions + // if (typeof createIfNotExists === "boolean" && createIfNotExists === false) { + // return {}; + // } const props: DynamicPropsValue = {}; const authValue = auth as PiecePropValueSchema; From daf21e4e533b2a72d20b03c961e3e4a63c69b2bc Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 17:49:45 +0530 Subject: [PATCH 25/60] fix(hubspot): fix auth imports --- .../pieces/community/hubspot/src/lib/actions/create-company.ts | 2 +- .../pieces/community/hubspot/src/lib/actions/update-company.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-company.ts b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts index e55e8c920a..66babc0448 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts @@ -1,4 +1,4 @@ -import { hubspotAuth } from '@activepieces/piece-hubspot'; +import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { objectPropertiesDropdown, propertiesDropdown ,getDefaultPropertiesForObject} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-company.ts b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts index e4f7886e40..f53db3cb8b 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts @@ -1,4 +1,4 @@ -import { hubspotAuth } from '@activepieces/piece-hubspot'; +import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { objectPropertiesDropdown, From 39365f3a3ba79338764f3f8ce0ca6b966fc1b985 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 22:08:13 +0530 Subject: [PATCH 26/60] fix(hubspot): fix props definiation --- .../hubspot/src/lib/actions/create-company.ts | 6 +- .../hubspot/src/lib/actions/create-contact.ts | 13 +- .../lib/actions/create-or-update-contact.ts | 8 +- .../hubspot/src/lib/actions/create-product.ts | 8 +- .../hubspot/src/lib/actions/create-ticket.ts | 17 +- .../hubspot/src/lib/actions/find-company.ts | 8 +- .../hubspot/src/lib/actions/find-contact.ts | 12 +- .../src/lib/actions/find-custom-object.ts | 89 ++++++ .../hubspot/src/lib/actions/find-product.ts | 10 +- .../hubspot/src/lib/actions/find-ticket.ts | 12 +- .../hubspot/src/lib/actions/get-company.ts | 4 +- .../hubspot/src/lib/actions/get-contact.ts | 12 +- .../hubspot/src/lib/actions/get-deal.ts | 12 +- .../hubspot/src/lib/actions/get-product.ts | 12 +- .../hubspot/src/lib/actions/get-ticket.ts | 12 +- .../hubspot/src/lib/actions/update-company.ts | 9 +- .../hubspot/src/lib/actions/update-contact.ts | 9 +- .../hubspot/src/lib/actions/update-product.ts | 9 +- .../hubspot/src/lib/actions/update-ticket.ts | 17 +- .../community/hubspot/src/lib/common/props.ts | 261 ++++++++++++------ 20 files changed, 359 insertions(+), 181 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-company.ts b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts index 66babc0448..b8bef6dc27 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-company.ts @@ -1,6 +1,6 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { objectPropertiesDropdown, propertiesDropdown ,getDefaultPropertiesForObject} from '../common/props'; +import { getDefaultPropertiesForObject, standardObjectDynamicProperties, standardObjectPropertiesDropdown} from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { MarkdownVariant } from '@activepieces/shared'; import { Client } from '@hubspot/api-client'; @@ -11,7 +11,7 @@ export const createCompanyAction = createAction({ displayName: 'Create Company', description: 'Creates a company in Hubspot.', props: { - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.COMPANY, []), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.COMPANY, []), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -20,7 +20,7 @@ export const createCompanyAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.COMPANY, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts index 426d18ac0b..29367f4392 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-contact.ts @@ -1,13 +1,10 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { - getDefaultPropertiesForObject, - objectPropertiesDropdown, - propertiesDropdown, -} from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { MarkdownVariant } from '@activepieces/shared'; import { Client } from '@hubspot/api-client'; +import { getDefaultPropertiesForObject, standardObjectDynamicProperties, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const createContactAction = createAction({ auth: hubspotAuth, @@ -15,7 +12,7 @@ export const createContactAction = createAction({ displayName: 'Create Contact', description: 'Creates a contact in Hubspot.', props: { - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, []), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.CONTACT, []), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -24,7 +21,7 @@ export const createContactAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts index 7c5a4407ba..16bca38cef 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact.ts @@ -1,10 +1,12 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { objectPropertiesDropdown } from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { Client } from '@hubspot/api-client'; +import { standardObjectDynamicProperties } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; import { FilterOperatorEnum } from '../common/types'; + export const createOrUpdateContactAction = createAction({ auth: hubspotAuth, name: 'create-or-update-contact', @@ -15,7 +17,7 @@ export const createOrUpdateContactAction = createAction({ displayName: 'Contact Email', required: true, }), - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, ['email']), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.CONTACT, ['email']), }, async run(context) { const email = context.propsValue.email; diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-product.ts b/packages/pieces/community/hubspot/src/lib/actions/create-product.ts index 08785384a5..d081fc3552 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-product.ts @@ -2,8 +2,8 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, - objectPropertiesDropdown, - propertiesDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { MarkdownVariant } from '@activepieces/shared'; @@ -15,7 +15,7 @@ export const createProductAction = createAction({ displayName: 'Create Product', description: 'Creates a product in Hubspot.', props: { - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.PRODUCT,[]), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.PRODUCT,[]), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -24,7 +24,7 @@ export const createProductAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.PRODUCT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts index 14a20bdc1f..e465cebb00 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-ticket.ts @@ -1,15 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { Client } from '@hubspot/api-client'; -import { OBJECT_TYPE } from '../common/constants'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, - objectPropertiesDropdown, - pipelineDropdown, - pipelineStageDropdown, -} from '../common/props'; + import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, pipelineDropdown, pipelineStageDropdown, standardObjectDynamicProperties, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const createTicketAction = createAction({ auth: hubspotAuth, @@ -32,7 +27,7 @@ export const createTicketAction = createAction({ displayName: 'Ticket Pipeline Stage', required: true, }), - objectProperties : objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ + objectProperties : standardObjectDynamicProperties(OBJECT_TYPE.TICKET, [ 'subject', 'hs_pipeline', 'hs_pipeline_stage', @@ -45,7 +40,7 @@ export const createTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-company.ts b/packages/pieces/community/hubspot/src/lib/actions/find-company.ts index 3e4f05417d..795ba99cf6 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-company.ts @@ -3,7 +3,7 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, - propertiesDropdown, + standardObjectPropertiesDropdown, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { Client } from '@hubspot/api-client'; @@ -15,7 +15,7 @@ export const findCompanyAction = createAction({ displayName: 'Find Company', description: 'Finds a company by searching.', props: { - firstSearchPropertyName: propertiesDropdown( + firstSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.COMPANY, displayName: 'First search property name', @@ -28,7 +28,7 @@ export const findCompanyAction = createAction({ displayName: 'First search property value', required: true, }), - secondSearchPropertyName: propertiesDropdown( + secondSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.COMPANY, displayName: 'Second search property name', @@ -49,7 +49,7 @@ export const findCompanyAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.COMPANY, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts index 24bd02e4d0..a28769c399 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-contact.ts @@ -1,9 +1,9 @@ import { MarkdownVariant } from '@activepieces/shared'; -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; import { Client } from '@hubspot/api-client'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; import { FilterOperatorEnum } from '../common/types'; export const findContactAction = createAction({ @@ -12,7 +12,7 @@ export const findContactAction = createAction({ displayName: 'Find Contact', description: 'Finds a contact by searching.', props: { - firstSearchPropertyName: propertiesDropdown( + firstSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.CONTACT, displayName: 'First search property name', @@ -25,7 +25,7 @@ export const findContactAction = createAction({ displayName: 'First search property value', required: true, }), - secondSearchPropertyName: propertiesDropdown( + secondSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.CONTACT, displayName: 'Second search property name', @@ -46,7 +46,7 @@ export const findContactAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts new file mode 100644 index 0000000000..6c81916105 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts @@ -0,0 +1,89 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; +import { hubspotAuth } from '../../'; +import { customObjectDropdown, customObjectPropertiesDropdown } from '../common/props'; +import { FilterOperatorEnum } from '../common/types'; + +export const findCustomObjectAction = createAction({ + auth: hubspotAuth, + name: 'find-custom-object', + displayName: 'Find Custom Object', + description: 'Finds a custom object by searching.', + props: { + customObjectType: customObjectDropdown, + firstSearchPropertyName: customObjectPropertiesDropdown('First search property name', true,true), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: customObjectPropertiesDropdown('Second search property name', false,true), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_object_id, hs_lastmodifieddate, hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: customObjectPropertiesDropdown( + 'Additional Properties to Retrieve', + false, + ), + }, + async run(context) { + const customObjectType = context.propsValue.customObjectType as string; + const { + firstSearchPropertyValue, + secondSearchPropertyValue, + } = context.propsValue; + const firstSearchPropertyName = context.propsValue.firstSearchPropertyName?.['values'] as string; + const secondSearchPropertyName = context.propsValue.secondSearchPropertyName?.['values'] as string; + + let additionalPropertiesToRetrieve =context.propsValue.additionalPropertiesToRetrieve?.['values']; + + try { + if (Array.isArray(additionalPropertiesToRetrieve)) { + additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + } + if (typeof additionalPropertiesToRetrieve === 'string') { + additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + } + } catch (error) { + additionalPropertiesToRetrieve = []; + } + + const filters = [ + { + propertyName: firstSearchPropertyName as unknown as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as unknown as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + console.log(JSON.stringify(filters)); + console.log(JSON.stringify(additionalPropertiesToRetrieve)); + + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.crm.objects.searchApi.doSearch(customObjectType, { + limit: 100, + properties: additionalPropertiesToRetrieve, + filterGroups: [{ filters }], + }); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-product.ts b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts index eb665152e9..313aca0671 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-product.ts @@ -1,7 +1,9 @@ import { MarkdownVariant } from '@activepieces/shared'; import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown + + } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { Client } from '@hubspot/api-client'; import { FilterOperatorEnum } from '../common/types'; @@ -12,7 +14,7 @@ export const findProductAction = createAction({ displayName: 'Find Product', description: 'Finds a product by searching.', props: { - firstSearchPropertyName: propertiesDropdown( + firstSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.PRODUCT, displayName: 'First search property name', @@ -25,7 +27,7 @@ export const findProductAction = createAction({ displayName: 'First search property value', required: true, }), - secondSearchPropertyName: propertiesDropdown( + secondSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.PRODUCT, displayName: 'Second search property name', @@ -46,7 +48,7 @@ export const findProductAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.PRODUCT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts index f01c0b631f..d4bbddd78f 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-ticket.ts @@ -1,9 +1,9 @@ import { MarkdownVariant } from '@activepieces/shared'; -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { getDefaultPropertiesForObject, propertiesDropdown } from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; import { Client } from '@hubspot/api-client'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; import { FilterOperatorEnum } from '../common/types'; export const findTicketAction = createAction({ @@ -12,7 +12,7 @@ export const findTicketAction = createAction({ displayName: 'Find Ticket', description: 'Finds a ticket by searching.', props: { - firstSearchPropertyName: propertiesDropdown( + firstSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.TICKET, displayName: 'First search property name', @@ -25,7 +25,7 @@ export const findTicketAction = createAction({ displayName: 'First search property value', required: true, }), - secondSearchPropertyName: propertiesDropdown( + secondSearchPropertyName: standardObjectPropertiesDropdown( { objectType: OBJECT_TYPE.TICKET, displayName: 'Second search property name', @@ -46,7 +46,7 @@ export const findTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts index dfb8f54e17..0274948f79 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-company.ts @@ -1,8 +1,8 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - propertiesDropdown, getDefaultPropertiesForObject, + standardObjectPropertiesDropdown, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { Client } from '@hubspot/api-client'; @@ -27,7 +27,7 @@ export const getCompanyAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.COMPANY, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts index 531882eb94..c65918be30 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-contact.ts @@ -1,12 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, -} from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { Client } from '@hubspot/api-client'; import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const getContactAction = createAction({ auth: hubspotAuth, @@ -27,7 +25,7 @@ export const getContactAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts index 4137cb6c04..adc4b1a18e 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-deal.ts @@ -1,12 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, -} from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { Client } from '@hubspot/api-client'; import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const getDealAction = createAction({ auth: hubspotAuth, @@ -27,7 +25,7 @@ export const getDealAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.DEAL, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts index 4680d00bd7..3165917804 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-product.ts @@ -1,12 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, -} from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { Client } from '@hubspot/api-client'; import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const getProductAction = createAction({ auth: hubspotAuth, @@ -27,7 +25,7 @@ export const getProductAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.PRODUCT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts index f48c3397e2..2c891b1fd1 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-ticket.ts @@ -1,12 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, -} from '../common/props'; -import { OBJECT_TYPE } from '../common/constants'; + import { Client } from '@hubspot/api-client'; import { MarkdownVariant } from '@activepieces/shared'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { hubspotAuth } from '../../'; export const getTicketAction = createAction({ auth: hubspotAuth, @@ -27,7 +25,7 @@ export const getTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-company.ts b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts index f53db3cb8b..d06411d80e 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-company.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-company.ts @@ -1,9 +1,10 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { - objectPropertiesDropdown, - propertiesDropdown, + getDefaultPropertiesForObject, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { MarkdownVariant } from '@activepieces/shared'; @@ -20,7 +21,7 @@ export const updateCompanyAction = createAction({ description: 'The ID of the company to update.', required: true, }), - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.COMPANY, []), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.COMPANY, []), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -29,7 +30,7 @@ export const updateCompanyAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.COMPANY, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts b/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts index 98cb5bfd6e..75d1288c03 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-contact.ts @@ -2,8 +2,9 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, - objectPropertiesDropdown, - propertiesDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, + } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { MarkdownVariant } from '@activepieces/shared'; @@ -20,7 +21,7 @@ export const updateContactAction = createAction({ description: 'The ID of the contact to update.', required: true, }), - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.CONTACT, []), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.CONTACT, []), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -29,7 +30,7 @@ export const updateContactAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-product.ts b/packages/pieces/community/hubspot/src/lib/actions/update-product.ts index 4d0753c381..0f94bb7d5c 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-product.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-product.ts @@ -2,8 +2,9 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, - objectPropertiesDropdown, - propertiesDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, + } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { MarkdownVariant } from '@activepieces/shared'; @@ -20,7 +21,7 @@ export const updateProductAction = createAction({ description:'The ID of the product to update.', required:true }), - objectProperties: objectPropertiesDropdown(OBJECT_TYPE.PRODUCT,[]), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.PRODUCT,[]), markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, value: `### Properties to retrieve: @@ -29,7 +30,7 @@ export const updateProductAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.PRODUCT, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts index 3d748372c1..1e3be6eff8 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts @@ -1,15 +1,10 @@ -import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; import { Client } from '@hubspot/api-client'; -import { OBJECT_TYPE } from '../common/constants'; -import { - propertiesDropdown, - getDefaultPropertiesForObject, - objectPropertiesDropdown, - pipelineDropdown, - pipelineStageDropdown, -} from '../common/props'; + import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, pipelineDropdown, pipelineStageDropdown, standardObjectDynamicProperties, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; export const updateTicketAction = createAction({ auth: hubspotAuth, @@ -37,7 +32,7 @@ export const updateTicketAction = createAction({ displayName: 'Ticket Pipeline Stage', required: false, }), - objectProperites: objectPropertiesDropdown(OBJECT_TYPE.TICKET, [ + objectProperites: standardObjectDynamicProperties(OBJECT_TYPE.TICKET, [ 'subject', 'hs_pipeline', 'hs_pipeline_stage', @@ -50,7 +45,7 @@ export const updateTicketAction = createAction({ **Specify here a list of additional properties to retrieve**`, }), - additionalPropertiesToRetrieve: propertiesDropdown({ + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.TICKET, displayName: 'Additional properties to retrieve', required: false, diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 4d22aafff8..444d068080 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -2,6 +2,7 @@ import { DropdownOption, DynamicPropsValue, OAuth2PropertyValue, + Piece, PieceAuth, PiecePropValueSchema, Property, @@ -260,7 +261,91 @@ function createPropertyDefinition(property: HubspotProperty, propertyDisplayName } } -export const objectPropertiesDropdown = (objectType: string, excludedProperties: string[]) => +async function retriveObjectProperties( + auth: PiecePropValueSchema, + objectType: string, + excludedProperties: string[] = [], +) { + const client = new Client({ accessToken: auth.access_token }); + + // Fetch property groups + const propertyGroups = await client.crm.properties.groupsApi.getAll(objectType); + const groupLabels = propertyGroups.results.reduce((map, group) => { + map[group.name] = group.label; + return map; + }, {} as Record); + + // Fetch all properties for the given object type + const allProperties = await client.crm.properties.coreApi.getAll(objectType); + + const props: DynamicPropsValue = {}; + + for (const property of allProperties.results) { + // skip read only properties + if ( + excludedProperties.includes(property.name) || + property.modificationMetadata?.readOnlyValue || + property.hidden + ) { + continue; + } + + // create property name with property group name + const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; + + if (property.referencedObjectType) { + props[property.name] = await createReferencedPropertyDefinition( + property, + propertyDisplayName, + auth.access_token, + ); + continue; + } + if (property.name === 'hs_shared_user_ids') { + const userOptions = await fetchUsersOptions(auth.access_token); + props[property.name] = Property.StaticMultiSelectDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: userOptions, + }, + }); + continue; + } + if (property.name === 'hs_shared_team_ids') { + const teamOptions = await fetchTeamsOptions(auth.access_token); + props[property.name] = Property.StaticMultiSelectDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: teamOptions, + }, + }); + continue; + } + if (property.name === 'hs_all_assigned_business_unit_ids') { + // TO DO : Add business unit options + // const businessUnitOptions = await fetchBusinessUnitsOptions(authValue.access_token); + // props[property.name] = Property.StaticMultiSelectDropdown({ + // displayName: propertyDisplayName, + // required: false, + // options: { + // disabled: false, + // options: businessUnitOptions, + // }, + // }); + continue; + } + + props[property.name] = createPropertyDefinition(property, propertyDisplayName); + } + // Remove null props + return Object.fromEntries(Object.entries(props).filter(([_, prop]) => prop !== null)); +} + +export const standardObjectDynamicProperties = (objectType: string, excludedProperties: string[]) => Property.DynamicProperties({ displayName: 'Object Properties', refreshers: [], @@ -271,87 +356,25 @@ export const objectPropertiesDropdown = (objectType: string, excludedProperties: // if (typeof createIfNotExists === "boolean" && createIfNotExists === false) { // return {}; // } - - const props: DynamicPropsValue = {}; const authValue = auth as PiecePropValueSchema; - const client = new Client({ accessToken: authValue.access_token }); - - const propertyGroups = await client.crm.properties.groupsApi.getAll(objectType); - - const groupLabels = propertyGroups.results.reduce((map, group) => { - map[group.name] = group.label; - return map; - }, {} as Record); - - const allProperties = await client.crm.properties.coreApi.getAll(objectType); - - for (const property of allProperties.results) { - // skip read only properties - if ( - excludedProperties.includes(property.name) || - property.modificationMetadata?.readOnlyValue || - property.hidden - ) { - continue; - } - - // create property name with property group name - const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; - - if (property.referencedObjectType) { - props[property.name] = await createReferencedPropertyDefinition( - property, - propertyDisplayName, - authValue.access_token, - ); - continue; - } - if (property.name === 'hs_shared_user_ids') { - const userOptions = await fetchUsersOptions(authValue.access_token); - props[property.name] = Property.StaticMultiSelectDropdown({ - displayName: propertyDisplayName, - required: false, - options: { - disabled: false, - options: userOptions, - }, - }); - continue; - } - if (property.name === 'hs_shared_team_ids') { - const teamOptions = await fetchTeamsOptions(authValue.access_token); - props[property.name] = Property.StaticMultiSelectDropdown({ - displayName: propertyDisplayName, - required: false, - options: { - disabled: false, - options: teamOptions, - }, - }); - continue; - } - if (property.name === 'hs_all_assigned_business_unit_ids') { - // TO DO : Add business unit options - // const businessUnitOptions = await fetchBusinessUnitsOptions(authValue.access_token); - // props[property.name] = Property.StaticMultiSelectDropdown({ - // displayName: propertyDisplayName, - // required: false, - // options: { - // disabled: false, - // options: businessUnitOptions, - // }, - // }); - continue; - } - - props[property.name] = createPropertyDefinition(property, propertyDisplayName); - } - // Remove null props - return Object.fromEntries(Object.entries(props).filter(([_, prop]) => prop !== null)); + return await retriveObjectProperties(authValue, objectType, excludedProperties); }, }); -export const propertiesDropdown = ( +export const customObjectDynamicProperties = Property.DynamicProperties({ + displayName: 'Custom Object Properties', + refreshers: ['customObjectType'], + required: false, + props: async ({ auth, customObjectType }) => { + if (!auth || !customObjectType) { + return {}; + } + const authValue = auth as PiecePropValueSchema; + return await retriveObjectProperties(authValue, customObjectType as unknown as string); + }, +}); + +export const standardObjectPropertiesDropdown = ( params: DropdownParams, includeDefaultProperties = false, isSingleSelect = false, @@ -406,6 +429,58 @@ export const propertiesDropdown = ( }); }; +export const customObjectPropertiesDropdown = (displayName: string, required: boolean, isSingleSelect = false, +) => + Property.DynamicProperties({ + displayName, + refreshers: ['customObjectType'], + required, + props: async ({ auth, customObjectType }) => { + if (!auth || !customObjectType) { + return {}; + } + const authValue = auth as PiecePropValueSchema; + + const client = new Client({ accessToken: authValue.access_token }); + + // Fetch all properties for the given object type + const allProperties = await client.crm.properties.coreApi.getAll( + customObjectType as unknown as string, + ); + + const propertyGroups = await client.crm.properties.groupsApi.getAll( + customObjectType as unknown as string, + ); + + const groupLabels = propertyGroups.results.reduce((map, group) => { + map[group.name] = group.label; + return map; + }, {} as Record); + + const options: DropdownOption[] = []; + for (const property of allProperties.results) { + const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; + options.push({ + label: propertyDisplayName, + value: property.name, + }); + } + + const props: DynamicPropsValue = {}; + const dropdownFunction = isSingleSelect ? Property.StaticDropdown : Property.StaticMultiSelectDropdown; + + props['values'] = dropdownFunction({ + displayName, + required, + options: { + disabled: false, + options, + }, + }); + return props; + }, + }); + export const workflowIdDropdown = Property.Dropdown({ displayName: 'Workflow', refreshers: [], @@ -508,10 +583,38 @@ export const pipelineStageDropdown = (params: DropdownParams) => }; }, }); +export const customObjectDropdown = Property.Dropdown({ + displayName: 'Type of Custom Object', + refreshers: [], + required: true, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const customObjectsResponse = await client.crm.schemas.coreApi.getAll(); + + const options = customObjectsResponse.results.map((customObj) => { + return { + label: customObj.labels.plural ?? customObj.name, + value: customObj.objectTypeId, + }; + }); + + return { + disabled: false, + options, + }; + }, +}); type DropdownParams = { objectType: OBJECT_TYPE; displayName: string; required: boolean; description?: string; -}; +}; \ No newline at end of file From 15e46b5a6f86d749c749b97f31c0fe8971de6235 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 22:08:27 +0530 Subject: [PATCH 27/60] feat(hubspot): create custom object action --- .../src/lib/actions/create-custom-object.ts | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts new file mode 100644 index 0000000000..41ae86f197 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts @@ -0,0 +1,73 @@ +import { hubspotAuth } from '../..'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { + customObjectDropdown, + customObjectDynamicProperties, + customObjectPropertiesDropdown, +} from '../common/props'; + +import { Client } from '@hubspot/api-client'; + +export const createCustomObjectAction = createAction({ + auth: hubspotAuth, + name: 'create-custome-object', + displayName: 'Create Custom Object', + description: 'Creates a custom object in Hubspot.', + props: { + customObjectType: customObjectDropdown, + objectProperties: customObjectDynamicProperties, + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_object_id, hs_lastmodifieddate, hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: customObjectPropertiesDropdown( + 'Additional Properties to Retrieve', + false, + ), + }, + async run(context) { + const customObjectType = context.propsValue.customObjectType as string; + const objectProperties = context.propsValue.objectProperties ?? {}; + let additionalPropertiesToRetrieve = + context.propsValue.additionalPropertiesToRetrieve?.['values']; + + try { + if (Array.isArray(additionalPropertiesToRetrieve)) { + additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + } + if (typeof additionalPropertiesToRetrieve === 'string') { + additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + } + } catch (error) { + additionalPropertiesToRetrieve = []; + } + + const customObjectProperties: Record = {}; + + // Add additional properties to the customObjectProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + customObjectProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdCustomObject = await client.crm.objects.basicApi.create(customObjectType, { + properties: customObjectProperties, + associations: [], + }); + + const customObjectDetails = await client.crm.objects.basicApi.getById( + customObjectType, + createdCustomObject.id, + additionalPropertiesToRetrieve, + ); + + return customObjectDetails; + }, +}); From b03f140db64cea5e66a9c6065690cee25ea9d574 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 22:08:45 +0530 Subject: [PATCH 28/60] feat(hubspot): get custom object action --- .../src/lib/actions/get-custom-object.ts | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts new file mode 100644 index 0000000000..e8b2e66987 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts @@ -0,0 +1,57 @@ +import { createAction, Property } from '@activepieces/pieces-framework'; + +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { customObjectDropdown, customObjectPropertiesDropdown } from '../common/props'; + +export const getCustomObjectAction = createAction({ + auth: hubspotAuth, + name: 'get-custom-object', + displayName: 'Get Custom Object', + description: 'Gets a custom object.', + props: { + customObjectType: customObjectDropdown, + customObjectId: Property.ShortText({ + displayName: 'Custom Object ID', + description: 'The ID of the custom object to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_object_id, hs_lastmodifieddate, hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: customObjectPropertiesDropdown('Additional Properties to Retrieve', false), + }, + async run(context) { + const customObjectType = context.propsValue.customObjectType as string; + const customObjectId = context.propsValue.customObjectId as string; + let additionalPropertiesToRetrieve = + context.propsValue.additionalPropertiesToRetrieve?.['values']; + + try { + if (Array.isArray(additionalPropertiesToRetrieve)) { + additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + } + if (typeof additionalPropertiesToRetrieve === 'string') { + additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + } + } catch (error) { + additionalPropertiesToRetrieve = []; + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const customObjectDetails = await client.crm.objects.basicApi.getById( + customObjectType, + customObjectId, + additionalPropertiesToRetrieve, + ); + + return customObjectDetails; + }, +}); From 888420e38a2cbcccabfa33fbb7ab1d14f7add665 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 22:09:07 +0530 Subject: [PATCH 29/60] feat(hubspot): update custom object action --- .../src/lib/actions/updated-custom-object.ts | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts diff --git a/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts new file mode 100644 index 0000000000..f701743737 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts @@ -0,0 +1,78 @@ +import { hubspotAuth } from '../..'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { + customObjectDropdown, + customObjectDynamicProperties, + customObjectPropertiesDropdown, +} from '../common/props'; + +import { Client } from '@hubspot/api-client'; + +export const updateCustomObjectAction = createAction({ + auth: hubspotAuth, + name: 'update-custome-object', + displayName: 'Update Custom Object', + description: 'Updates a custom object in Hubspot.', + props: { + customObjectType: customObjectDropdown, + customObjectId: Property.ShortText({ + displayName: 'Custom Object ID', + description: 'The ID of the custom object to update.', + required: true, + }), + objectProperties: customObjectDynamicProperties, + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_object_id, hs_lastmodifieddate, hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: customObjectPropertiesDropdown('Additional Properties to Retrieve', false), + }, + async run(context) { + const customObjectType = context.propsValue.customObjectType as string; + const customObjectId = context.propsValue.customObjectId as string; + const objectProperties = context.propsValue.objectProperties ?? {}; + let additionalPropertiesToRetrieve = + context.propsValue.additionalPropertiesToRetrieve?.['values']; + try { + if (Array.isArray(additionalPropertiesToRetrieve)) { + additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + } + if (typeof additionalPropertiesToRetrieve === 'string') { + additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + } + } catch (error) { + additionalPropertiesToRetrieve = []; + } + + const customObjectProperties: Record = {}; + + // Add additional properties to the customObjectProperties object + Object.entries(objectProperties).forEach(([key, value]) => { + // Format values if they are arrays + customObjectProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedCustomObject = await client.crm.objects.basicApi.update( + customObjectType, + customObjectId, + { + properties: customObjectProperties, + }, + ); + + const customObjectDetails = await client.crm.objects.basicApi.getById( + customObjectType, + updatedCustomObject.id, + additionalPropertiesToRetrieve, + ); + + return customObjectDetails; + }, +}); From 0274ba73a28658163acd56a193979cbb14356f40 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 22:09:42 +0530 Subject: [PATCH 30/60] feat: find custom object action --- .../pieces/community/hubspot/src/index.ts | 8 +++++ .../src/lib/actions/find-custom-object.ts | 33 +++++++++++-------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 7e801fbbe3..7af4f7ac6d 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -33,6 +33,10 @@ import { findProductAction } from './lib/actions/find-product'; import { createCompanyAction } from './lib/actions/create-company'; import { findCompanyAction } from './lib/actions/find-company'; import { updateCompanyAction } from './lib/actions/update-company'; +import { createCustomObjectAction } from './lib/actions/create-custom-object'; +import { updateCustomObjectAction } from './lib/actions/updated-custom-object'; +import { getCustomObjectAction } from './lib/actions/get-custom-object'; +import { findCustomObjectAction } from './lib/actions/find-custom-object'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -96,6 +100,10 @@ export const hubspot = createPiece({ updateProductAction, findProductAction, getProductAction, + createCustomObjectAction, + updateCustomObjectAction, + getCustomObjectAction, + findCustomObjectAction, getPipelineStageDeatilsAction, addContactToWorkflowAction, createDealAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts index 6c81916105..27af3a8d61 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts @@ -2,7 +2,7 @@ import { MarkdownVariant } from '@activepieces/shared'; import { createAction, Property } from '@activepieces/pieces-framework'; import { Client } from '@hubspot/api-client'; import { hubspotAuth } from '../../'; -import { customObjectDropdown, customObjectPropertiesDropdown } from '../common/props'; +import { customObjectDropdown, customObjectPropertiesDropdown } from '../common/props'; import { FilterOperatorEnum } from '../common/types'; export const findCustomObjectAction = createAction({ @@ -12,12 +12,20 @@ export const findCustomObjectAction = createAction({ description: 'Finds a custom object by searching.', props: { customObjectType: customObjectDropdown, - firstSearchPropertyName: customObjectPropertiesDropdown('First search property name', true,true), + firstSearchPropertyName: customObjectPropertiesDropdown( + 'First search property name', + true, + true, + ), firstSearchPropertyValue: Property.ShortText({ displayName: 'First search property value', required: true, }), - secondSearchPropertyName: customObjectPropertiesDropdown('Second search property name', false,true), + secondSearchPropertyName: customObjectPropertiesDropdown( + 'Second search property name', + false, + true, + ), secondSearchPropertyValue: Property.ShortText({ displayName: 'Second search property value', required: false, @@ -37,14 +45,16 @@ export const findCustomObjectAction = createAction({ }, async run(context) { const customObjectType = context.propsValue.customObjectType as string; - const { - firstSearchPropertyValue, - secondSearchPropertyValue, - } = context.propsValue; - const firstSearchPropertyName = context.propsValue.firstSearchPropertyName?.['values'] as string; - const secondSearchPropertyName = context.propsValue.secondSearchPropertyName?.['values'] as string; + const { firstSearchPropertyValue, secondSearchPropertyValue } = context.propsValue; + const firstSearchPropertyName = context.propsValue.firstSearchPropertyName?.[ + 'values' + ] as string; + const secondSearchPropertyName = context.propsValue.secondSearchPropertyName?.[ + 'values' + ] as string; - let additionalPropertiesToRetrieve =context.propsValue.additionalPropertiesToRetrieve?.['values']; + let additionalPropertiesToRetrieve = + context.propsValue.additionalPropertiesToRetrieve?.['values']; try { if (Array.isArray(additionalPropertiesToRetrieve)) { @@ -73,9 +83,6 @@ export const findCustomObjectAction = createAction({ }); } - console.log(JSON.stringify(filters)); - console.log(JSON.stringify(additionalPropertiesToRetrieve)); - const client = new Client({ accessToken: context.auth.access_token }); const response = await client.crm.objects.searchApi.doSearch(customObjectType, { From acf11309b31df9c1b3a4cda8e41635189ac91ffa Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 23:02:25 +0530 Subject: [PATCH 31/60] chore: remove duplicate actions --- .../pieces/community/hubspot/src/index.ts | 46 +++++----- .../lib/actions/add-contact-to-workflow.ts | 12 +-- .../src/lib/actions/create-contact.action.ts | 88 ------------------- .../create-or-update-contact-action.ts | 51 ----------- .../src/lib/actions/get-owner-by-email.ts | 23 +++++ .../src/lib/actions/get-owner-by-id.ts | 23 +++++ .../lib/actions/get-pipeline-stage-details.ts | 17 ++-- .../src/lib/actions/search-owner-by-email.ts | 23 ----- .../community/hubspot/src/lib/common/index.ts | 42 --------- .../community/hubspot/src/lib/common/props.ts | 27 +++--- 10 files changed, 101 insertions(+), 251 deletions(-) delete mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-contact.action.ts delete mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact-action.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-owner-by-email.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-owner-by-id.ts delete mode 100644 packages/pieces/community/hubspot/src/lib/actions/search-owner-by-email.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 7af4f7ac6d..b56bfadefe 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -2,9 +2,6 @@ import { createCustomApiCallAction } from '@activepieces/pieces-common'; import { OAuth2PropertyValue, PieceAuth, createPiece } from '@activepieces/pieces-framework'; import { PieceCategory } from '@activepieces/shared'; import { hubSpotListsAddContactAction } from './lib/actions/add-contact-to-list-action'; -import { createHubspotContact } from './lib/actions/create-contact.action'; -import { hubSpotContactsCreateOrUpdateAction } from './lib/actions/create-or-update-contact-action'; -import { hubSpotGetOwnerByEmailAction } from './lib/actions/search-owner-by-email'; import { newCompanyAdded } from './lib/triggers/new-company-added'; import { newContactAdded } from './lib/triggers/new-contact-added'; import { newDealAdded } from './lib/triggers/new-deal-added'; @@ -37,6 +34,8 @@ import { createCustomObjectAction } from './lib/actions/create-custom-object'; import { updateCustomObjectAction } from './lib/actions/updated-custom-object'; import { getCustomObjectAction } from './lib/actions/get-custom-object'; import { findCustomObjectAction } from './lib/actions/find-custom-object'; +import { getOwnerByEmailAction } from './lib/actions/get-owner-by-email'; +import { getOwnerByIdAction } from './lib/actions/get-owner-by-id'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -78,36 +77,35 @@ export const hubspot = createPiece({ categories: [PieceCategory.SALES_AND_CRM], auth: hubspotAuth, actions: [ - createHubspotContact, - hubSpotContactsCreateOrUpdateAction, hubSpotListsAddContactAction, - hubSpotGetOwnerByEmailAction, + addContactToWorkflowAction, + createCompanyAction, createContactAction, - updateContactAction, + createCustomObjectAction, + createDealAction, + createOrUpdateContactAction, + createProductAction, + createTicketAction, + getCompanyAction, getContactAction, + getCustomObjectAction, getDealAction, - createCompanyAction, + getProductAction, + getTicketAction, updateCompanyAction, - findCompanyAction, - getCompanyAction, - createTicketAction, + updateContactAction, + updateCustomObjectAction, + updateDealAction, + updateProductAction, updateTicketAction, - getTicketAction, + findCompanyAction, findContactAction, - createOrUpdateContactAction, - findTicketAction, - createProductAction, - updateProductAction, - findProductAction, - getProductAction, - createCustomObjectAction, - updateCustomObjectAction, - getCustomObjectAction, findCustomObjectAction, + findProductAction, + findTicketAction, + getOwnerByEmailAction, + getOwnerByIdAction, getPipelineStageDeatilsAction, - addContactToWorkflowAction, - createDealAction, - updateDealAction, createCustomApiCallAction({ baseUrl: () => 'https://api.hubapi.com', auth: hubspotAuth, diff --git a/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts index b76f74b260..c28ff74a6a 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-workflow.ts @@ -1,8 +1,7 @@ import { hubspotAuth } from "../../"; import { createAction, Property } from "@activepieces/pieces-framework"; import { workflowIdDropdown } from "../common/props"; -import { hubspotApiCall } from "../common"; -import { HttpMethod } from "@activepieces/pieces-common"; +import { AuthenticationType, httpClient, HttpMethod } from "@activepieces/pieces-common"; export const addContactToWorkflowAction = createAction({ auth:hubspotAuth, @@ -21,10 +20,13 @@ export const addContactToWorkflowAction = createAction({ const contactEmail = context.propsValue.email; const workflowId = context.propsValue.workflowId; - const response = await hubspotApiCall({ - accessToken: context.auth.access_token, + const response = await httpClient.sendRequest({ method: HttpMethod.POST, - resourceUri:`/automation/v2/workflows/${workflowId}/enrollments/contacts/${contactEmail}`, + url: `https://api.hubapi.com/automation/v2/workflows/${workflowId}/enrollments/contacts/${contactEmail}`, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: context.auth.access_token, + }, }) return response; diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-contact.action.ts b/packages/pieces/community/hubspot/src/lib/actions/create-contact.action.ts deleted file mode 100644 index c29174b12a..0000000000 --- a/packages/pieces/community/hubspot/src/lib/actions/create-contact.action.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { createAction, Property } from '@activepieces/pieces-framework'; -import { - AuthenticationType, - httpClient, - HttpMethod, - HttpRequest, -} from '@activepieces/pieces-common'; -import { hubspotAuth } from '../../'; -import { hubspotCommon } from '../common'; - -export const createHubspotContact = createAction({ - auth: hubspotAuth, - name: 'create_contact', - displayName: 'Create Contact', - description: 'Fails on duplicate email addresses', - props: { - firstName: Property.ShortText({ - displayName: 'First Name', - description: 'First name of the new contact', - required: true, - }), - lastName: Property.ShortText({ - displayName: 'Last Name', - description: 'Last name of the new contact', - required: true, - }), - zip: Property.ShortText({ - displayName: 'Zip Code', - description: 'Zip code of the new contact', - required: false, - }), - email: Property.ShortText({ - displayName: 'Email', - description: 'Email of the new contact', - required: false, - }), - choose_props: hubspotCommon.choose_props, - dynamicProperties: hubspotCommon.dynamicProperties, - }, - async run(context) { - const dynamicProperties = context.propsValue.dynamicProperties as Record< - string, - any - >; - - const configsWithoutAuthentication: Record = { - firstName: context.propsValue.firstName, - lastName: context.propsValue.lastName, - }; - if (context.propsValue.zip) { - configsWithoutAuthentication['zip'] = context.propsValue.zip; - } - if (context.propsValue.email) { - configsWithoutAuthentication['email'] = context.propsValue.email; - } - Object.entries(dynamicProperties).forEach((f) => { - configsWithoutAuthentication[f[0]] = f[1]; - }); - - const body = { - properties: Object.entries(configsWithoutAuthentication).map((f) => { - return { - property: f[0] as string, - value: f[1], - }; - }), - }; - const request: HttpRequest<{ - properties: { property: string; value: any }[]; - }> = { - method: HttpMethod.POST, - url: 'https://api.hubapi.com/contacts/v1/contact/', - body: body, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: context.auth.access_token, - }, - queryParams: {}, - }; - const result = await httpClient.sendRequest(request); - - return { - success: true, - request_body: body, - response_body: result.body, - }; - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact-action.ts b/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact-action.ts deleted file mode 100644 index 52f6590e59..0000000000 --- a/packages/pieces/community/hubspot/src/lib/actions/create-or-update-contact-action.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { hubSpotClient } from '../common/client'; -import { createAction, Property } from '@activepieces/pieces-framework'; -import { assertNotNullOrUndefined } from '@activepieces/shared'; -import { hubspotAuth } from '../../'; - -export const hubSpotContactsCreateOrUpdateAction = createAction({ - auth: hubspotAuth, - name: 'create_or_update_contact', - displayName: 'Create or Update Contact', - description: 'Updates contact if email address already exists', - props: { - email: Property.ShortText({ - displayName: 'Email', - description: 'Contact email', - required: true, - }), - firstName: Property.ShortText({ - displayName: 'First Name', - description: 'contact first name', - required: false, - }), - lastName: Property.ShortText({ - displayName: 'Last Name', - description: 'contact last name', - required: false, - }), - zip: Property.ShortText({ - displayName: 'Zip Code', - description: 'contact zip code', - required: false, - }), - }, - - async run(context) { - const token = context.auth.access_token; - const { email, firstName, lastName, zip } = context.propsValue; - - assertNotNullOrUndefined(token, 'token'); - assertNotNullOrUndefined(email, 'email'); - - return await hubSpotClient.contacts.createOrUpdate({ - token, - email, - contact: { - firstname: firstName, - lastname: lastName, - zip, - }, - }); - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-email.ts b/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-email.ts new file mode 100644 index 0000000000..c34b2df0c0 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-email.ts @@ -0,0 +1,23 @@ +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotAuth } from '../..'; +import { Client } from '@hubspot/api-client'; + +export const getOwnerByEmailAction = createAction({ + auth: hubspotAuth, + name: 'get-owner-by-email', + displayName: 'Get Owner by Email', + description: 'Gets an existing owner by email.', + props: { + email: Property.ShortText({ + displayName: 'Owner Email', + required: true, + }), + }, + async run(context) { + const { email } = context.propsValue; + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.crm.owners.ownersApi.getPage(email); + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-id.ts b/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-id.ts new file mode 100644 index 0000000000..9be64f0bc6 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-owner-by-id.ts @@ -0,0 +1,23 @@ +import { createAction, Property } from '@activepieces/pieces-framework'; +import { hubspotAuth } from '../..'; +import { Client } from '@hubspot/api-client'; + +export const getOwnerByIdAction = createAction({ + auth: hubspotAuth, + name: 'get-owner-by-id', + displayName: 'Get Owner by ID', + description: 'Gets an existing owner by ID.', + props: { + ownerId: Property.ShortText({ + displayName: 'Owner ID', + required: true, + }), + }, + async run(context) { + const { ownerId } = context.propsValue; + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.crm.owners.ownersApi.getById(Number(ownerId)); + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts b/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts index df5a640a77..890d1417f7 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-pipeline-stage-details.ts @@ -1,7 +1,6 @@ import { hubspotAuth } from '../../'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotApiCall } from '../common'; -import { HttpMethod } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; export const getPipelineStageDeatilsAction = createAction({ auth: hubspotAuth, @@ -40,12 +39,14 @@ export const getPipelineStageDeatilsAction = createAction({ const pipelineId = context.propsValue.pipelineId; const stageId = context.propsValue.stageId; - const stageResponse = await hubspotApiCall({ - accessToken: context.auth.access_token, - method: HttpMethod.GET, - resourceUri: `/crm/v3/pipelines/${objectType}/${pipelineId}/stages/${stageId}`, - }); + const client = new Client({ accessToken: context.auth.access_token }); - return stageResponse; + const response = await client.crm.pipelines.pipelineStagesApi.getById( + objectType, + pipelineId, + stageId, + ); + + return response; }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/search-owner-by-email.ts b/packages/pieces/community/hubspot/src/lib/actions/search-owner-by-email.ts deleted file mode 100644 index c5249e0b85..0000000000 --- a/packages/pieces/community/hubspot/src/lib/actions/search-owner-by-email.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { createAction, Property } from '@activepieces/pieces-framework'; -import { hubspotAuth } from '../../'; -import { hubSpotClient } from '../common/client'; - -export const hubSpotGetOwnerByEmailAction = createAction({ - auth: hubspotAuth, - name: 'get_owner_by_email', - displayName: 'Get Owner by Email', - description: 'Retrieves an existing owner by email.', - props: { - email: Property.ShortText({ - displayName: 'Owner Email', - required: true, - }), - }, - async run(context) { - const { email } = context.propsValue; - return await hubSpotClient.listContactOwners( - context.auth.access_token as string, - email as string - ); - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/common/index.ts b/packages/pieces/community/hubspot/src/lib/common/index.ts index f9b979c8bf..6148913069 100644 --- a/packages/pieces/community/hubspot/src/lib/common/index.ts +++ b/packages/pieces/community/hubspot/src/lib/common/index.ts @@ -1,9 +1,7 @@ import { AuthenticationType, - HttpMessageBody, HttpMethod, HttpRequest, - QueryParams, httpClient, } from '@activepieces/pieces-common'; import { @@ -223,43 +221,3 @@ export const hubspotCommon = { }), }; -export type RequestParams = Record; - -export type HubspotApiCallParams = { - accessToken: string; - method: HttpMethod; - resourceUri: string; - query?: RequestParams; - body?: any; -}; - -export async function hubspotApiCall({ - accessToken, - method, - resourceUri, - query, - body, -}: HubspotApiCallParams): Promise { - const baseUrl = 'https://api.hubapi.com'; - const qs: QueryParams = {}; - - if (query) { - for (const [key, value] of Object.entries(query)) { - if (value !== null && value !== undefined) { - qs[key] = String(value); - } - } - } - const request: HttpRequest = { - method, - url: baseUrl + resourceUri, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - queryParams: qs, - body, - }; - const response = await httpClient.sendRequest(request); - return response.body; -} diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 444d068080..b9872ea927 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -8,8 +8,8 @@ import { Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; -import { hubspotApiCall, HubspotFieldType } from '.'; -import { HttpMethod } from '@activepieces/pieces-common'; +import { HubspotFieldType } from '.'; +import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; import { WorkflowResponse, HubspotProperty } from './types'; import { DEFAULT_COMPANY_PROPERTIES, @@ -429,7 +429,10 @@ export const standardObjectPropertiesDropdown = ( }); }; -export const customObjectPropertiesDropdown = (displayName: string, required: boolean, isSingleSelect = false, +export const customObjectPropertiesDropdown = ( + displayName: string, + required: boolean, + isSingleSelect = false, ) => Property.DynamicProperties({ displayName, @@ -467,7 +470,9 @@ export const customObjectPropertiesDropdown = (displayName: string, required: bo } const props: DynamicPropsValue = {}; - const dropdownFunction = isSingleSelect ? Property.StaticDropdown : Property.StaticMultiSelectDropdown; + const dropdownFunction = isSingleSelect + ? Property.StaticDropdown + : Property.StaticMultiSelectDropdown; props['values'] = dropdownFunction({ displayName, @@ -494,15 +499,17 @@ export const workflowIdDropdown = Property.Dropdown({ } const token = (auth as OAuth2PropertyValue).access_token; - const workflowsResponse = await hubspotApiCall<{ workflows: WorkflowResponse[] }>({ - accessToken: token, + const workflowsResponse = await httpClient.sendRequest<{ workflows: WorkflowResponse[] }>({ method: HttpMethod.GET, - resourceUri: `/automation/v2/workflows`, + url: `https://api.hubapi.com/automation/v2/workflows`, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: token, + }, }); - const options: DropdownOption[] = []; - for (const workflow of workflowsResponse.workflows) { + for (const workflow of workflowsResponse.body.workflows) { if (workflow.enabled) { options.push({ label: workflow.name, @@ -617,4 +624,4 @@ type DropdownParams = { displayName: string; required: boolean; description?: string; -}; \ No newline at end of file +}; From 59bc6c0770c6113f6f19ea958280f445c6e86a19 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Sun, 22 Dec 2024 23:09:21 +0530 Subject: [PATCH 32/60] fix(hubspot): fix lint issue --- .../src/lib/actions/create-custom-object.ts | 11 ++++--- .../src/lib/actions/find-custom-object.ts | 12 ++++--- .../src/lib/actions/get-custom-object.ts | 11 ++++--- .../src/lib/actions/updated-custom-object.ts | 12 ++++--- .../community/hubspot/src/lib/common/index.ts | 16 ++-------- .../community/hubspot/src/lib/common/props.ts | 4 +-- .../community/hubspot/src/lib/common/types.ts | 32 +++++++++---------- 7 files changed, 44 insertions(+), 54 deletions(-) diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts index 41ae86f197..d019322c8a 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts @@ -33,18 +33,19 @@ export const createCustomObjectAction = createAction({ async run(context) { const customObjectType = context.propsValue.customObjectType as string; const objectProperties = context.propsValue.objectProperties ?? {}; - let additionalPropertiesToRetrieve = + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve?.['values']; + let propertiesToRetrieve; try { if (Array.isArray(additionalPropertiesToRetrieve)) { - additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + propertiesToRetrieve = additionalPropertiesToRetrieve; } if (typeof additionalPropertiesToRetrieve === 'string') { - additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + propertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); } } catch (error) { - additionalPropertiesToRetrieve = []; + propertiesToRetrieve = []; } const customObjectProperties: Record = {}; @@ -65,7 +66,7 @@ export const createCustomObjectAction = createAction({ const customObjectDetails = await client.crm.objects.basicApi.getById( customObjectType, createdCustomObject.id, - additionalPropertiesToRetrieve, + propertiesToRetrieve, ); return customObjectDetails; diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts index 27af3a8d61..986dacee88 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/find-custom-object.ts @@ -53,18 +53,20 @@ export const findCustomObjectAction = createAction({ 'values' ] as string; - let additionalPropertiesToRetrieve = + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve?.['values']; + let propertiesToRetrieve; + try { if (Array.isArray(additionalPropertiesToRetrieve)) { - additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + propertiesToRetrieve = additionalPropertiesToRetrieve; } if (typeof additionalPropertiesToRetrieve === 'string') { - additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + propertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); } } catch (error) { - additionalPropertiesToRetrieve = []; + propertiesToRetrieve = []; } const filters = [ @@ -87,7 +89,7 @@ export const findCustomObjectAction = createAction({ const response = await client.crm.objects.searchApi.doSearch(customObjectType, { limit: 100, - properties: additionalPropertiesToRetrieve, + properties: propertiesToRetrieve, filterGroups: [{ filters }], }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts index e8b2e66987..89d4765317 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/get-custom-object.ts @@ -30,18 +30,19 @@ export const getCustomObjectAction = createAction({ async run(context) { const customObjectType = context.propsValue.customObjectType as string; const customObjectId = context.propsValue.customObjectId as string; - let additionalPropertiesToRetrieve = + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve?.['values']; + let propertiesToRetrieve; try { if (Array.isArray(additionalPropertiesToRetrieve)) { - additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + propertiesToRetrieve = additionalPropertiesToRetrieve; } if (typeof additionalPropertiesToRetrieve === 'string') { - additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + propertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); } } catch (error) { - additionalPropertiesToRetrieve = []; + propertiesToRetrieve = []; } const client = new Client({ accessToken: context.auth.access_token }); @@ -49,7 +50,7 @@ export const getCustomObjectAction = createAction({ const customObjectDetails = await client.crm.objects.basicApi.getById( customObjectType, customObjectId, - additionalPropertiesToRetrieve, + propertiesToRetrieve, ); return customObjectDetails; diff --git a/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts index f701743737..cfe080d2bd 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts @@ -36,17 +36,19 @@ export const updateCustomObjectAction = createAction({ const customObjectType = context.propsValue.customObjectType as string; const customObjectId = context.propsValue.customObjectId as string; const objectProperties = context.propsValue.objectProperties ?? {}; - let additionalPropertiesToRetrieve = + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve?.['values']; + + let propertiesToRetrieve; try { if (Array.isArray(additionalPropertiesToRetrieve)) { - additionalPropertiesToRetrieve = additionalPropertiesToRetrieve; + propertiesToRetrieve = additionalPropertiesToRetrieve; } if (typeof additionalPropertiesToRetrieve === 'string') { - additionalPropertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + propertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); } } catch (error) { - additionalPropertiesToRetrieve = []; + propertiesToRetrieve = []; } const customObjectProperties: Record = {}; @@ -70,7 +72,7 @@ export const updateCustomObjectAction = createAction({ const customObjectDetails = await client.crm.objects.basicApi.getById( customObjectType, updatedCustomObject.id, - additionalPropertiesToRetrieve, + propertiesToRetrieve, ); return customObjectDetails; diff --git a/packages/pieces/community/hubspot/src/lib/common/index.ts b/packages/pieces/community/hubspot/src/lib/common/index.ts index 6148913069..ca33d23d8d 100644 --- a/packages/pieces/community/hubspot/src/lib/common/index.ts +++ b/packages/pieces/community/hubspot/src/lib/common/index.ts @@ -15,21 +15,9 @@ import { ShortTextProperty, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; +import { HubspotFieldType } from './types'; + -export enum HubspotFieldType { - BooleanCheckBox = 'booleancheckbox', - Date = 'date', - File = 'file', - Number = 'number', - CalculationEquation = 'calculation_equation', - PhoneNumber = 'phonenumber', - Text = 'text', - TextArea = 'textarea', - Html = 'html', - CheckBox = 'checkbox', - Select = 'select', - Radio = 'radio', -} interface HubspotProperty { name: string; diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index b9872ea927..0d17370359 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -2,15 +2,13 @@ import { DropdownOption, DynamicPropsValue, OAuth2PropertyValue, - Piece, PieceAuth, PiecePropValueSchema, Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; -import { HubspotFieldType } from '.'; import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; -import { WorkflowResponse, HubspotProperty } from './types'; +import { WorkflowResponse, HubspotProperty,HubspotFieldType } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 6ff04bfc02..7c23c5bf64 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -131,23 +131,6 @@ export type SearchDealsResponse = { }; }; }; -// ["date","textarea","number","select","file","calculation_equation","checkbox","calculation_rollup","text","calculation_read_time","booleancheckbox","radio","phonenumber","html"] - -enum HubspotFieldType { - BooleanCheckBox = 'booleancheckbox', - Date = 'date', - File = 'file', - Number = 'number', - CalculationEquation = 'calculation_equation', - PhoneNumber = 'phonenumber', - Text = 'text', - TextArea = 'textarea', - Html = 'html', - CheckBox = 'checkbox', - Select = 'select', - Radio = 'radio', -} - export type HubspotProperty= { name: string; label: string; @@ -196,4 +179,19 @@ export enum FilterOperatorEnum { NotHasProperty = "NOT_HAS_PROPERTY", ContainsToken = "CONTAINS_TOKEN", NotContainsToken = "NOT_CONTAINS_TOKEN", +} + +export enum HubspotFieldType { + BooleanCheckBox = 'booleancheckbox', + Date = 'date', + File = 'file', + Number = 'number', + CalculationEquation = 'calculation_equation', + PhoneNumber = 'phonenumber', + Text = 'text', + TextArea = 'textarea', + Html = 'html', + CheckBox = 'checkbox', + Select = 'select', + Radio = 'radio', } \ No newline at end of file From 7aca66f9db7d9d07c851dc67738adf7979e4fa33 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Mon, 23 Dec 2024 13:55:51 +0530 Subject: [PATCH 33/60] fix(hubspot): fix deals action --- .../pieces/community/hubspot/src/index.ts | 5 +- .../src/lib/actions/create-custom-object.ts | 2 +- .../hubspot/src/lib/actions/create-deal.ts | 353 ++++------------- .../hubspot/src/lib/actions/find-deal.ts | 93 +++++ ...stom-object.ts => update-custom-object.ts} | 2 +- .../hubspot/src/lib/actions/update-deal.ts | 355 ++++-------------- .../hubspot/src/lib/actions/update-ticket.ts | 1 - .../community/hubspot/src/lib/common/props.ts | 41 +- 8 files changed, 282 insertions(+), 570 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-deal.ts rename packages/pieces/community/hubspot/src/lib/actions/{updated-custom-object.ts => update-custom-object.ts} (100%) diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index b56bfadefe..da08f67066 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -31,11 +31,12 @@ import { createCompanyAction } from './lib/actions/create-company'; import { findCompanyAction } from './lib/actions/find-company'; import { updateCompanyAction } from './lib/actions/update-company'; import { createCustomObjectAction } from './lib/actions/create-custom-object'; -import { updateCustomObjectAction } from './lib/actions/updated-custom-object'; +import { updateCustomObjectAction } from './lib/actions/update-custom-object'; import { getCustomObjectAction } from './lib/actions/get-custom-object'; import { findCustomObjectAction } from './lib/actions/find-custom-object'; import { getOwnerByEmailAction } from './lib/actions/get-owner-by-email'; import { getOwnerByIdAction } from './lib/actions/get-owner-by-id'; +import { findDealAction } from './lib/actions/find-deal'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -62,6 +63,7 @@ export const hubspotAuth = PieceAuth.OAuth2({ 'automation', 'e-commerce', 'tickets', + 'settings.currencies.read', 'settings.users.read', 'settings.users.teams.read', // 'business_units_view.read' @@ -101,6 +103,7 @@ export const hubspot = createPiece({ findCompanyAction, findContactAction, findCustomObjectAction, + findDealAction, findProductAction, findTicketAction, getOwnerByEmailAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts index d019322c8a..f2c23d2c12 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-custom-object.ts @@ -1,6 +1,6 @@ -import { hubspotAuth } from '../..'; import { createAction, Property } from '@activepieces/pieces-framework'; import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../..'; import { customObjectDropdown, customObjectDynamicProperties, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts index 6b9ae38125..7b3e29737a 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/create-deal.ts @@ -1,288 +1,89 @@ -import { - AuthenticationType, - HttpMethod, - HttpRequest, - httpClient, -} from '@activepieces/pieces-common'; - import { hubspotAuth } from '../../'; -import { - DynamicPropsValue, - PiecePropValueSchema, - Property, - createAction, -} from '@activepieces/pieces-framework'; +import { Property, createAction } from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; import { - ListDealPipelinesResponse, - ListOwnersResponse, - ListPipelineStagesResponse, - ListPropertiesResponse, - PropertyResponse, -} from '../common/types'; + getDefaultPropertiesForObject, + pipelineDropdown, + pipelineStageDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, +} from '../common/props'; + +import { Client } from '@hubspot/api-client'; export const createDealAction = createAction({ - auth: hubspotAuth, - name: 'create_deal', - displayName: 'Create Deal', - description: 'Creates a new deal in hubspot.', - props: { - dealname: Property.ShortText({ - displayName: 'Deal Name', - required: true, - }), - amount: Property.Number({ - displayName: 'Deal Amount', - required: false, - }), - pipelineId: Property.Dropdown({ - displayName: 'Deal Pipeline', - refreshers: [], - required: true, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/pipelines/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = - await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((pipeline) => { - return { - label: pipeline.label, - value: pipeline.id, - }; - }), - }; - }, - }), - dealstageId: Property.Dropdown({ - displayName: 'Deal Stage', - refreshers: ['pipelineId'], - required: true, - options: async ({ auth, pipelineId }) => { - if (!auth || !pipelineId) { - return { - disabled: true, - placeholder: - 'Please connect your account first and select pipeline.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: `https://api.hubapi.com/crm/v3/pipelines/deals/${pipelineId}/stages`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = - await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((stage) => { - return { - label: stage.label, - value: stage.id, - }; - }), - }; - }, - }), - hubspot_owner_id: Property.Dropdown({ - displayName: 'Deal Owner', - refreshers: [], - required: false, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/owners', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest( - request - ); - return { - disabled: false, - options: response.body.results.map((owner) => { - return { - label: owner.email, - value: owner.id, - }; - }), - }; - }, - }), - additionalFields: Property.DynamicProperties({ - displayName: 'Additional Fields', - refreshers: [], - required: true, - props: async ({ auth }) => { - if (!auth) return {}; + auth: hubspotAuth, + name: 'create-deal', + displayName: 'Create Deal', + description: 'Creates a new deal in Hubspot.', + props: { + dealname: Property.ShortText({ + displayName: 'Deal Name', + required: true, + }), + pipelineId: pipelineDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Deal Pipeline', + required: true, + }), + pipelineStageId: pipelineStageDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Deal Stage', + required: true, + }), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.DEAL, [ + 'dealname', + 'pipeline', + 'dealstage', + ]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { dealname, pipelineId, pipelineStageId } = context.propsValue; + const objectProperites = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const dealProperties: Record = { + dealname, + pipeline: pipelineId!, + dealstage: pipelineStageId!, + }; + + // Add additional properties to the dealProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + dealProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); - const fields: DynamicPropsValue = {}; - const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: context.auth.access_token }); - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/properties/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; + const createdDeal = await client.crm.deals.basicApi.create({ + properties: dealProperties, + }); + // Retrieve default properties for the deal and merge with additional properties to retrieve + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); - const response = await httpClient.sendRequest( - request - ); + const dealDetails = await client.crm.deals.basicApi.getById(createdDeal.id, [ + ...defaultDealProperties, + ...additionalPropertiesToRetrieve, + ]); - for (const property of response.body.results) { - if (isRelevantProperty(property)) { - switch (property.fieldType) { - case 'booleancheckbox': - case 'radio': - case 'select': - fields[property.name] = Property.StaticDropdown({ - displayName: property.label, - description: property.description ?? '', - required: false, - options: { - disabled: false, - options: property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case 'checkbox': - fields[property.name] = Property.StaticMultiSelectDropdown({ - displayName: property.label, - description: property.description ?? '', - required: false, - options: { - disabled: false, - options: property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case 'date': - fields[property.name] = Property.DateTime({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'file': - fields[property.name] = Property.File({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'text': - case 'phonenumber': - case 'html': - fields[property.name] = Property.ShortText({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'textarea': - fields[property.name] = Property.LongText({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - default: - break; - } - } - } - return fields; - }, - }), - }, - async run(context) { - const additionalFields = context.propsValue.additionalFields; - const properties: DynamicPropsValue = {}; - Object.entries(additionalFields).forEach(([key, value]) => { - if (Array.isArray(value)) { - properties[key] = value.join(';'); - } else { - properties[key] = value; - } - }); - const request: HttpRequest = { - method: HttpMethod.POST, - url: 'https://api.hubapi.com/crm/v3/objects/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: context.auth.access_token, - }, - body: { - properties: { - dealname: context.propsValue.dealname, - amount: context.propsValue.amount, - pipeline: context.propsValue.pipelineId, - dealstage: context.propsValue.dealstageId, - hubspot_owner_id: context.propsValue.hubspot_owner_id, - ...properties, - }, - }, - }; - const response = await httpClient.sendRequest(request); - return response.body; - }, + return dealDetails; + }, }); -function isRelevantProperty(property: PropertyResponse) { - return ( - !property.modificationMetadata.readOnlyValue && - !property.hidden && - !property.externalOptions && - ![ - 'dealname', - 'pipeline', - 'dealstage', - 'hubspot_owner_id', - 'amount', - ].includes(property.name) - ); -} diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/find-deal.ts new file mode 100644 index 0000000000..14d30cab17 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-deal.ts @@ -0,0 +1,93 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { FilterOperatorEnum } from '../common/types'; +import { Client } from '@hubspot/api-client'; + +export const findDealAction = createAction({ + auth: hubspotAuth, + name: 'find-deal', + displayName: 'Find Deal', + description: 'Finds a deal by searching.', + props: { + firstSearchPropertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.DEAL, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.DEAL, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); + + const response = client.crm.deals.searchApi.doSearch({ + limit: 100, + properties: [...defaultDealProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts b/packages/pieces/community/hubspot/src/lib/actions/update-custom-object.ts similarity index 100% rename from packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts rename to packages/pieces/community/hubspot/src/lib/actions/update-custom-object.ts index cfe080d2bd..c92844157c 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/updated-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-custom-object.ts @@ -1,6 +1,6 @@ -import { hubspotAuth } from '../..'; import { createAction, Property } from '@activepieces/pieces-framework'; import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../..'; import { customObjectDropdown, customObjectDynamicProperties, diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts b/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts index 6bce8b92ec..30ad3973fc 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-deal.ts @@ -1,320 +1,103 @@ -import { - AuthenticationType, - HttpMethod, - HttpRequest, - httpClient, -} from '@activepieces/pieces-common'; - import { hubspotAuth } from '../../'; import { - DynamicPropsValue, - PiecePropValueSchema, Property, createAction, } from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; import { - ListDealPipelinesResponse, - ListOwnersResponse, - ListPipelineStagesResponse, - ListPropertiesResponse, - PropertyResponse, - SearchDealsResponse, -} from '../common/types'; + getDefaultPropertiesForObject, + pipelineDropdown, + pipelineStageDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, +} from '../common/props'; + +import { Client } from '@hubspot/api-client'; export const updateDealAction = createAction({ auth: hubspotAuth, - name: 'update_deal', + name: 'update-deal', displayName: 'Update Deal', - description: 'Updates an existing deal in hubspot.', + description: 'Updates a deal in HubSpot.', props: { - dealId: Property.Dropdown({ + dealId: Property.ShortText({ displayName: 'Deal ID', - refreshers: [], + description: 'The ID of the deal to update.', required: true, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const deals: { label: string; value: string }[] = []; - let after; - do { - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/objects/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - queryParams: after - ? { - limit: '100', - after: after, - } - : { limit: '100' }, - }; - const response = await httpClient.sendRequest(request); - deals.push( - ...response.body.results.map((deal) => { - return { - label: deal.properties['dealname'], - value: deal.id, - }; - }), - ); - after = response.body.paging?.next.after; - } while (after !== undefined); - - return { - disabled: false, - options: deals, - }; - }, }), dealname: Property.ShortText({ displayName: 'Deal Name', required: false, }), - pipelineId: Property.Dropdown({ + pipelineId: pipelineDropdown({ + objectType: OBJECT_TYPE.DEAL, displayName: 'Deal Pipeline', - refreshers: [], - required: true, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/pipelines/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((pipeline) => { - return { - label: pipeline.label, - value: pipeline.id, - }; - }), - }; - }, + required: false, }), - dealstageId: Property.Dropdown({ + pipelineStageId: pipelineStageDropdown({ + objectType: OBJECT_TYPE.DEAL, displayName: 'Deal Stage', - refreshers: ['pipelineId'], - required: true, - options: async ({ auth, pipelineId }) => { - if (!auth || !pipelineId) { - return { - disabled: true, - placeholder: 'Please connect your account first and select pipeline.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: `https://api.hubapi.com/crm/v3/pipelines/deals/${pipelineId}/stages`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((stage) => { - return { - label: stage.label, - value: stage.id, - }; - }), - }; - }, + required: false, }), - hubspot_owner_id: Property.Dropdown({ - displayName: 'Deal Owner', - refreshers: [], + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.DEAL, [ + 'dealname', + 'pipeline', + 'dealstage', + ]), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', required: false, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/owners', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((owner) => { - return { - label: owner.email, - value: owner.id, - }; - }), - }; - }, }), - additionalFields: Property.DynamicProperties({ - displayName: 'Additional Fields', - refreshers: [], - required: true, - props: async ({ auth }) => { - if (!auth) return {}; + }, + async run(context) { + const { dealId, dealname, pipelineId, pipelineStageId } = context.propsValue; + const objectProperites = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; - const fields: DynamicPropsValue = {}; - const authValue = auth as PiecePropValueSchema; + const dealProperties: Record = {}; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/properties/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; + if (dealname) { + dealProperties['dealname'] = dealname; + } + if (pipelineId) { + dealProperties['pipeline'] = pipelineId; + } + if (pipelineStageId) { + dealProperties['dealstage'] = pipelineStageId; + } - const response = await httpClient.sendRequest(request); + // Add additional properties to the dealProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + dealProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); - for (const property of response.body.results) { - if (isRelevantProperty(property)) { - switch (property.fieldType) { - case 'booleancheckbox': - case 'radio': - case 'select': - fields[property.name] = Property.StaticDropdown({ - displayName: property.label, - description: property.description ?? '', - required: false, - options: { - disabled: false, - options: property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case 'checkbox': - fields[property.name] = Property.StaticMultiSelectDropdown({ - displayName: property.label, - description: property.description ?? '', - required: false, - options: { - disabled: false, - options: property.options.map((option) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case 'date': - fields[property.name] = Property.DateTime({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'file': - fields[property.name] = Property.File({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'text': - case 'phonenumber': - case 'html': - fields[property.name] = Property.ShortText({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - case 'textarea': - fields[property.name] = Property.LongText({ - displayName: property.label, - description: property.description ?? '', - required: false, - }); - break; - default: - break; - } - } - } - return fields; - }, - }), - }, - async run(context) { - const dealId = context.propsValue.dealId; - const additionalFields = context.propsValue.additionalFields; - const properties: DynamicPropsValue = {}; - Object.entries(additionalFields).forEach(([key, value]) => { - if (Array.isArray(value)) { - properties[key] = value.join(';'); - } else { - properties[key] = value; - } + const client = new Client({ accessToken: context.auth.access_token }); + + const updatedDeal = await client.crm.deals.basicApi.update(dealId, { + properties: dealProperties, }); - const request: HttpRequest = { - method: HttpMethod.PATCH, - url: `https://api.hubapi.com/crm/v3/objects/deals/${dealId}`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: context.auth.access_token, - }, - body: { - properties: { - dealname: context.propsValue.dealname, - pipeline: context.propsValue.pipelineId, - dealstage: context.propsValue.dealstageId, - hubspot_owner_id: context.propsValue.hubspot_owner_id, - ...properties, - }, - }, - }; - const response = await httpClient.sendRequest(request); - return response.body; + // Retrieve default properties for the deal and merge with additional properties to retrieve + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); + + const dealDetails = await client.crm.deals.basicApi.getById(updatedDeal.id, [ + ...defaultDealProperties, + ...additionalPropertiesToRetrieve, + ]); + + return dealDetails; }, }); -function isRelevantProperty(property: PropertyResponse) { - return ( - !property.modificationMetadata.readOnlyValue && - !property.hidden && - !property.externalOptions && - !['dealname', 'pipeline', 'dealstage', 'hubspot_owner_id'].includes(property.name) - ); -} diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts index 1e3be6eff8..e8a5d141c9 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/update-ticket.ts @@ -19,7 +19,6 @@ export const updateTicketAction = createAction({ }), ticketName: Property.ShortText({ displayName: 'Ticket Name', - description: 'The name of the ticket to create.', required: false, }), pipelineId: pipelineDropdown({ diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 0d17370359..55794faf65 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -8,7 +8,7 @@ import { } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; -import { WorkflowResponse, HubspotProperty,HubspotFieldType } from './types'; +import { WorkflowResponse, HubspotProperty, HubspotFieldType } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, @@ -151,6 +151,28 @@ async function fetchTeamsOptions(accessToken: string): Promise[]> { + const options: DropdownOption[] = []; + + const response = await httpClient.sendRequest<{ + results: Array<{ currencyCode: string; currencyName: string }>; + }>({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/settings/v3/currencies/codes', + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: accessToken, + }, + }); + for (const currency of response.body.results) { + options.push({ + label: currency.currencyName, + value: currency.currencyCode, + }); + } + return options; +} + // async function fetchBusinessUnitsOptions(accessToken: string): Promise[]> { // const client = new Client({ accessToken: accessToken }); // const options: DropdownOption[] = []; @@ -287,7 +309,7 @@ async function retriveObjectProperties( ) { continue; } - + // create property name with property group name const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; @@ -311,7 +333,7 @@ async function retriveObjectProperties( }); continue; } - if (property.name === 'hs_shared_team_ids') { + if (['hs_shared_team_ids', 'hs_attributed_team_ids'].includes(property.name)) { const teamOptions = await fetchTeamsOptions(auth.access_token); props[property.name] = Property.StaticMultiSelectDropdown({ displayName: propertyDisplayName, @@ -323,6 +345,18 @@ async function retriveObjectProperties( }); continue; } + if (property.name === 'deal_currency_code') { + const currencyOptions = await fetchCurrenciesOptions(auth.access_token); + props[property.name] = Property.StaticDropdown({ + displayName: propertyDisplayName, + required: false, + options: { + disabled: false, + options: currencyOptions, + }, + }); + continue; + } if (property.name === 'hs_all_assigned_business_unit_ids') { // TO DO : Add business unit options // const businessUnitOptions = await fetchBusinessUnitsOptions(authValue.access_token); @@ -336,7 +370,6 @@ async function retriveObjectProperties( // }); continue; } - props[property.name] = createPropertyDefinition(property, propertyDisplayName); } // Remove null props From 79b19b987208debac1182dd07531bd8623b24b8d Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Mon, 23 Dec 2024 16:25:52 +0530 Subject: [PATCH 34/60] feat(hubspot): add line items action --- .../pieces/community/hubspot/src/index.ts | 8 + .../src/lib/actions/create-line-item.ts | 72 ++++++ .../hubspot/src/lib/actions/find-line-item.ts | 93 ++++++++ .../hubspot/src/lib/actions/get-line-item.ts | 48 ++++ .../src/lib/actions/update-line-item.ts | 81 +++++++ .../hubspot/src/lib/common/constants.ts | 212 ++++++++++-------- .../community/hubspot/src/lib/common/props.ts | 43 +++- 7 files changed, 461 insertions(+), 96 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-line-item.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-line-item.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/get-line-item.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/update-line-item.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index da08f67066..2656f24796 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -37,6 +37,10 @@ import { findCustomObjectAction } from './lib/actions/find-custom-object'; import { getOwnerByEmailAction } from './lib/actions/get-owner-by-email'; import { getOwnerByIdAction } from './lib/actions/get-owner-by-id'; import { findDealAction } from './lib/actions/find-deal'; +import { createLineItemAction } from './lib/actions/create-line-item'; +import { getLineItemAction } from './lib/actions/get-line-item'; +import { updateLineItemAction } from './lib/actions/update-line-item'; +import { findLineItemAction } from './lib/actions/find-line-item'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -85,6 +89,7 @@ export const hubspot = createPiece({ createContactAction, createCustomObjectAction, createDealAction, + createLineItemAction, createOrUpdateContactAction, createProductAction, createTicketAction, @@ -92,18 +97,21 @@ export const hubspot = createPiece({ getContactAction, getCustomObjectAction, getDealAction, + getLineItemAction, getProductAction, getTicketAction, updateCompanyAction, updateContactAction, updateCustomObjectAction, updateDealAction, + updateLineItemAction, updateProductAction, updateTicketAction, findCompanyAction, findContactAction, findCustomObjectAction, findDealAction, + findLineItemAction, findProductAction, findTicketAction, getOwnerByEmailAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-line-item.ts b/packages/pieces/community/hubspot/src/lib/actions/create-line-item.ts new file mode 100644 index 0000000000..7cf5e7a3d7 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-line-item.ts @@ -0,0 +1,72 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + productDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; + +import { Client } from '@hubspot/api-client'; + +export const createLineItemAction = createAction({ + auth: hubspotAuth, + name: 'create-line-item', + displayName: 'Create Line Item', + description: 'Creates a line item in Hubspot.', + props: { + productId: productDropdown({ + displayName: 'Line Item Information: Product ID', + required: true, + objectType: OBJECT_TYPE.PRODUCT, + }), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.LINE_ITEM, ['hs_product_id']), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const productId = context.propsValue.productId; + + const objectProperites = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const lineItemProperties: Record = { + hs_product_id: productId!, + }; + + // Add additional properties to the lineItemProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + lineItemProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdLineItem = await client.crm.lineItems.basicApi.create({ + associations: [], + properties: lineItemProperties, + }); + // Retrieve default properties for the line item and merge with additional properties to retrieve + const defaultlineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + + const lineItemDeatils = await client.crm.lineItems.basicApi.getById(createdLineItem.id, [ + ...defaultlineItemProperties, + ...additionalPropertiesToRetrieve, + ]); + + return lineItemDeatils; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-line-item.ts b/packages/pieces/community/hubspot/src/lib/actions/find-line-item.ts new file mode 100644 index 0000000000..7a5e78c9b8 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-line-item.ts @@ -0,0 +1,93 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; +import { hubspotAuth } from '../../'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { FilterOperatorEnum } from '../common/types'; + +export const findLineItemAction = createAction({ + auth: hubspotAuth, + name: 'find-line-item', + displayName: 'Find Line Item', + description: 'Finds a line item by searching.', + props: { + firstSearchPropertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'First search property name', + required: true, + }, + true, + true, + ), + firstSearchPropertyValue: Property.ShortText({ + displayName: 'First search property value', + required: true, + }), + secondSearchPropertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Second search property name', + required: false, + }, + true, + true, + ), + secondSearchPropertyValue: Property.ShortText({ + displayName: 'Second search property value', + required: false, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { + firstSearchPropertyName, + firstSearchPropertyValue, + secondSearchPropertyName, + secondSearchPropertyValue, + } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const filters = [ + { + propertyName: firstSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: firstSearchPropertyValue, + }, + ]; + + if (secondSearchPropertyName && secondSearchPropertyValue) { + filters.push({ + propertyName: secondSearchPropertyName as string, + operator: FilterOperatorEnum.Eq, + value: secondSearchPropertyValue, + }); + } + + const client = new Client({ accessToken: context.auth.access_token }); + + const defaultLineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + + const response = client.crm.lineItems.searchApi.doSearch({ + limit: 100, + properties: [...defaultLineItemProperties, ...additionalPropertiesToRetrieve], + filterGroups: [{ filters }], + }); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/get-line-item.ts b/packages/pieces/community/hubspot/src/lib/actions/get-line-item.ts new file mode 100644 index 0000000000..a28860011e --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/get-line-item.ts @@ -0,0 +1,48 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; + +export const getLineItemAction = createAction({ + auth: hubspotAuth, + name: 'get-line-item', + displayName: 'Get Line Item', + description: 'Gets a line item.', + props: { + lineItemId: Property.ShortText({ + displayName: 'Line Item ID', + description: 'The ID of the line item to get.', + required: true, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const { lineItemId } = context.propsValue; + + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const defaultLineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + const client = new Client({ accessToken: context.auth.access_token }); + + const lineItemDetails = await client.crm.lineItems.basicApi.getById(lineItemId, [ + ...defaultLineItemProperties, + ...additionalPropertiesToRetrieve, + ]); + + return lineItemDetails; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/update-line-item.ts b/packages/pieces/community/hubspot/src/lib/actions/update-line-item.ts new file mode 100644 index 0000000000..8f713ffcb0 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/update-line-item.ts @@ -0,0 +1,81 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + getDefaultPropertiesForObject, + productDropdown, + standardObjectDynamicProperties, + standardObjectPropertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; + +import { Client } from '@hubspot/api-client'; + +export const updateLineItemAction = createAction({ + auth: hubspotAuth, + name: 'update-line-item', + displayName: 'Update Line Item', + description: 'Updates a line item in Hubspot.', + props: { + lineItemId: Property.ShortText({ + displayName: 'Line Item ID', + description: 'The ID of the line item to update.', + required: true, + }), + productId: productDropdown({ + displayName: 'Line Item Information: Product ID', + required: false, + objectType: OBJECT_TYPE.PRODUCT, + }), + objectProperties: standardObjectDynamicProperties(OBJECT_TYPE.LINE_ITEM, ['hs_product_id']), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async run(context) { + const lineItemId = context.propsValue.lineItemId; + const productId = context.propsValue.productId; + const objectProperites = context.propsValue.objectProperties ?? {}; + const additionalPropertiesToRetrieve = context.propsValue.additionalPropertiesToRetrieve ?? []; + + const lineItemProperties: Record = { + hs_product_id: productId!, + }; + + if(productId) + { + lineItemProperties['hs_product_id'] = productId; + } + + // Add additional properties to the lineItemProperties object + Object.entries(objectProperites).forEach(([key, value]) => { + // Format values if they are arrays + lineItemProperties[key] = Array.isArray(value) ? value.join(';') : value; + }); + + const client = new Client({ accessToken: context.auth.access_token }); + + const createdLineItem = await client.crm.lineItems.basicApi.update(lineItemId, { + properties: lineItemProperties, + }); + // Retrieve default properties for the line item and merge with additional properties to retrieve + const defaultlineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + + const lineItemDeatils = await client.crm.lineItems.basicApi.getById(createdLineItem.id, [ + ...defaultlineItemProperties, + ...additionalPropertiesToRetrieve, + ]); + + return lineItemDeatils; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index 84efcdf77f..65dc8a2677 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -1,111 +1,133 @@ export const enum OBJECT_TYPE { - CONTACT = 'contact', - COMPANY = 'company', - DEAL = 'deal', - TICKET = 'ticket', - PRODUCT = 'product' + CONTACT = 'contact', + COMPANY = 'company', + DEAL = 'deal', + TICKET = 'ticket', + PRODUCT = 'product', + LINE_ITEM = 'line_item', } export const DEFAULT_CONTACT_PROPERTIES = [ - 'firstname', - 'lastname', - 'email', - 'company', - 'website', - 'mobilephone', - 'phone', - 'fax', - 'address', - 'city', - 'state', - 'zip', - 'salutation', - 'country', - 'jobtitle', - 'hs_createdate', - 'hs_email_domain', - 'hs_object_id', - 'lastmodifieddate', - 'hs_persona', - 'hs_language', - 'lifecyclestage', - 'createdate', - 'numemployees', - 'annualrevenue', - 'industry', + 'firstname', + 'lastname', + 'email', + 'company', + 'website', + 'mobilephone', + 'phone', + 'fax', + 'address', + 'city', + 'state', + 'zip', + 'salutation', + 'country', + 'jobtitle', + 'hs_createdate', + 'hs_email_domain', + 'hs_object_id', + 'lastmodifieddate', + 'hs_persona', + 'hs_language', + 'lifecyclestage', + 'createdate', + 'numemployees', + 'annualrevenue', + 'industry', ]; export const DEFAULT_DEAL_PROPERTIES = [ - 'dealtype', - 'dealname', - 'amount', - 'description', - 'closedate', - 'createdate', - 'num_associated_contacts', - 'hs_forecast_amount', - 'hs_forecast_probability', - 'hs_manual_forecast_category', - 'hs_next_step', - 'hs_object_id', - 'hs_lastmodifieddate', - 'hubspot_owner_id', - 'hubspot_team_id', + 'dealtype', + 'dealname', + 'amount', + 'description', + 'closedate', + 'createdate', + 'num_associated_contacts', + 'hs_forecast_amount', + 'hs_forecast_probability', + 'hs_manual_forecast_category', + 'hs_next_step', + 'hs_object_id', + 'hs_lastmodifieddate', + 'hubspot_owner_id', + 'hubspot_team_id', ]; export const DEFAULT_TICKET_PROPERTIES = [ - 'subject', - 'content', - 'source_type', - 'createdate', - 'hs_pipeline', - 'hs_pipeline_stage', - 'hs_resolution', - 'hs_ticket_category', - 'hs_ticket_id', - 'hs_ticket_priority', - 'hs_lastmodifieddate', - 'hubspot_owner_id', - 'hubspot_team_id', + 'subject', + 'content', + 'source_type', + 'createdate', + 'hs_pipeline', + 'hs_pipeline_stage', + 'hs_resolution', + 'hs_ticket_category', + 'hs_ticket_id', + 'hs_ticket_priority', + 'hs_lastmodifieddate', + 'hubspot_owner_id', + 'hubspot_team_id', ]; export const DEFAULT_COMPANY_PROPERTIES = [ - "name", - "domain", - "industry", - "about_us", - "phone", - "address", - "address2", - "city", - "state", - "zip", - "country", - "website", - "type", - "description", - "founded_year", - "hs_createdate", - "hs_lastmodifieddate", - "hs_object_id", - "is_public", - "timezone", - "total_money_raised", - "total_revenue", - "owneremail", - "ownername", - "numberofemployees", - "annualrevenue", - "lifecyclestage", - "createdate", - "web_technologies", + 'name', + 'domain', + 'industry', + 'about_us', + 'phone', + 'address', + 'address2', + 'city', + 'state', + 'zip', + 'country', + 'website', + 'type', + 'description', + 'founded_year', + 'hs_createdate', + 'hs_lastmodifieddate', + 'hs_object_id', + 'is_public', + 'timezone', + 'total_money_raised', + 'total_revenue', + 'owneremail', + 'ownername', + 'numberofemployees', + 'annualrevenue', + 'lifecyclestage', + 'createdate', + 'web_technologies', ]; export const DEFAULT_PRODUCT_PROPERTIES = [ - "createdate", - "description", - "name", - "price", - "tax", - "hs_lastmodifieddate", -]; \ No newline at end of file + 'createdate', + 'description', + 'name', + 'price', + 'tax', + 'hs_lastmodifieddate', +]; + +export const DEFAULT_LINE_ITEM_PROPERTIES = [ + 'name', + 'description', + 'price', + 'quantity', + 'amount', + 'discount', + 'tax', + 'createdate', + 'hs_object_id', + 'hs_product_id', + 'hs_images', + 'hs_lastmodifieddate', + 'hs_line_item_currency_code', + 'hs_sku', + 'hs_url', + 'hs_cost_of_goods_sold', + 'hs_discount_percentage', + 'hs_term_in_months', +]; diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 55794faf65..d7adcae80c 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -13,6 +13,7 @@ import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, DEFAULT_DEAL_PROPERTIES, + DEFAULT_LINE_ITEM_PROPERTIES, DEFAULT_PRODUCT_PROPERTIES, DEFAULT_TICKET_PROPERTIES, OBJECT_TYPE, @@ -89,6 +90,8 @@ export function getDefaultPropertiesForObject(objectType: OBJECT_TYPE): string[] return DEFAULT_COMPANY_PROPERTIES; case OBJECT_TYPE.PRODUCT: return DEFAULT_PRODUCT_PROPERTIES; + case OBJECT_TYPE.LINE_ITEM: + return DEFAULT_LINE_ITEM_PROPERTIES; default: return []; } @@ -309,7 +312,7 @@ async function retriveObjectProperties( ) { continue; } - + // create property name with property group name const propertyDisplayName = `${groupLabels[property.groupName] || ''}: ${property.label}`; @@ -621,6 +624,44 @@ export const pipelineStageDropdown = (params: DropdownParams) => }; }, }); + +export const productDropdown =(params: DropdownParams) => Property.Dropdown({ + displayName: params.displayName, + refreshers: [], + required: params.required, + description: params.description, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const options: DropdownOption[] = []; + + const limit = 100; + let after: string | undefined; + do { + const response = await client.crm.products.basicApi.getPage(limit, after, ['name']); + for (const product of response.results) { + options.push({ + label: product.properties.name ?? product.id, + value: product.id, + }); + } + + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + }; + }, +}); export const customObjectDropdown = Property.Dropdown({ displayName: 'Type of Custom Object', refreshers: [], From db1066381eebb10280d4544f87ce8c4f9ad9b8be Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Mon, 23 Dec 2024 21:21:51 +0530 Subject: [PATCH 35/60] feat(hubspot): remove contcat from list action --- .../pieces/community/hubspot/src/index.ts | 2 + .../lib/actions/add-contact-to-list-action.ts | 55 ++++---- .../lib/actions/remove-contact-from-list.ts | 51 ++++++++ .../community/hubspot/src/lib/common/props.ts | 120 +++++++++++++----- 4 files changed, 172 insertions(+), 56 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/remove-contact-from-list.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 2656f24796..931808a09d 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -41,6 +41,7 @@ import { createLineItemAction } from './lib/actions/create-line-item'; import { getLineItemAction } from './lib/actions/get-line-item'; import { updateLineItemAction } from './lib/actions/update-line-item'; import { findLineItemAction } from './lib/actions/find-line-item'; +import { removeContactFromListAction } from './lib/actions/remove-contact-from-list'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -100,6 +101,7 @@ export const hubspot = createPiece({ getLineItemAction, getProductAction, getTicketAction, + removeContactFromListAction, updateCompanyAction, updateContactAction, updateCustomObjectAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-list-action.ts b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-list-action.ts index 27623c9e43..04d850588b 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-list-action.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/add-contact-to-list-action.ts @@ -1,35 +1,36 @@ -import { hubSpotListIdDropdown } from '../common/props'; -import { hubSpotClient } from '../common/client'; +import { staticListsDropdown } from '../common/props'; import { createAction, Property } from '@activepieces/pieces-framework'; -import { assertNotNullOrUndefined } from '@activepieces/shared'; import { hubspotAuth } from '../../'; +import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; export const hubSpotListsAddContactAction = createAction({ - auth: hubspotAuth, - name: 'add_contact_to_list', - displayName: 'Add contact To List', - description: 'Add contact to list', - props: { - listId: hubSpotListIdDropdown, - email: Property.ShortText({ - displayName: 'Email', - description: 'Contact email', - required: true, - }), - }, + auth: hubspotAuth, + name: 'add_contact_to_list', + displayName: 'Add contact To List', + description: 'Add contact to list', + props: { + listId: staticListsDropdown, + email: Property.ShortText({ + displayName: 'Contact Email', + required: true, + }), + }, - async run(context) { - const token = context.auth.access_token; - const { listId, email } = context.propsValue; + async run(context) { + const { listId, email } = context.propsValue; - assertNotNullOrUndefined(token, 'token'); - assertNotNullOrUndefined(listId, 'list'); - assertNotNullOrUndefined(email, 'email'); + const response = await httpClient.sendRequest({ + method: HttpMethod.POST, + url: `https://api.hubapi.com/contacts/v1/lists/${listId}/add`, + body: { + emails: [email], + }, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: context.auth.access_token, + }, + }) - return await hubSpotClient.lists.addContact({ - token, - listId, - email, - }); - }, + return response.body; + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/remove-contact-from-list.ts b/packages/pieces/community/hubspot/src/lib/actions/remove-contact-from-list.ts new file mode 100644 index 0000000000..489f9df163 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/remove-contact-from-list.ts @@ -0,0 +1,51 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { staticListsDropdown } from '../common/props'; +import { HttpMethod } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum, HubSpotAddContactsToListResponse } from '../common/types'; + +export const removeContactFromListAction = createAction({ + auth: hubspotAuth, + name: 'remove-contact-from-list', + displayName: 'Remove Contact from List', + description: 'Remove a contact from a specific list.', + props: { + listId: staticListsDropdown, + email: Property.ShortText({ + displayName: 'Contact Email', + required: true, + }), + }, + async run(context) { + const { listId, email } = context.propsValue; + + const client = new Client({ accessToken: context.auth.access_token }); + + const contact = await client.crm.contacts.searchApi.doSearch({ + limit: 1, + filterGroups: [ + { filters: [{ propertyName: 'email', operator: FilterOperatorEnum.Eq, value: email }] }, + ], + }); + if (contact.results.length === 0) { + throw new Error( + `No contact with email '${email}' was found. Unable to remove unknown contact from list.`, + ); + } + const apiResponse = await client.apiRequest({ + path: `/contacts/v1/lists/${listId}/remove`, + method: HttpMethod.POST, + body: { vids: [contact.results[0].id] }, + defaultJson: true, + }); + + const parsedResponse =(await apiResponse.json()) as HubSpotAddContactsToListResponse; + if(parsedResponse.updated.length === 0) { + throw new Error( + `Contact with email '${email}' wasn't a member of list with id '${listId}'.`, + ); + } + return parsedResponse; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index d7adcae80c..eccf5b4006 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -7,7 +7,12 @@ import { Property, } from '@activepieces/pieces-framework'; import { hubSpotClient } from './client'; -import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; +import { + AuthenticationType, + httpClient, + HttpMethod, + HttpRequest, +} from '@activepieces/pieces-common'; import { WorkflowResponse, HubspotProperty, HubspotFieldType } from './types'; import { DEFAULT_COMPANY_PROPERTIES, @@ -625,11 +630,48 @@ export const pipelineStageDropdown = (params: DropdownParams) => }, }); -export const productDropdown =(params: DropdownParams) => Property.Dropdown({ - displayName: params.displayName, +export const productDropdown = (params: DropdownParams) => + Property.Dropdown({ + displayName: params.displayName, + refreshers: [], + required: params.required, + description: params.description, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const options: DropdownOption[] = []; + + const limit = 100; + let after: string | undefined; + do { + const response = await client.crm.products.basicApi.getPage(limit, after, ['name']); + for (const product of response.results) { + options.push({ + label: product.properties.name ?? product.id, + value: product.id, + }); + } + + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + }; + }, + }); +export const customObjectDropdown = Property.Dropdown({ + displayName: 'Type of Custom Object', refreshers: [], - required: params.required, - description: params.description, + required: true, options: async ({ auth }) => { if (!auth) { return buildEmptyList({ @@ -640,21 +682,14 @@ export const productDropdown =(params: DropdownParams) => Property.Dropdown({ const authValue = auth as PiecePropValueSchema; const client = new Client({ accessToken: authValue.access_token }); - const options: DropdownOption[] = []; - - const limit = 100; - let after: string | undefined; - do { - const response = await client.crm.products.basicApi.getPage(limit, after, ['name']); - for (const product of response.results) { - options.push({ - label: product.properties.name ?? product.id, - value: product.id, - }); - } + const customObjectsResponse = await client.crm.schemas.coreApi.getAll(); - after = response.paging?.next?.after; - } while (after); + const options = customObjectsResponse.results.map((customObj) => { + return { + label: customObj.labels.plural ?? customObj.name, + value: customObj.objectTypeId, + }; + }); return { disabled: false, @@ -662,8 +697,9 @@ export const productDropdown =(params: DropdownParams) => Property.Dropdown({ }; }, }); -export const customObjectDropdown = Property.Dropdown({ - displayName: 'Type of Custom Object', + +export const staticListsDropdown = Property.Dropdown({ + displayName: 'List ID', refreshers: [], required: true, options: async ({ auth }) => { @@ -674,16 +710,40 @@ export const customObjectDropdown = Property.Dropdown({ } const authValue = auth as PiecePropValueSchema; - const client = new Client({ accessToken: authValue.access_token }); - - const customObjectsResponse = await client.crm.schemas.coreApi.getAll(); + const options: DropdownOption[] = []; - const options = customObjectsResponse.results.map((customObj) => { - return { - label: customObj.labels.plural ?? customObj.name, - value: customObj.objectTypeId, + let offset = 0; + let hasMore = true; + do { + const request: HttpRequest = { + url: 'https://api.hubapi.com/contacts/v1/lists/static', + method: HttpMethod.GET, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: authValue.access_token, + }, + queryParams: { + count: '100', + offset: offset.toString(), + }, }; - }); + const response = await httpClient.sendRequest<{ + total: number; + offset: number; + 'has-more': boolean; + lists: Array<{ name: string; listId: number }>; + }>(request); + + for (const list of response.body.lists) { + options.push({ + label: list.name, + value: list.listId, + }); + } + offset += 100; + hasMore = response.body['has-more']; + + } while (hasMore); return { disabled: false, @@ -691,6 +751,8 @@ export const customObjectDropdown = Property.Dropdown({ }; }, }); + + type DropdownParams = { objectType: OBJECT_TYPE; displayName: string; From 3915835486e9ea5ae9caf8b6f465b25e53f9795a Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Tue, 24 Dec 2024 10:05:39 +0530 Subject: [PATCH 36/60] feat(hubspot): upload file action --- packages/pieces/community/hubspot/src/index.ts | 1 + .../hubspot/src/lib/actions/upload-file.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/upload-file.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 931808a09d..dff8b661c4 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -71,6 +71,7 @@ export const hubspotAuth = PieceAuth.OAuth2({ 'settings.currencies.read', 'settings.users.read', 'settings.users.teams.read', + 'files' // 'business_units_view.read' ], }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts b/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts new file mode 100644 index 0000000000..e9d1c7150c --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts @@ -0,0 +1,18 @@ +import { hubspotAuth } from "../../"; +import { createAction } from "@activepieces/pieces-framework"; +import {Client } from "@hubspot/api-client"; + +export const uploadFileAction = createAction({ + auth:hubspotAuth, + name:"upload-file", + displayName:"Upload File", + description:"Uploads a file to HubSpot File Manager.", + props:{ + + }, + async run(context){ + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.files.filesApi.upload() + } +}) \ No newline at end of file From cf38f15f33109cb8a5275ec3fa14c95071d92e5c Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Tue, 24 Dec 2024 15:15:57 +0530 Subject: [PATCH 37/60] feat(hubspot): upload file action --- .../pieces/community/hubspot/src/index.ts | 2 + .../hubspot/src/lib/actions/upload-file.ts | 120 +++++++++++++++--- .../community/hubspot/src/lib/common/props.ts | 1 - 3 files changed, 106 insertions(+), 17 deletions(-) diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index dff8b661c4..27c5d98cb6 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -42,6 +42,7 @@ import { getLineItemAction } from './lib/actions/get-line-item'; import { updateLineItemAction } from './lib/actions/update-line-item'; import { findLineItemAction } from './lib/actions/find-line-item'; import { removeContactFromListAction } from './lib/actions/remove-contact-from-list'; +import { uploadFileAction } from './lib/actions/upload-file'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -110,6 +111,7 @@ export const hubspot = createPiece({ updateLineItemAction, updateProductAction, updateTicketAction, + uploadFileAction, findCompanyAction, findContactAction, findCustomObjectAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts b/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts index e9d1c7150c..312f0cbda5 100644 --- a/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts +++ b/packages/pieces/community/hubspot/src/lib/actions/upload-file.ts @@ -1,18 +1,106 @@ -import { hubspotAuth } from "../../"; -import { createAction } from "@activepieces/pieces-framework"; -import {Client } from "@hubspot/api-client"; +import { hubspotAuth } from '../../'; +import { + createAction, + DropdownOption, + PiecePropValueSchema, + Property, +} from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; export const uploadFileAction = createAction({ - auth:hubspotAuth, - name:"upload-file", - displayName:"Upload File", - description:"Uploads a file to HubSpot File Manager.", - props:{ - - }, - async run(context){ - const client = new Client({ accessToken: context.auth.access_token }); - - const response = await client.files.filesApi.upload() - } -}) \ No newline at end of file + auth: hubspotAuth, + name: 'upload-file', + displayName: 'Upload File', + description: 'Uploads a file to HubSpot File Manager.', + props: { + folderId: Property.Dropdown({ + displayName: 'Folder', + refreshers: [], + required: true, + options: async ({ auth }) => { + if (!auth) { + return { + disabled: true, + options: [], + placeholder: 'Please connect your account.', + }; + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const limit = 100; + const options: DropdownOption[] = []; + let after: string | undefined; + + do { + const response = await client.files.foldersApi.doSearch( + undefined, + after, + undefined, + limit, + ); + + for (const folder of response.results) { + options.push({ + value: folder.id, + label: folder.name ?? folder.id, + }); + } + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + }; + }, + }), + fileName: Property.ShortText({ + displayName: 'File Name', + required: true, + }), + accessLevel: Property.StaticDropdown({ + displayName: 'Access Level', + required: true, + options: { + disabled: false, + options: [ + { + value: 'PUBLIC_INDEXABLE', + label: 'PUBLIC_INDEXABLE', + }, + { + value: 'PUBLIC_NOT_INDEXABLE', + label: 'PUBLIC_NOT_INDEXABLE', + }, + { label: 'PRIVATE', value: 'PRIVATE' }, + ], + }, + }), + file: Property.File({ + displayName: 'File', + required: true, + }), + }, + async run(context) { + const { accessLevel, fileName, folderId, file } = context.propsValue; + const client = new Client({ accessToken: context.auth.access_token }); + + const response = await client.files.filesApi.upload( + { + name: fileName, + data: file.data, + }, + folderId, + undefined, + fileName, + undefined, + JSON.stringify({ + access: accessLevel, + }), + ); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index eccf5b4006..a6e048e0c5 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -752,7 +752,6 @@ export const staticListsDropdown = Property.Dropdown({ }, }); - type DropdownParams = { objectType: OBJECT_TYPE; displayName: string; From e384a75920eac9bcc994eb005bf0a886b835efd5 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Tue, 24 Dec 2024 16:25:27 +0530 Subject: [PATCH 38/60] feat(hubspot): remove email subscription action --- .../pieces/community/hubspot/src/index.ts | 3 ++ .../lib/actions/remove-email-subscription.ts | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/remove-email-subscription.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 27c5d98cb6..f79bbb93b5 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -43,6 +43,7 @@ import { updateLineItemAction } from './lib/actions/update-line-item'; import { findLineItemAction } from './lib/actions/find-line-item'; import { removeContactFromListAction } from './lib/actions/remove-contact-from-list'; import { uploadFileAction } from './lib/actions/upload-file'; +import { removeEmailSubscriptionAction } from './lib/actions/remove-email-subscription'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -69,6 +70,7 @@ export const hubspotAuth = PieceAuth.OAuth2({ 'automation', 'e-commerce', 'tickets', + 'content', 'settings.currencies.read', 'settings.users.read', 'settings.users.teams.read', @@ -104,6 +106,7 @@ export const hubspot = createPiece({ getProductAction, getTicketAction, removeContactFromListAction, + removeEmailSubscriptionAction, updateCompanyAction, updateContactAction, updateCustomObjectAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/remove-email-subscription.ts b/packages/pieces/community/hubspot/src/lib/actions/remove-email-subscription.ts new file mode 100644 index 0000000000..2ae777919c --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/remove-email-subscription.ts @@ -0,0 +1,34 @@ +import { hubspotAuth } from '../../'; +import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; +import { createAction, Property } from '@activepieces/pieces-framework'; + +export const removeEmailSubscriptionAction = createAction({ + auth: hubspotAuth, + name: 'remove-email-subscription', + displayName: 'Remove Email Subscription', + description: 'Removes email subscription.', + props: { + email: Property.ShortText({ + displayName: 'Email', + required: true, + }), + }, + async run(context) { + const { email } = context.propsValue; + + // https://developers.hubspot.com/docs/reference/api/marketing/subscriptions-preferences/v1#update-email-subscription-status-for-an-email-address + const response = await httpClient.sendRequest({ + method: HttpMethod.PUT, + url: `https://api.hubapi.com/email/public/v1/subscriptions/${email}`, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: context.auth.access_token, + }, + body: { + unsubscribeFromAll: true, + }, + }); + + return response.body; + }, +}); From d33284a902392cb9c6c3ede04e3e4c43b8e330dd Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 25 Dec 2024 13:41:07 +0530 Subject: [PATCH 39/60] feat(hubspot): associations action --- .../pieces/community/hubspot/src/index.ts | 6 + .../src/lib/actions/create-associations.ts | 108 +++++++++++++++ .../src/lib/actions/find-associations.ts | 56 ++++++++ .../src/lib/actions/remove-associations.ts | 108 +++++++++++++++ .../hubspot/src/lib/common/constants.ts | 24 ++++ .../community/hubspot/src/lib/common/props.ts | 128 +++++++++++++++++- .../community/hubspot/src/lib/common/types.ts | 8 +- 7 files changed, 435 insertions(+), 3 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-associations.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/find-associations.ts create mode 100644 packages/pieces/community/hubspot/src/lib/actions/remove-associations.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index f79bbb93b5..0d1f033d94 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -44,6 +44,9 @@ import { findLineItemAction } from './lib/actions/find-line-item'; import { removeContactFromListAction } from './lib/actions/remove-contact-from-list'; import { uploadFileAction } from './lib/actions/upload-file'; import { removeEmailSubscriptionAction } from './lib/actions/remove-email-subscription'; +import { createAssociationsAction } from './lib/actions/create-associations'; +import { removeAssociationsAction } from './lib/actions/remove-associations'; +import { findAssociationsAction } from './lib/actions/find-associations'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -90,6 +93,7 @@ export const hubspot = createPiece({ actions: [ hubSpotListsAddContactAction, addContactToWorkflowAction, + createAssociationsAction, createCompanyAction, createContactAction, createCustomObjectAction, @@ -105,6 +109,7 @@ export const hubspot = createPiece({ getLineItemAction, getProductAction, getTicketAction, + removeAssociationsAction, removeContactFromListAction, removeEmailSubscriptionAction, updateCompanyAction, @@ -115,6 +120,7 @@ export const hubspot = createPiece({ updateProductAction, updateTicketAction, uploadFileAction, + findAssociationsAction, findCompanyAction, findContactAction, findCustomObjectAction, diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-associations.ts b/packages/pieces/community/hubspot/src/lib/actions/create-associations.ts new file mode 100644 index 0000000000..89dc51b3ad --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-associations.ts @@ -0,0 +1,108 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + fromObjectTypeAssociationDropdown, + associationTypeDropdown, + toObjectIdsDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { AssociationSpecAssociationCategoryEnum } from '../common/types'; + +export const createAssociationsAction = createAction({ + auth: hubspotAuth, + name: 'create-associations', + displayName: 'Create Associations', + description: 'Creates assosiations between objects', + props: { + fromObjectId: Property.ShortText({ + displayName: 'From Object ID', + description: 'The ID of the object being associated.', + required: true, + }), + fromObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'From Object Type', + required: true, + description: 'The type of the object being associated.', + }), + toObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'To Object Type', + required: true, + description: 'Type of the objects the from object is being associated with.', + }), + associationType: associationTypeDropdown, + toObjectIds: toObjectIdsDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'To Object IDs', + required: true, + description: 'The ID\'sof the objects the from object is being associated with', + }), + }, + async run(context) { + const { fromObjectId, fromObjectType, toObjectType, associationType } = context.propsValue; + + const client = new Client({ accessToken: context.auth.access_token }); + + if(context.propsValue.toObjectIds === undefined) { + throw new Error('Please provide To Object IDs'); + } + + let toObjectIds: any[]; + if (Array.isArray(context.propsValue.toObjectIds)) { + toObjectIds = context.propsValue.toObjectIds; + } else { + try { + toObjectIds = JSON.parse(context.propsValue.toObjectIds); + } catch { + throw new Error( + `Please provide To Object IDs in a valid format. Provided : ${JSON.stringify( + context.propsValue.toObjectIds, + )}`, + ); + } + } + + // find the association category + const associationLabels = await client.crm.associations.v4.schema.definitionsApi.getAll( + fromObjectType as string, + toObjectType as string, + ); + const association = associationLabels.results.find( + (associationLabel) => associationLabel.typeId === associationType, + ); + if (!association) { + throw new Error( + `Association type ${associationType} not found for ${fromObjectType} to ${toObjectType}`, + ); + } + const associationCategory = association.category; + + const response = await client.crm.associations.v4.batchApi.create( + fromObjectType as string, + toObjectType as string, + { + inputs: toObjectIds.map((objectId) => { + return { + _from: { + id: fromObjectId, + }, + to: { + id: objectId, + }, + types: [ + { + associationCategory: + associationCategory as unknown as AssociationSpecAssociationCategoryEnum, + associationTypeId: associationType, + }, + ], + }; + }), + }, + ); + + return response; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/find-associations.ts b/packages/pieces/community/hubspot/src/lib/actions/find-associations.ts new file mode 100644 index 0000000000..f153377938 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/find-associations.ts @@ -0,0 +1,56 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { fromObjectTypeAssociationDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; + +export const findAssociationsAction = createAction({ + auth: hubspotAuth, + name: 'find-associations', + displayName: 'Find Associations', + description: 'Finds associations between objects', + props: { + fromObjectId: Property.ShortText({ + displayName: 'From Object ID', + description: 'The ID of the object you want to search the association.', + required: true, + }), + fromObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'From Object Type', + required: true, + description: 'The type of the object you want to search the association.', + }), + toObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'To Object Type', + required: true, + description: 'Type of the object the from object is being associated with.', + }), + }, + async run(context) { + const { fromObjectId, fromObjectType, toObjectType } = context.propsValue; + + const client = new Client({ accessToken: context.auth.access_token }); + + const results = []; + const limit = 100; + let after: string | undefined; + + do { + const reponse = await client.crm.associations.v4.basicApi.getPage( + fromObjectType as string, + fromObjectId as string, + toObjectType as string, + after, + limit, + ); + for(const association of reponse.results) { + results.push(association); + } + after = reponse.paging?.next?.after; + } while (after); + + return results; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/actions/remove-associations.ts b/packages/pieces/community/hubspot/src/lib/actions/remove-associations.ts new file mode 100644 index 0000000000..798a94b9a9 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/remove-associations.ts @@ -0,0 +1,108 @@ +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { + fromObjectTypeAssociationDropdown, + associationTypeDropdown, + toObjectIdsDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { AssociationSpecAssociationCategoryEnum } from '../common/types'; + +export const removeAssociationsAction = createAction({ + auth: hubspotAuth, + name: 'remove-associations', + displayName: 'Remove Associations', + description: 'Removes assosiations between objects', + props: { + fromObjectId: Property.ShortText({ + displayName: 'From Object ID', + description: 'The ID of the object you want to remove the association from.', + required: true, + }), + fromObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'From Object Type', + required: true, + description: 'The type of the object you want to remove the association from.', + }), + toObjectType: fromObjectTypeAssociationDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'To Object Type', + required: true, + description: "Type of the currently associated objects that you're removing the association from.", + }), + associationType: associationTypeDropdown, + toObjectIds: toObjectIdsDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'To Object IDs', + description: 'The IDs of the currently associated objects that you\'re removing the association from.', + required: true, + }), + }, + async run(context) { + const { fromObjectId, fromObjectType, toObjectType, associationType } = context.propsValue; + + const client = new Client({ accessToken: context.auth.access_token }); + + if(context.propsValue.toObjectIds === undefined) { + throw new Error('Please provide To Object IDs'); + } + + let toObjectIds: any[]; + if (Array.isArray(context.propsValue.toObjectIds)) { + toObjectIds = context.propsValue.toObjectIds; + } else { + try { + toObjectIds = JSON.parse(context.propsValue.toObjectIds); + } catch { + throw new Error( + `Please provide To Object IDs in a valid format. Provided : ${JSON.stringify( + context.propsValue.toObjectIds, + )}`, + ); + } + } + + // find the association category + const associationLabels = await client.crm.associations.v4.schema.definitionsApi.getAll( + fromObjectType as string, + toObjectType as string, + ); + const association = associationLabels.results.find( + (associationLabel) => associationLabel.typeId === associationType, + ); + if (!association) { + throw new Error( + `Association type ${associationType} not found for ${fromObjectType} to ${toObjectType}`, + ); + } + const associationCategory = association.category; + + const response = await client.crm.associations.v4.batchApi.archiveLabels( + fromObjectType as string, + toObjectType as string, + { + inputs: toObjectIds.map((objectId) => { + return { + _from: { + id: fromObjectId, + }, + to: { + id: objectId, + }, + types: [ + { + associationCategory: + associationCategory as unknown as AssociationSpecAssociationCategoryEnum, + associationTypeId: associationType, + }, + ], + }; + }), + }, + ); + + return {success: true}; + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index 65dc8a2677..56ba4f8437 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -131,3 +131,27 @@ export const DEFAULT_LINE_ITEM_PROPERTIES = [ 'hs_discount_percentage', 'hs_term_in_months', ]; + +export const STANDARD_OBJECT_TYPES = [ + { + label: "Contacts", + value: OBJECT_TYPE.CONTACT, + }, + { + label: "Companies", + value: OBJECT_TYPE.COMPANY, + }, + { + label: "Deals", + value: OBJECT_TYPE.DEAL, + }, + { + label: "Tickets", + value: OBJECT_TYPE.TICKET, + }, + { + label: "Line Items", + value: OBJECT_TYPE.LINE_ITEM, + }, + + ]; \ No newline at end of file diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index a6e048e0c5..dabd1048d3 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -22,6 +22,7 @@ import { DEFAULT_PRODUCT_PROPERTIES, DEFAULT_TICKET_PROPERTIES, OBJECT_TYPE, + STANDARD_OBJECT_TYPES, } from './constants'; import { Client } from '@hubspot/api-client'; import { hubspotAuth } from '../../'; @@ -538,7 +539,9 @@ export const workflowIdDropdown = Property.Dropdown({ } const token = (auth as OAuth2PropertyValue).access_token; - const workflowsResponse = await httpClient.sendRequest<{ workflows: WorkflowResponse[] }>({ + const workflowsResponse = await httpClient.sendRequest<{ + workflows: WorkflowResponse[]; + }>({ method: HttpMethod.GET, url: `https://api.hubapi.com/automation/v2/workflows`, authentication: { @@ -742,7 +745,6 @@ export const staticListsDropdown = Property.Dropdown({ } offset += 100; hasMore = response.body['has-more']; - } while (hasMore); return { @@ -752,6 +754,128 @@ export const staticListsDropdown = Property.Dropdown({ }, }); +export const fromObjectTypeAssociationDropdown = (params: DropdownParams) => + Property.Dropdown({ + displayName: params.displayName, + refreshers: [], + required: params.required, + description: params.description, + options: async ({ auth }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const customObjectsResponse = await client.crm.schemas.coreApi.getAll(); + + // + const options = customObjectsResponse.results.map((customObj) => { + return { + label: customObj.labels.plural ?? customObj.name, + value: customObj.objectTypeId, + }; + }); + return { + disabled: false, + options: [...STANDARD_OBJECT_TYPES, ...options], + }; + }, + }); + +export const associationTypeDropdown = Property.Dropdown({ + displayName: 'Type of the association', + refreshers: ['fromObjectType', 'toObjectType'], + required: true, + options: async ({ auth, fromObjectType, toObjectType }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + const associationLabels = await client.crm.associations.v4.schema.definitionsApi.getAll( + fromObjectType as string, + toObjectType as string, + ); + + const options = associationLabels.results.map((associationLabel) => { + return { + label: associationLabel.label ?? `${fromObjectType}_to_${toObjectType}`, + value: associationLabel.typeId, + }; + }); + + return { + disabled: false, + options, + }; + }, +}); + +export const toObjectIdsDropdown =(params: DropdownParams) => Property.MultiSelectDropdown({ + displayName: params.displayName, + description: params.description, + refreshers: ['toObjectType'], + required: params.required, + options: async ({ auth, toObjectType }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const limit = 100; + const options: DropdownOption[] = []; + let after: string | undefined; + do { + const response = await client.crm.objects.basicApi.getPage( + toObjectType as string, + limit, + after, + ); + for (const object of response.results) { + let labelName; + switch (toObjectType) { + case OBJECT_TYPE.CONTACT: + labelName = 'email'; + break; + case OBJECT_TYPE.COMPANY: + labelName = 'name'; + break; + case OBJECT_TYPE.DEAL: + labelName = 'dealname'; + break; + case OBJECT_TYPE.TICKET: + labelName = 'subject'; + break; + case OBJECT_TYPE.LINE_ITEM: + labelName = 'name'; + break; + } + options.push({ + label: object.properties[labelName!] ?? object.id, + value: object.id, + }); + } + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + }; + }, +}); + type DropdownParams = { objectType: OBJECT_TYPE; displayName: string; diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 7c23c5bf64..056b7242da 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -194,4 +194,10 @@ export enum HubspotFieldType { CheckBox = 'checkbox', Select = 'select', Radio = 'radio', -} \ No newline at end of file +} + +export declare enum AssociationSpecAssociationCategoryEnum { + HubspotDefined = "HUBSPOT_DEFINED", + UserDefined = "USER_DEFINED", + IntegratorDefined = "INTEGRATOR_DEFINED" +} From 69adbff0da4a73cebfa659f3d6420dbe77fa93ba Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 25 Dec 2024 15:44:24 +0530 Subject: [PATCH 40/60] feat(hubspot): new or updated company trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../lib/triggers/new-or-updated-company.ts | 144 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 0d1f033d94..2d71d47e3e 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -47,6 +47,7 @@ import { removeEmailSubscriptionAction } from './lib/actions/remove-email-subscr import { createAssociationsAction } from './lib/actions/create-associations'; import { removeAssociationsAction } from './lib/actions/remove-associations'; import { findAssociationsAction } from './lib/actions/find-associations'; +import { newOrUpdatedCompanyTrigger } from './lib/triggers/new-or-updated-company'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -140,6 +141,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newOrUpdatedCompanyTrigger, newTaskAdded, newCompanyAdded, newContactAdded, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts new file mode 100644 index 0000000000..e5593acc3e --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts @@ -0,0 +1,144 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +const polling: Polling< + PiecePropValueSchema, + { additionalPropertiesToRetrieve?: string[] | string } +> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); + const propertiesToRetrieve = [...defaultCompanyProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.companies.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newOrUpdatedCompanyTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-or-updated-company', + displayName: 'Company Recently Created or Updated', + description: 'Triggers when a company recenty created or updated', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-20T10:08:20.243Z', + archived: false, + id: '27508860336', + properties: { + about_us: 'Automation', + address: null, + address2: null, + annualrevenue: '500000', + city: null, + country: null, + createdate: '2024-12-20T10:08:20.243Z', + description: 'Automation', + domain: 'www.activepieces.com', + founded_year: null, + hs_createdate: null, + hs_lastmodifieddate: '2024-12-25T10:04:47.382Z', + hs_object_id: '27508860336', + industry: 'COMPUTER_SOFTWARE', + is_public: null, + lifecyclestage: 'lead', + name: 'Activepieces', + numberofemployees: '6', + owneremail: null, + ownername: null, + phone: null, + state: null, + timezone: null, + total_money_raised: null, + total_revenue: null, + type: 'OTHER', + web_technologies: null, + website: 'www.activepieces.com', + zip: null, + }, + updatedAt: '2024-12-25T10:04:47.382Z', + }, +}); From 5af08767a564eded9fcdebf5886ab2829d538b94 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 25 Dec 2024 16:11:40 +0530 Subject: [PATCH 41/60] feat(hubspot): new or updated contact action --- .../pieces/community/hubspot/src/index.ts | 2 + .../lib/triggers/new-or-updated-company.ts | 2 +- .../lib/triggers/new-or-updated-contact.ts | 144 ++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 2d71d47e3e..2a5aad56c5 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -48,6 +48,7 @@ import { createAssociationsAction } from './lib/actions/create-associations'; import { removeAssociationsAction } from './lib/actions/remove-associations'; import { findAssociationsAction } from './lib/actions/find-associations'; import { newOrUpdatedCompanyTrigger } from './lib/triggers/new-or-updated-company'; +import { newOrUpdatedContactTrigger } from './lib/triggers/new-or-updated-contact'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -142,6 +143,7 @@ export const hubspot = createPiece({ ], triggers: [ newOrUpdatedCompanyTrigger, + newOrUpdatedContactTrigger, newTaskAdded, newCompanyAdded, newContactAdded, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts index e5593acc3e..f39c44089d 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts @@ -67,7 +67,7 @@ export const newOrUpdatedCompanyTrigger = createTrigger({ auth: hubspotAuth, name: 'new-or-updated-company', displayName: 'Company Recently Created or Updated', - description: 'Triggers when a company recenty created or updated', + description: 'Triggers when a company recenty created or updated.', props: { markdown: Property.MarkDown({ variant: MarkdownVariant.INFO, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts new file mode 100644 index 0000000000..57478c14f9 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts @@ -0,0 +1,144 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +const polling: Polling< + PiecePropValueSchema, + { additionalPropertiesToRetrieve?: string[] | string } +> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + const propertiesToRetrieve = [...defaultContactProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.contacts.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-lastmodifieddate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newOrUpdatedContactTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-or-updated-contact', + displayName: 'Contact Recently Created or Updated', + description: 'Triggers when a contact recenty created or updated.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-20T10:08:20.243Z', + archived: false, + id: '27508860336', + properties: { + about_us: 'Automation', + address: null, + address2: null, + annualrevenue: '500000', + city: null, + country: null, + createdate: '2024-12-20T10:08:20.243Z', + description: 'Automation', + domain: 'www.activepieces.com', + founded_year: null, + hs_createdate: null, + hs_lastmodifieddate: '2024-12-25T10:04:47.382Z', + hs_object_id: '27508860336', + industry: 'COMPUTER_SOFTWARE', + is_public: null, + lifecyclestage: 'lead', + name: 'Activepieces', + numberofemployees: '6', + owneremail: null, + ownername: null, + phone: null, + state: null, + timezone: null, + total_money_raised: null, + total_revenue: null, + type: 'OTHER', + web_technologies: null, + website: 'www.activepieces.com', + zip: null, + }, + updatedAt: '2024-12-25T10:04:47.382Z', + }, +}); From 25b604a1cd42446383b87d0df19799b171e88c28 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Wed, 25 Dec 2024 16:44:11 +0530 Subject: [PATCH 42/60] feat(hubspot): new or update line item action --- .../pieces/community/hubspot/src/index.ts | 4 + .../lib/triggers/new-or-updated-contact.ts | 233 +++++++++--------- .../lib/triggers/new-or-updated-line-item.ts | 133 ++++++++++ .../lib/triggers/new-or-updated-product.ts | 122 +++++++++ 4 files changed, 374 insertions(+), 118 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 2a5aad56c5..ebed41dc25 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -49,6 +49,8 @@ import { removeAssociationsAction } from './lib/actions/remove-associations'; import { findAssociationsAction } from './lib/actions/find-associations'; import { newOrUpdatedCompanyTrigger } from './lib/triggers/new-or-updated-company'; import { newOrUpdatedContactTrigger } from './lib/triggers/new-or-updated-contact'; +import { newOrUpdatedProductTrigger } from './lib/triggers/new-or-updated-product'; +import { newOrUpdatedLineItemTrigger } from './lib/triggers/new-or-updated-line-item'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -144,11 +146,13 @@ export const hubspot = createPiece({ triggers: [ newOrUpdatedCompanyTrigger, newOrUpdatedContactTrigger, + newOrUpdatedLineItemTrigger, newTaskAdded, newCompanyAdded, newContactAdded, newDealAdded, newTicketAdded, dealStageUpdatedTrigger, + newOrUpdatedProductTrigger ], }); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts index 57478c14f9..75f8d10b8a 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts @@ -1,10 +1,10 @@ import { MarkdownVariant } from '@activepieces/shared'; import { hubspotAuth } from '../../'; import { - createTrigger, - PiecePropValueSchema, - Property, - TriggerStrategy, + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; @@ -14,131 +14,128 @@ import { FilterOperatorEnum } from '../common/types'; import dayjs from 'dayjs'; const polling: Polling< - PiecePropValueSchema, - { additionalPropertiesToRetrieve?: string[] | string } + PiecePropValueSchema, + { additionalPropertiesToRetrieve?: string[] | string } > = { - strategy: DedupeStrategy.TIMEBASED, - async items({ auth, propsValue, lastFetchEpochMS }) { - const client = new Client({ accessToken: auth.access_token }); + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); - // Extract properties once to avoid recomputation - const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; - const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); - const propertiesToRetrieve = [...defaultContactProperties, ...additionalProperties]; + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + const propertiesToRetrieve = [...defaultContactProperties, ...additionalProperties]; - const items = []; - let after; + const items = []; + let after; - do { - const isTest = lastFetchEpochMS === 0; - const response = await client.crm.contacts.searchApi.doSearch({ - limit: isTest ? 10 : 100, - properties: propertiesToRetrieve, - sorts: ['-lastmodifieddate'], - filterGroups: isTest - ? [] - : [ - { - filters: [ - { - propertyName: 'lastmodifieddate', - operator: FilterOperatorEnum.Gt, - value: lastFetchEpochMS.toString(), - }, - ], - }, - ], - }); - after = response.paging?.next?.after; - items.push(...response.results); + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.contacts.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-lastmodifieddate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); - // Stop fetching if it's a test - if (isTest) break; - } while (after); + // Stop fetching if it's a test + if (isTest) break; + } while (after); - return items.map((item) => ({ - epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), - data: item, - })); - }, + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), + data: item, + })); + }, }; export const newOrUpdatedContactTrigger = createTrigger({ - auth: hubspotAuth, - name: 'new-or-updated-contact', - displayName: 'Contact Recently Created or Updated', - description: 'Triggers when a contact recenty created or updated.', - props: { - markdown: Property.MarkDown({ - variant: MarkdownVariant.INFO, - value: `### Properties to retrieve: + auth: hubspotAuth, + name: 'new-or-updated-contact', + displayName: 'Contact Recently Created or Updated', + description: 'Triggers when a contact recenty created or updated.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry **Specify here a list of additional properties to retrieve**`, - }), - additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ - objectType: OBJECT_TYPE.CONTACT, - displayName: 'Additional properties to retrieve', - required: false, - }), - }, - type: TriggerStrategy.POLLING, - async onEnable(context) { - await pollingHelper.onEnable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - async onDisable(context) { - await pollingHelper.onDisable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - async test(context) { - return await pollingHelper.test(polling, context); - }, - async run(context) { - return await pollingHelper.poll(polling, context); - }, - sampleData: { - createdAt: '2024-12-20T10:08:20.243Z', - archived: false, - id: '27508860336', - properties: { - about_us: 'Automation', - address: null, - address2: null, - annualrevenue: '500000', - city: null, - country: null, - createdate: '2024-12-20T10:08:20.243Z', - description: 'Automation', - domain: 'www.activepieces.com', - founded_year: null, - hs_createdate: null, - hs_lastmodifieddate: '2024-12-25T10:04:47.382Z', - hs_object_id: '27508860336', - industry: 'COMPUTER_SOFTWARE', - is_public: null, - lifecyclestage: 'lead', - name: 'Activepieces', - numberofemployees: '6', - owneremail: null, - ownername: null, - phone: null, - state: null, - timezone: null, - total_money_raised: null, - total_revenue: null, - type: 'OTHER', - web_technologies: null, - website: 'www.activepieces.com', - zip: null, - }, - updatedAt: '2024-12-25T10:04:47.382Z', - }, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-06T10:52:58.322Z', + archived: false, + id: '82665997707', + properties: { + address: null, + annualrevenue: null, + city: 'Brisbane', + company: 'HubSpot', + country: null, + createdate: '2024-12-06T10:52:58.322Z', + email: 'emailmaria@hubspot.com', + fax: null, + firstname: 'Maria', + hs_createdate: null, + hs_email_domain: 'hubspot.com', + hs_language: null, + hs_object_id: '82665997707', + hs_persona: null, + industry: null, + jobtitle: 'Salesperson', + lastmodifieddate: '2024-12-20T12:50:35.201Z', + lastname: 'Johnson (Sample Contact)', + lifecyclestage: 'lead', + mobilephone: null, + numemployees: null, + phone: null, + salutation: null, + state: null, + website: 'http://www.HubSpot.com', + zip: null, + }, + updatedAt: '2024-12-20T12:50:35.201Z', + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts new file mode 100644 index 0000000000..98d54a9618 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts @@ -0,0 +1,133 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +const polling: Polling< + PiecePropValueSchema, + { additionalPropertiesToRetrieve?: string[] | string } +> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultLineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + const propertiesToRetrieve = [...defaultLineItemProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.lineItems.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newOrUpdatedLineItemTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-or-updated-line-item', + displayName: 'Line Item Recently Created or Updated', + description: 'Triggers when a line item recenty created or updated.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-24T16:17:34.281Z', + archived: false, + id: '26854130802', + properties: { + amount: '15.00', + createdate: '2024-12-24T16:17:34.281Z', + description: 'Chair', + discount: null, + hs_cost_of_goods_sold: '10', + hs_discount_percentage: null, + hs_images: null, + hs_lastmodifieddate: '2024-12-24T16:17:50.488Z', + hs_line_item_currency_code: 'USD', + hs_object_id: '26854130802', + hs_product_id: '17602013482', + hs_sku: 'ch-100', + hs_term_in_months: null, + hs_url: null, + name: 'Chair', + price: '15.0', + quantity: '1', + tax: null, + }, + updatedAt: '2024-12-24T16:17:50.488Z', + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts new file mode 100644 index 0000000000..d6a18f2707 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts @@ -0,0 +1,122 @@ +import { MarkdownVariant } from '@activepieces/shared'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +const polling: Polling< + PiecePropValueSchema, + { additionalPropertiesToRetrieve?: string[] | string } +> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); + const propertiesToRetrieve = [...defaultProductProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.products.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newOrUpdatedProductTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-or-updated-product', + displayName: 'Product Recently Created or Updated', + description: 'Triggers when a product recenty created or updated.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-18T16:10:27.710Z', + archived: false, + id: '17602013482', + properties: { + createdate: '2024-12-18T16:10:27.710Z', + description: 'Chair', + hs_lastmodifieddate: '2024-12-23T08:13:30.314Z', + hs_object_id: '17602013482', + name: 'Chair', + price: '15.0', + tax: null, + }, + updatedAt: '2024-12-23T08:13:30.314Z', + }, +}); From a19a82687f8939a384495640b6d3decab2770672 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 13:31:57 +0530 Subject: [PATCH 43/60] feat(hubspot): contact property changed trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../triggers/new-contact-property-changed.ts | 183 ++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index ebed41dc25..51f29efe5e 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -51,6 +51,7 @@ import { newOrUpdatedCompanyTrigger } from './lib/triggers/new-or-updated-compan import { newOrUpdatedContactTrigger } from './lib/triggers/new-or-updated-contact'; import { newOrUpdatedProductTrigger } from './lib/triggers/new-or-updated-product'; import { newOrUpdatedLineItemTrigger } from './lib/triggers/new-or-updated-line-item'; +import { newContactPropertyChangedTrigger } from './lib/triggers/new-contact-property-changed'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -150,6 +151,7 @@ export const hubspot = createPiece({ newTaskAdded, newCompanyAdded, newContactAdded, + newContactPropertyChangedTrigger, newDealAdded, newTicketAdded, dealStageUpdatedTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts new file mode 100644 index 0000000000..a1a876857d --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts @@ -0,0 +1,183 @@ +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { Client } from '@hubspot/api-client'; +import dayjs from 'dayjs'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + propertyName?: string | string[]; + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const propertyToCheck = propsValue.propertyName as string; + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + const propertiesToRetrieve = [...defaultCompanyProperties, ...additionalProperties]; + + const items = []; + // For test, we only fetch 10 contacts + if (lastFetchEpochMS === 0) { + const response = await client.crm.contacts.searchApi.doSearch({ + limit: 10, + properties: propertiesToRetrieve, + sorts: ['-lastmodifieddate'], + }); + items.push(...response.results); + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), + data: item, + })); + } + //fetch updated contacts + const updatedContacts = []; + let after; + do { + const response = await client.crm.contacts.searchApi.doSearch({ + limit: 100, + sorts: ['-lastmodifieddate'], + filterGroups: [ + { + filters: [ + { + propertyName: propertyToCheck, + operator: FilterOperatorEnum.HasProperty, + }, + { + propertyName: 'lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + updatedContacts.push(...response.results); + } while (after); + + if (updatedContacts.length === 0) { + return []; + } + + // Fetch contacts with property history + const updatedContcatsWithPropertyHistory = await client.crm.contacts.batchApi.read({ + propertiesWithHistory: [propertyToCheck], + properties: propertiesToRetrieve, + inputs: updatedContacts.map((contact) => { + return { + id: contact.id, + }; + }), + }); + + for (const contact of updatedContcatsWithPropertyHistory.results) { + const history = contact.propertiesWithHistory?.[propertyToCheck]; + if (!history || history.length === 0) { + continue; + } + const propertyLastModifiedDateTimeStamp = dayjs(history[0].timestamp).valueOf(); + if (propertyLastModifiedDateTimeStamp > lastFetchEpochMS) { + const { propertiesWithHistory, ...item } = contact; + items.push(item); + } + } + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), + data: item, + }));; + }, +}; + +export const newContactPropertyChangedTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-contact-property-changed', + displayName: 'New Contact Property Change', + description: 'Triggers when a specified property is updated on a contact.', + props: { + propertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Property Name', + required: true, + }, + true, + true, + ), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-06T10:52:58.322Z', + archived: false, + id: '82665997707', + properties: { + address: null, + annualrevenue: null, + city: 'Brisbane', + company: 'HubSpot', + country: null, + createdate: '2024-12-06T10:52:58.322Z', + email: 'emailmaria@hubspot.com', + fax: null, + firstname: 'Maria', + hs_createdate: null, + hs_email_domain: 'hubspot.com', + hs_language: null, + hs_object_id: '82665997707', + hs_persona: null, + industry: null, + jobtitle: 'Salesperson', + lastmodifieddate: '2024-12-20T12:50:35.201Z', + lastname: 'Johnson (Sample Contact)', + lifecyclestage: 'lead', + mobilephone: null, + numemployees: null, + phone: null, + salutation: null, + state: null, + website: 'http://www.HubSpot.com', + zip: null, + }, + updatedAt: '2024-12-20T12:50:35.201Z', + }, +}); From 3c58e1da778d691216472eede1661b27d8cfd7c7 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 13:57:04 +0530 Subject: [PATCH 44/60] feat(hubspot): ticket property changed trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../triggers/new-contact-property-changed.ts | 14 +- .../triggers/new-ticket-property-changed.ts | 181 ++++++++++++++++++ 3 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 51f29efe5e..39cc09a574 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -52,6 +52,7 @@ import { newOrUpdatedContactTrigger } from './lib/triggers/new-or-updated-contac import { newOrUpdatedProductTrigger } from './lib/triggers/new-or-updated-product'; import { newOrUpdatedLineItemTrigger } from './lib/triggers/new-or-updated-line-item'; import { newContactPropertyChangedTrigger } from './lib/triggers/new-contact-property-changed'; +import { newTicketPropertyChangedTrigger } from './lib/triggers/new-ticket-property-changed'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -152,6 +153,7 @@ export const hubspot = createPiece({ newCompanyAdded, newContactAdded, newContactPropertyChangedTrigger, + newTicketPropertyChangedTrigger, newDealAdded, newTicketAdded, dealStageUpdatedTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts index a1a876857d..f47986bbae 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts @@ -2,6 +2,7 @@ import { hubspotAuth } from '../../'; import { createTrigger, PiecePropValueSchema, + Property, TriggerStrategy, } from '@activepieces/pieces-framework'; import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; @@ -11,6 +12,7 @@ import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-com import { Client } from '@hubspot/api-client'; import dayjs from 'dayjs'; import { FilterOperatorEnum } from '../common/types'; +import { MarkdownVariant } from '@activepieces/shared'; type Props = { propertyName?: string | string[]; @@ -21,7 +23,7 @@ const polling: Polling, Props> = { strategy: DedupeStrategy.TIMEBASED, async items({ auth, propsValue, lastFetchEpochMS }) { const client = new Client({ accessToken: auth.access_token }); - + const propertyToCheck = propsValue.propertyName as string; // Extract properties once to avoid recomputation @@ -100,7 +102,7 @@ const polling: Polling, Props> = { return items.map((item) => ({ epochMilliSeconds: dayjs(item.properties['lastmodifieddate']).valueOf(), data: item, - }));; + })); }, }; @@ -119,6 +121,14 @@ export const newContactPropertyChangedTrigger = createTrigger({ true, true, ), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ objectType: OBJECT_TYPE.CONTACT, displayName: 'Additional properties to retrieve', diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts new file mode 100644 index 0000000000..7448bdfab1 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts @@ -0,0 +1,181 @@ +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { Client } from '@hubspot/api-client'; +import dayjs from 'dayjs'; +import { FilterOperatorEnum } from '../common/types'; +import { MarkdownVariant } from '@activepieces/shared'; + +type Props = { + propertyName?: string | string[]; + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const propertyToCheck = propsValue.propertyName as string; + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); + const propertiesToRetrieve = [...defaultTicketProperties, ...additionalProperties]; + + const items = []; + // For test, we only fetch 10 tickets + if (lastFetchEpochMS === 0) { + const response = await client.crm.tickets.searchApi.doSearch({ + limit: 10, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + }); + items.push(...response.results); + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + } + //fetch updated tickets + const updatedTickets = []; + let after; + do { + const response = await client.crm.tickets.searchApi.doSearch({ + limit: 100, + sorts: ['-hs_lastmodifieddate'], + filterGroups: [ + { + filters: [ + { + propertyName: propertyToCheck, + operator: FilterOperatorEnum.HasProperty, + }, + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + updatedTickets.push(...response.results); + } while (after); + + if (updatedTickets.length === 0) { + return []; + } + + // Fetch tickets with property history + const updatedTicketsWithPropertyHistory = await client.crm.tickets.batchApi.read({ + propertiesWithHistory: [propertyToCheck], + properties: propertiesToRetrieve, + inputs: updatedTickets.map((ticket) => { + return { + id: ticket.id, + }; + }), + }); + + for (const ticket of updatedTicketsWithPropertyHistory.results) { + const history = ticket.propertiesWithHistory?.[propertyToCheck]; + if (!history || history.length === 0) { + continue; + } + const propertyLastModifiedDateTimeStamp = dayjs(history[0].timestamp).valueOf(); + if (propertyLastModifiedDateTimeStamp > lastFetchEpochMS) { + const { propertiesWithHistory, ...item } = ticket; + items.push(item); + } + } + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newTicketPropertyChangedTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-ticket-property-changed', + displayName: 'New Ticket Property Change', + description: 'Triggers when a specified property is updated on a ticket.', + props: { + propertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.TICKET, + displayName: 'Property Name', + required: true, + }, + true, + true, + ), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-21T14:23:38.368Z', + archived: false, + id: '18092693102', + properties: { + content: null, + createdate: '2024-12-21T14:23:38.368Z', + hs_lastmodifieddate: '2024-12-26T08:11:34.374Z', + hs_object_id: '18092693102', + hs_pipeline: '0', + hs_pipeline_stage: '1', + hs_resolution: 'ISSUE_FIXED', + hs_ticket_category: null, + hs_ticket_id: '18092693102', + hs_ticket_priority: null, + hubspot_owner_id: null, + hubspot_team_id: null, + source_type: null, + subject: 'NEW', + }, + updatedAt: '2024-12-26T08:11:34.374Z', + }, +}); From ccf0c58d0e3f78cf7545941d0186304ed0dfc5bf Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 14:37:55 +0530 Subject: [PATCH 45/60] feat(hubspot): company property changed trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../triggers/new-company-propety-changed.ts | 153 ++++++++++++++++++ .../triggers/new-contact-property-changed.ts | 22 +-- .../triggers/new-ticket-property-changed.ts | 23 +-- 4 files changed, 159 insertions(+), 41 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 39cc09a574..33e8e9ff57 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -53,6 +53,7 @@ import { newOrUpdatedProductTrigger } from './lib/triggers/new-or-updated-produc import { newOrUpdatedLineItemTrigger } from './lib/triggers/new-or-updated-line-item'; import { newContactPropertyChangedTrigger } from './lib/triggers/new-contact-property-changed'; import { newTicketPropertyChangedTrigger } from './lib/triggers/new-ticket-property-changed'; +import { newCompanyPropertyChangedTrigger } from './lib/triggers/new-company-propety-changed'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -154,6 +155,7 @@ export const hubspot = createPiece({ newContactAdded, newContactPropertyChangedTrigger, newTicketPropertyChangedTrigger, + newCompanyPropertyChangedTrigger, newDealAdded, newTicketAdded, dealStageUpdatedTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts new file mode 100644 index 0000000000..fecaa1f569 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts @@ -0,0 +1,153 @@ +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { Client } from '@hubspot/api-client'; +import dayjs from 'dayjs'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + propertyName?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const propertyToCheck = propsValue.propertyName as string; + + const propertiesToRetrieve = [propertyToCheck]; + + const items = []; + // For test, we only fetch 10 comapnies + if (lastFetchEpochMS === 0) { + const response = await client.crm.companies.searchApi.doSearch({ + limit: 10, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + }); + items.push(...response.results); + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + } + //fetch updated companies + const updatedComapnies = []; + let after; + do { + const response = await client.crm.companies.searchApi.doSearch({ + limit: 100, + sorts: ['-hs_lastmodifieddate'], + filterGroups: [ + { + filters: [ + { + propertyName: propertyToCheck, + operator: FilterOperatorEnum.HasProperty, + }, + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + updatedComapnies.push(...response.results); + } while (after); + + if (updatedComapnies.length === 0) { + return []; + } + + // Fetch companies with property history + const updatedComapniesWithPropertyHistory = await client.crm.companies.batchApi.read({ + propertiesWithHistory: [propertyToCheck], + properties: propertiesToRetrieve, + inputs: updatedComapnies.map((company) => { + return { + id: company.id, + }; + }), + }); + + for (const company of updatedComapniesWithPropertyHistory.results) { + const history = company.propertiesWithHistory?.[propertyToCheck]; + if (!history || history.length === 0) { + continue; + } + const propertyLastModifiedDateTimeStamp = dayjs(history[0].timestamp).valueOf(); + if (propertyLastModifiedDateTimeStamp > lastFetchEpochMS) { + const { propertiesWithHistory, ...item } = company; + items.push(item); + } + } + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newCompanyPropertyChangedTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-company-property-changed', + displayName: 'New Company Property Change', + description: 'Triggers when a specified property is updated on a company.', + props: { + propertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Property Name', + required: true, + }, + true, + true, + ), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + id: '27656515180', + properties: { + createdate: '2024-12-26T08:36:10.463Z', + domain: 'www.activepieces.com', + hs_lastmodifieddate: '2024-12-26T08:58:48.657Z', + hs_object_id: '27656515180', + name: 'Activepieces', + }, + createdAt: '2024-12-26T08:36:10.463Z', + updatedAt: '2024-12-26T08:58:48.657Z', + archived: false, + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts index f47986bbae..fc0469cef0 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts @@ -2,21 +2,18 @@ import { hubspotAuth } from '../../'; import { createTrigger, PiecePropValueSchema, - Property, TriggerStrategy, } from '@activepieces/pieces-framework'; -import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { standardObjectPropertiesDropdown } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; import { Client } from '@hubspot/api-client'; import dayjs from 'dayjs'; import { FilterOperatorEnum } from '../common/types'; -import { MarkdownVariant } from '@activepieces/shared'; type Props = { propertyName?: string | string[]; - additionalPropertiesToRetrieve?: string | string[]; }; const polling: Polling, Props> = { @@ -27,9 +24,7 @@ const polling: Polling, Props> = { const propertyToCheck = propsValue.propertyName as string; // Extract properties once to avoid recomputation - const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; - const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); - const propertiesToRetrieve = [...defaultCompanyProperties, ...additionalProperties]; + const propertiesToRetrieve = [propertyToCheck]; const items = []; // For test, we only fetch 10 contacts @@ -121,19 +116,6 @@ export const newContactPropertyChangedTrigger = createTrigger({ true, true, ), - markdown: Property.MarkDown({ - variant: MarkdownVariant.INFO, - value: `### Properties to retrieve: - - firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry - - **Specify here a list of additional properties to retrieve**`, - }), - additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ - objectType: OBJECT_TYPE.CONTACT, - displayName: 'Additional properties to retrieve', - required: false, - }), }, type: TriggerStrategy.POLLING, async onEnable(context) { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts index 7448bdfab1..1f1d11e1e3 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts @@ -2,21 +2,18 @@ import { hubspotAuth } from '../../'; import { createTrigger, PiecePropValueSchema, - Property, TriggerStrategy, } from '@activepieces/pieces-framework'; -import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { standardObjectPropertiesDropdown } from '../common/props'; import { OBJECT_TYPE } from '../common/constants'; import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; import { Client } from '@hubspot/api-client'; import dayjs from 'dayjs'; import { FilterOperatorEnum } from '../common/types'; -import { MarkdownVariant } from '@activepieces/shared'; type Props = { propertyName?: string | string[]; - additionalPropertiesToRetrieve?: string | string[]; }; const polling: Polling, Props> = { @@ -26,10 +23,7 @@ const polling: Polling, Props> = { const propertyToCheck = propsValue.propertyName as string; - // Extract properties once to avoid recomputation - const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; - const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); - const propertiesToRetrieve = [...defaultTicketProperties, ...additionalProperties]; + const propertiesToRetrieve = [propertyToCheck]; const items = []; // For test, we only fetch 10 tickets @@ -121,19 +115,6 @@ export const newTicketPropertyChangedTrigger = createTrigger({ true, true, ), - markdown: Property.MarkDown({ - variant: MarkdownVariant.INFO, - value: `### Properties to retrieve: - - subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id - - **Specify here a list of additional properties to retrieve**`, - }), - additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ - objectType: OBJECT_TYPE.TICKET, - displayName: 'Additional properties to retrieve', - required: false, - }), }, type: TriggerStrategy.POLLING, async onEnable(context) { From 2443ddb3cda6f26d91ecf39918f8c3d139e64f48 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 15:13:59 +0530 Subject: [PATCH 46/60] feat(hubspot): custom object property change trigger --- .../pieces/community/hubspot/src/index.ts | 16 +- ...anged.ts => new-company-propety-change.ts} | 6 +- ...nged.ts => new-contact-property-change.ts} | 6 +- .../new-custom-object-property-change.ts | 154 ++++++++++++++++++ .../lib/triggers/new-deal-property-change.ts | 152 +++++++++++++++++ ...anged.ts => new-ticket-property-change.ts} | 6 +- 6 files changed, 325 insertions(+), 15 deletions(-) rename packages/pieces/community/hubspot/src/lib/triggers/{new-company-propety-changed.ts => new-company-propety-change.ts} (96%) rename packages/pieces/community/hubspot/src/lib/triggers/{new-contact-property-changed.ts => new-contact-property-change.ts} (97%) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts rename packages/pieces/community/hubspot/src/lib/triggers/{new-ticket-property-changed.ts => new-ticket-property-change.ts} (96%) diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 33e8e9ff57..3d41e5961a 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -51,9 +51,11 @@ import { newOrUpdatedCompanyTrigger } from './lib/triggers/new-or-updated-compan import { newOrUpdatedContactTrigger } from './lib/triggers/new-or-updated-contact'; import { newOrUpdatedProductTrigger } from './lib/triggers/new-or-updated-product'; import { newOrUpdatedLineItemTrigger } from './lib/triggers/new-or-updated-line-item'; -import { newContactPropertyChangedTrigger } from './lib/triggers/new-contact-property-changed'; -import { newTicketPropertyChangedTrigger } from './lib/triggers/new-ticket-property-changed'; -import { newCompanyPropertyChangedTrigger } from './lib/triggers/new-company-propety-changed'; +import { newContactPropertyChangeTrigger } from './lib/triggers/new-contact-property-change'; +import { newTicketPropertyChangeTrigger } from './lib/triggers/new-ticket-property-change'; +import { newCompanyPropertyChangeTrigger } from './lib/triggers/new-company-propety-change'; +import { newDealPropertyChangeTrigger } from './lib/triggers/new-deal-property-change'; +import { newCustomObjectPropertyChangeTrigger } from './lib/triggers/new-custom-object-property-change'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -153,9 +155,11 @@ export const hubspot = createPiece({ newTaskAdded, newCompanyAdded, newContactAdded, - newContactPropertyChangedTrigger, - newTicketPropertyChangedTrigger, - newCompanyPropertyChangedTrigger, + newContactPropertyChangeTrigger, + newCustomObjectPropertyChangeTrigger, + newDealPropertyChangeTrigger, + newTicketPropertyChangeTrigger, + newCompanyPropertyChangeTrigger, newDealAdded, newTicketAdded, dealStageUpdatedTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts similarity index 96% rename from packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts rename to packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts index fecaa1f569..dbaf8f47d8 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts @@ -1,4 +1,4 @@ -import { hubspotAuth } from '../../'; +import { hubspotAuth } from '../..'; import { createTrigger, PiecePropValueSchema, @@ -100,9 +100,9 @@ const polling: Polling, Props> = { }, }; -export const newCompanyPropertyChangedTrigger = createTrigger({ +export const newCompanyPropertyChangeTrigger = createTrigger({ auth: hubspotAuth, - name: 'new-company-property-changed', + name: 'new-company-property-change', displayName: 'New Company Property Change', description: 'Triggers when a specified property is updated on a company.', props: { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts similarity index 97% rename from packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts rename to packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts index fc0469cef0..ed8c103f4c 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts @@ -1,4 +1,4 @@ -import { hubspotAuth } from '../../'; +import { hubspotAuth } from '../..'; import { createTrigger, PiecePropValueSchema, @@ -101,9 +101,9 @@ const polling: Polling, Props> = { }, }; -export const newContactPropertyChangedTrigger = createTrigger({ +export const newContactPropertyChangeTrigger = createTrigger({ auth: hubspotAuth, - name: 'new-contact-property-changed', + name: 'new-contact-property-change', displayName: 'New Contact Property Change', description: 'Triggers when a specified property is updated on a contact.', props: { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts new file mode 100644 index 0000000000..4c73c7e6ac --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts @@ -0,0 +1,154 @@ +import { hubspotAuth } from '../..'; +import { + createTrigger, + DynamicPropsValue, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { + customObjectDropdown, + customObjectPropertiesDropdown, + standardObjectPropertiesDropdown, +} from '../common/props'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { Client } from '@hubspot/api-client'; +import dayjs from 'dayjs'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + customObjectType?: string; + propertyName?: DynamicPropsValue; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const customObjectType = propsValue.customObjectType as string; + const propertyToCheck = propsValue.propertyName?.['values'] as string; + + const propertiesToRetrieve = [propertyToCheck]; + + const items = []; + // For test, we only fetch 10 custom objects + if (lastFetchEpochMS === 0) { + const response = await client.crm.objects.searchApi.doSearch(customObjectType, { + limit: 10, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + }); + items.push(...response.results); + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + } + //fetch updated custom objects + const updatedCustomObjects = []; + let after; + do { + const response = await client.crm.objects.searchApi.doSearch(customObjectType, { + limit: 100, + sorts: ['-hs_lastmodifieddate'], + filterGroups: [ + { + filters: [ + { + propertyName: propertyToCheck, + operator: FilterOperatorEnum.HasProperty, + }, + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + updatedCustomObjects.push(...response.results); + } while (after); + + if (updatedCustomObjects.length === 0) { + return []; + } + + // Fetch custom objects with property history + const updatedCustomObjectsWithPropertyHistory = await client.crm.objects.batchApi.read( + customObjectType, + { + propertiesWithHistory: [propertyToCheck], + properties: propertiesToRetrieve, + inputs: updatedCustomObjects.map((customObject) => { + return { + id: customObject.id, + }; + }), + }, + ); + + for (const customObject of updatedCustomObjectsWithPropertyHistory.results) { + const history = customObject.propertiesWithHistory?.[propertyToCheck]; + if (!history || history.length === 0) { + continue; + } + const propertyLastModifiedDateTimeStamp = dayjs(history[0].timestamp).valueOf(); + if (propertyLastModifiedDateTimeStamp > lastFetchEpochMS) { + const { propertiesWithHistory, ...item } = customObject; + items.push(item); + } + } + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newCustomObjectPropertyChangeTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-custom-object-property-change', + displayName: 'New Custom Object Property Change', + description: 'Triggers when a specified property is updated on a custom object.', + props: { + customObjectType: customObjectDropdown, + propertyName: customObjectPropertiesDropdown('Property Name', true, true), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-22T15:20:16.121Z', + archived: false, + id: '21583829313', + properties: { + hs_createdate: '2024-12-22T15:20:16.121Z', + hs_lastmodifieddate: '2024-12-22T15:20:16.818Z', + hs_object_id: '21583829313', + pet_name: 'Oreo', + }, + updatedAt: '2024-12-22T15:20:16.818Z', + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts new file mode 100644 index 0000000000..ea1e1509a1 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts @@ -0,0 +1,152 @@ +import { hubspotAuth } from '../..'; +import { + createTrigger, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { Client } from '@hubspot/api-client'; +import dayjs from 'dayjs'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + propertyName?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const propertyToCheck = propsValue.propertyName as string; + + const propertiesToRetrieve = [propertyToCheck]; + + const items = []; + // For test, we only fetch 10 deals + if (lastFetchEpochMS === 0) { + const response = await client.crm.deals.searchApi.doSearch({ + limit: 10, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + }); + items.push(...response.results); + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + } + //fetch updated deals + const updatedDeals = []; + let after; + do { + const response = await client.crm.deals.searchApi.doSearch({ + limit: 100, + sorts: ['-hs_lastmodifieddate'], + filterGroups: [ + { + filters: [ + { + propertyName: propertyToCheck, + operator: FilterOperatorEnum.HasProperty, + }, + { + propertyName: 'hs_lastmodifieddate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + updatedDeals.push(...response.results); + } while (after); + + if (updatedDeals.length === 0) { + return []; + } + + // Fetch deals with property history + const updatedDealsWithPropertyHistory = await client.crm.deals.batchApi.read({ + propertiesWithHistory: [propertyToCheck], + properties: propertiesToRetrieve, + inputs: updatedDeals.map((deal) => { + return { + id: deal.id, + }; + }), + }); + + for (const deal of updatedDealsWithPropertyHistory.results) { + const history = deal.propertiesWithHistory?.[propertyToCheck]; + if (!history || history.length === 0) { + continue; + } + const propertyLastModifiedDateTimeStamp = dayjs(history[0].timestamp).valueOf(); + if (propertyLastModifiedDateTimeStamp > lastFetchEpochMS) { + const { propertiesWithHistory, ...item } = deal; + items.push(item); + } + } + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), + data: item, + })); + }, +}; + +export const newDealPropertyChangeTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-deal-property-change', + displayName: 'New Deal Property Change', + description: 'Triggers when a specified property is updated on a deal.', + props: { + propertyName: standardObjectPropertiesDropdown( + { + objectType: OBJECT_TYPE.DEAL, + displayName: 'Property Name', + required: true, + }, + true, + true, + ), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-23T08:19:21.614Z', + archived: false, + id: '30906615140', + properties: { + amount: '150', + createdate: '2024-12-23T08:19:21.614Z', + hs_lastmodifieddate: '2024-12-26T09:30:44.578Z', + hs_object_id: '30906615140', + }, + updatedAt: '2024-12-26T09:30:44.578Z', + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts similarity index 96% rename from packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts rename to packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts index 1f1d11e1e3..c14332e889 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-changed.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts @@ -1,4 +1,4 @@ -import { hubspotAuth } from '../../'; +import { hubspotAuth } from '../..'; import { createTrigger, PiecePropValueSchema, @@ -100,9 +100,9 @@ const polling: Polling, Props> = { }, }; -export const newTicketPropertyChangedTrigger = createTrigger({ +export const newTicketPropertyChangeTrigger = createTrigger({ auth: hubspotAuth, - name: 'new-ticket-property-changed', + name: 'new-ticket-property-change', displayName: 'New Ticket Property Change', description: 'Triggers when a specified property is updated on a ticket.', props: { From 21e3e18fe7bf67878aa675b9761c8c88130570a8 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 16:32:26 +0530 Subject: [PATCH 47/60] feat(hubspot): new line item trigger --- .../hubspot/src/lib/triggers/new-line-item.ts | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts new file mode 100644 index 0000000000..9dc5b5705e --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts @@ -0,0 +1,137 @@ +import { hubspotAuth } from '../../'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultLineItemProperties = getDefaultPropertiesForObject(OBJECT_TYPE.LINE_ITEM); + const propertiesToRetrieve = [...defaultLineItemProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.lineItems.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newLineItemTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-line-item', + displayName: 'New Line Item', + description: 'Triggers when new line item is available.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, description, price, quantity, amount, discount, tax, createdate, hs_object_id, hs_product_id, hs_images, hs_lastmodifieddate, hs_line_item_currency_code, hs_sku, hs_url, hs_cost_of_goods_sold, hs_discount_percentage, hs_term_in_months + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.LINE_ITEM, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-25T11:08:54.763Z', + archived: false, + id: '26882583648', + properties: { + amount: '5.00', + createdate: '2024-12-25T11:08:54.763Z', + description: 'CHAIR', + discount: '10', + hs_cost_of_goods_sold: '10', + hs_discount_percentage: null, + hs_images: null, + hs_lastmodifieddate: '2024-12-25T11:10:02.750Z', + hs_line_item_currency_code: null, + hs_object_id: '26882583648', + hs_product_id: '17602013482', + hs_sku: 'fb-100', + hs_tax_amount: null, + hs_tcv: '5.00', + hs_term_in_months: null, + hs_total_discount: '10.00', + hs_url: null, + name: 'Chair', + price: '15.0', + quantity: null, + tax: null, + }, + updatedAt: '2024-12-25T11:10:02.750Z', + }, +}); From c006e13be770090478e3db1a2fbb65ba2593f4cb Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 16:32:50 +0530 Subject: [PATCH 48/60] feat(hubspot): new custom object trigger --- .../src/lib/triggers/new-custom-object.ts | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts new file mode 100644 index 0000000000..5e67c7e0aa --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts @@ -0,0 +1,131 @@ +import { hubspotAuth } from '../../'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { + createTrigger, + DynamicPropsValue, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { customObjectDropdown, customObjectPropertiesDropdown } from '../common/props'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +type Props = { + customObjectType?: string; + additionalPropertiesToRetrieve?: DynamicPropsValue; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const customObjectType = propsValue.customObjectType as string; + const additionalPropertiesToRetrieve = propsValue.additionalPropertiesToRetrieve?.['values']; + + let propertiesToRetrieve; + try { + if (Array.isArray(additionalPropertiesToRetrieve)) { + propertiesToRetrieve = additionalPropertiesToRetrieve; + } + if (typeof additionalPropertiesToRetrieve === 'string') { + propertiesToRetrieve = JSON.parse(additionalPropertiesToRetrieve as string); + } + } catch (error) { + propertiesToRetrieve = []; + } + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.objects.searchApi.doSearch(customObjectType, { + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-hs_createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'hs_createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newCustomObjectTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-custom-object', + displayName: 'New Custom Object', + description: 'Triggers when new custom object is available.', + props: { + customObjectType: customObjectDropdown, + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_object_id, hs_lastmodifieddate, hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: customObjectPropertiesDropdown( + 'Additional Properties to Retrieve', + false, + ), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-22T15:20:16.121Z', + archived: false, + id: '21583829313', + properties: { + hs_createdate: '2024-12-22T15:20:16.121Z', + hs_lastmodifieddate: '2024-12-22T15:20:16.818Z', + hs_object_id: '21583829313', + pet_name: 'Oreo', + }, + updatedAt: '2024-12-22T15:20:16.818Z', + }, +}); From 269311adfa56ddb2026596d18434bb0fda241594 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 16:38:39 +0530 Subject: [PATCH 49/60] feat(hubspot): new product trigger --- .../hubspot/src/lib/triggers/new-product.ts | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-product.ts diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts new file mode 100644 index 0000000000..e0aa1623af --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts @@ -0,0 +1,123 @@ +import { hubspotAuth } from '../../'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { MarkdownVariant } from '@activepieces/shared'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; +import dayjs from 'dayjs'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + // Extract properties once to avoid recomputation + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.PRODUCT); + const propertiesToRetrieve = [...defaultProductProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.products.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newProductTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-product', + displayName: 'New Product', + description: 'Triggers when new product is available.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + createdate, description, name, price, tax, hs_lastmodifieddate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.PRODUCT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + createdAt: '2024-12-22T10:43:01.920Z', + archived: false, + id: '17727139749', + properties: { + createdate: '2024-12-22T10:43:01.920Z', + description: null, + hs_lastmodifieddate: '2024-12-23T08:13:30.506Z', + hs_object_id: '17727139749', + name: 'TEST', + price: '20.0', + tax: null, + }, + updatedAt: '2024-12-23T08:13:30.506Z', + }, +}); From 64599a7e6e97def4cc5d91d4f271950b29edb51a Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 16:42:53 +0530 Subject: [PATCH 50/60] fix(hubspot): fix deal trigger --- .../src/lib/triggers/new-deal-added.ts | 62 --------- .../hubspot/src/lib/triggers/new-deal.ts | 128 ++++++++++++++++++ 2 files changed, 128 insertions(+), 62 deletions(-) delete mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-deal-added.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-deal-added.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-deal-added.ts deleted file mode 100644 index c5324c226a..0000000000 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-deal-added.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - OAuth2PropertyValue, - createTrigger, -} from '@activepieces/pieces-framework'; -import { TriggerStrategy } from '@activepieces/pieces-framework'; -import { - DedupeStrategy, - Polling, - pollingHelper, -} from '@activepieces/pieces-common'; - -import { hubSpotAuthentication } from '../common/props'; -import { hubSpotClient } from '../common/client'; -import dayjs from 'dayjs'; - -const polling: Polling> = { - strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, lastFetchEpochMS }) => { - const currentValues = - ( - await hubSpotClient.searchDeals(auth.access_token, { - createdAt: lastFetchEpochMS, - }) - ).results ?? []; - const items = currentValues.map((item: { createdAt: string }) => ({ - epochMilliSeconds: dayjs(item.createdAt).valueOf(), - data: item, - })); - return items; - }, -}; - -export const newDealAdded = createTrigger({ - auth: hubSpotAuthentication, - name: 'new_deal', - displayName: 'New Deal Added', - description: 'Trigger when a new deal is added.', - props: {}, - type: TriggerStrategy.POLLING, - onEnable: async (context) => { - await pollingHelper.onEnable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - onDisable: async (context) => { - await pollingHelper.onDisable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - run: async (context) => { - return await pollingHelper.poll(polling, context) - }, - test: async (context) => { - return await pollingHelper.test(polling, context) - }, - - sampleData: {}, -}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts new file mode 100644 index 0000000000..3c88e4efdf --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts @@ -0,0 +1,128 @@ +import { PiecePropValueSchema, Property, createTrigger } from '@activepieces/pieces-framework'; +import { TriggerStrategy } from '@activepieces/pieces-framework'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import dayjs from 'dayjs'; +import { hubspotAuth } from '../..'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultProductProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); + const propertiesToRetrieve = [...defaultProductProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.deals.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newDealTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-deal', + displayName: 'New Deal', + description: 'Trigger when a new deal is added.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + + sampleData: { + createdAt: '2024-12-23T08:19:21.614Z', + archived: false, + id: '30906615140', + properties: { + amount: '150', + closedate: null, + createdate: '2024-12-23T08:19:21.614Z', + dealname: 'test deal', + dealtype: 'newbusiness', + description: 'test', + hs_forecast_amount: '150.0', + hs_forecast_probability: null, + hs_lastmodifieddate: '2024-12-26T10:31:45.624Z', + hs_manual_forecast_category: null, + hs_next_step: null, + hs_object_id: '30906615140', + hubspot_owner_id: '64914635', + hubspot_team_id: '55094099', + num_associated_contacts: '1', + }, + updatedAt: '2024-12-26T10:31:45.624Z', + }, +}); From 6e3485f2cecddbbfc0cd9aea9cb5cdb6f12f33e9 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 16:47:46 +0530 Subject: [PATCH 51/60] fix: fix new ticket trigger --- .../pieces/community/hubspot/src/index.ts | 14 +- .../src/lib/triggers/new-ticket-added.ts | 62 --------- .../hubspot/src/lib/triggers/new-ticket.ts | 127 ++++++++++++++++++ 3 files changed, 137 insertions(+), 66 deletions(-) delete mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-ticket-added.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 3d41e5961a..72308e2152 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -4,9 +4,9 @@ import { PieceCategory } from '@activepieces/shared'; import { hubSpotListsAddContactAction } from './lib/actions/add-contact-to-list-action'; import { newCompanyAdded } from './lib/triggers/new-company-added'; import { newContactAdded } from './lib/triggers/new-contact-added'; -import { newDealAdded } from './lib/triggers/new-deal-added'; +import { newDealTrigger } from './lib/triggers/new-deal'; import { newTaskAdded } from './lib/triggers/new-task-added'; -import { newTicketAdded } from './lib/triggers/new-ticket-added'; +import { newTicketTrigger } from './lib/triggers/new-ticket'; import { createDealAction } from './lib/actions/create-deal'; import { updateDealAction } from './lib/actions/update-deal'; import { dealStageUpdatedTrigger } from './lib/triggers/deal-stage-updated'; @@ -56,6 +56,9 @@ import { newTicketPropertyChangeTrigger } from './lib/triggers/new-ticket-proper import { newCompanyPropertyChangeTrigger } from './lib/triggers/new-company-propety-change'; import { newDealPropertyChangeTrigger } from './lib/triggers/new-deal-property-change'; import { newCustomObjectPropertyChangeTrigger } from './lib/triggers/new-custom-object-property-change'; +import { newLineItemTrigger } from './lib/triggers/new-line-item'; +import { newProductTrigger } from './lib/triggers/new-product'; +import { newCustomObjectTrigger } from './lib/triggers/new-custom-object'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -160,8 +163,11 @@ export const hubspot = createPiece({ newDealPropertyChangeTrigger, newTicketPropertyChangeTrigger, newCompanyPropertyChangeTrigger, - newDealAdded, - newTicketAdded, + newDealTrigger, + newTicketTrigger, + newLineItemTrigger, + newProductTrigger, + newCustomObjectTrigger, dealStageUpdatedTrigger, newOrUpdatedProductTrigger ], diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-added.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-added.ts deleted file mode 100644 index 16018eace9..0000000000 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-added.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - OAuth2PropertyValue, - createTrigger, -} from '@activepieces/pieces-framework'; -import { TriggerStrategy } from '@activepieces/pieces-framework'; -import { - DedupeStrategy, - Polling, - pollingHelper, -} from '@activepieces/pieces-common'; - -import { hubSpotAuthentication } from '../common/props'; -import { hubSpotClient } from '../common/client'; -import dayjs from 'dayjs'; - -const polling: Polling> = { - strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, lastFetchEpochMS }) => { - const currentValues = - ( - await hubSpotClient.searchTickets(auth.access_token, { - createdAt: lastFetchEpochMS, - }) - ).results ?? []; - const items = currentValues.map((item: { createdAt: string }) => ({ - epochMilliSeconds: dayjs(item.createdAt).valueOf(), - data: item, - })); - return items; - }, -}; - -export const newTicketAdded = createTrigger({ - name: 'new_ticket', - auth: hubSpotAuthentication, - displayName: 'New Ticket Added', - description: 'Trigger when a new ticket is added.', - props: {}, - type: TriggerStrategy.POLLING, - onEnable: async ({ store, propsValue, auth }) => { - await pollingHelper.onEnable(polling, { - auth, - store: store, - propsValue: propsValue, - }); - }, - onDisable: async ({ store, propsValue, auth }) => { - await pollingHelper.onDisable(polling, { - auth, - store: store, - propsValue: propsValue, - }); - }, - run: async (context) => { - return await pollingHelper.poll(polling, context); - }, - test: async (context) => { - return await pollingHelper.test(polling, context); - }, - - sampleData: {}, -}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts new file mode 100644 index 0000000000..3f7f72fc75 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts @@ -0,0 +1,127 @@ +import { PiecePropValueSchema, Property, createTrigger } from '@activepieces/pieces-framework'; +import { TriggerStrategy } from '@activepieces/pieces-framework'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import dayjs from 'dayjs'; +import { hubspotAuth } from '../..'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultTicketProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TICKET); + const propertiesToRetrieve = [...defaultTicketProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.tickets.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newTicketTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-ticket', + displayName: 'New Ticket', + description: 'Trigger when new deal is available.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + subject, content, source_type, createdate, hs_pipeline, hs_pipeline_stage, hs_resolution, hs_ticket_category, hs_ticket_id, hs_ticket_priority, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.TICKET, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + + sampleData: { + createdAt: '2024-12-26T08:40:12.881Z', + archived: false, + id: '18166565782', + properties: { + content: null, + createdate: '2024-12-26T08:40:12.881Z', + hs_lastmodifieddate: '2024-12-26T08:40:14.245Z', + hs_object_id: '18166565782', + hs_pipeline: '0', + hs_pipeline_stage: '1', + hs_resolution: null, + hs_ticket_category: null, + hs_ticket_id: '18166565782', + hs_ticket_priority: null, + hubspot_owner_id: '1594636734', + hubspot_team_id: '55094099', + source_type: null, + subject: 'test', + }, + updatedAt: '2024-12-26T08:40:14.245Z', + }, +}); From 6e2a3abf01b8b9ad54dc8e04b87f95bb66f1ea87 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 19:00:50 +0530 Subject: [PATCH 52/60] feat(hubspot): new form trigger --- .../pieces/community/hubspot/src/index.ts | 5 +- .../community/hubspot/src/lib/common/props.ts | 101 ++++++++---- .../src/lib/triggers/new-form-submission.ts | 155 ++++++++++++++++++ 3 files changed, 228 insertions(+), 33 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-form-submission.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 72308e2152..36df8b3b5e 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -59,6 +59,7 @@ import { newCustomObjectPropertyChangeTrigger } from './lib/triggers/new-custom- import { newLineItemTrigger } from './lib/triggers/new-line-item'; import { newProductTrigger } from './lib/triggers/new-product'; import { newCustomObjectTrigger } from './lib/triggers/new-custom-object'; +import { newFormSubmissionTrigger } from './lib/triggers/new-form-submission'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -89,7 +90,8 @@ export const hubspotAuth = PieceAuth.OAuth2({ 'settings.currencies.read', 'settings.users.read', 'settings.users.teams.read', - 'files' + 'files', + 'forms' // 'business_units_view.read' ], }); @@ -152,6 +154,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newFormSubmissionTrigger, newOrUpdatedCompanyTrigger, newOrUpdatedContactTrigger, newOrUpdatedLineItemTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index dabd1048d3..b3d23dd882 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -818,12 +818,70 @@ export const associationTypeDropdown = Property.Dropdown({ }, }); -export const toObjectIdsDropdown =(params: DropdownParams) => Property.MultiSelectDropdown({ - displayName: params.displayName, - description: params.description, - refreshers: ['toObjectType'], - required: params.required, - options: async ({ auth, toObjectType }) => { +export const toObjectIdsDropdown = (params: DropdownParams) => + Property.MultiSelectDropdown({ + displayName: params.displayName, + description: params.description, + refreshers: ['toObjectType'], + required: params.required, + options: async ({ auth, toObjectType }) => { + if (!auth) { + return buildEmptyList({ + placeholder: 'Please connect your account.', + }); + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + + const limit = 100; + const options: DropdownOption[] = []; + let after: string | undefined; + do { + const response = await client.crm.objects.basicApi.getPage( + toObjectType as string, + limit, + after, + ); + for (const object of response.results) { + let labelName; + switch (toObjectType) { + case OBJECT_TYPE.CONTACT: + labelName = 'email'; + break; + case OBJECT_TYPE.COMPANY: + labelName = 'name'; + break; + case OBJECT_TYPE.DEAL: + labelName = 'dealname'; + break; + case OBJECT_TYPE.TICKET: + labelName = 'subject'; + break; + case OBJECT_TYPE.LINE_ITEM: + labelName = 'name'; + break; + } + options.push({ + label: object.properties[labelName!] ?? object.id, + value: object.id, + }); + } + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + }; + }, + }); + +export const formDropdown = Property.Dropdown({ + displayName: 'Form', + refreshers: [], + required: true, + options: async ({ auth }) => { if (!auth) { return buildEmptyList({ placeholder: 'Please connect your account.', @@ -835,35 +893,14 @@ export const toObjectIdsDropdown =(params: DropdownParams) => Property.MultiSele const limit = 100; const options: DropdownOption[] = []; + let after: string | undefined; do { - const response = await client.crm.objects.basicApi.getPage( - toObjectType as string, - limit, - after, - ); - for (const object of response.results) { - let labelName; - switch (toObjectType) { - case OBJECT_TYPE.CONTACT: - labelName = 'email'; - break; - case OBJECT_TYPE.COMPANY: - labelName = 'name'; - break; - case OBJECT_TYPE.DEAL: - labelName = 'dealname'; - break; - case OBJECT_TYPE.TICKET: - labelName = 'subject'; - break; - case OBJECT_TYPE.LINE_ITEM: - labelName = 'name'; - break; - } + const response = await client.marketing.forms.formsApi.getPage(after, limit); + for (const form of response.results) { options.push({ - label: object.properties[labelName!] ?? object.id, - value: object.id, + label: form.name, + value: form.id, }); } after = response.paging?.next?.after; diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-form-submission.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-form-submission.ts new file mode 100644 index 0000000000..d6baf939f7 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-form-submission.ts @@ -0,0 +1,155 @@ +import { hubspotAuth } from '../../'; +import { + AuthenticationType, + DedupeStrategy, + httpClient, + HttpMethod, + Polling, + pollingHelper, + QueryParams, +} from '@activepieces/pieces-common'; +import { + createTrigger, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { formDropdown } from '../common/props'; + +type Props = { + formId: string; +}; + +type FormSubmissionResponse = { + results: Array<{ + conversionId: string; + submittedAt: number; + pageUrl: string; + values: Array<{ name: string; value: string }>; + }>; + paging?: { + next?: { + after: string; + }; + }; +}; + +type FormField = { + name: string; + label: string; + fieldType: string; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const authValue = auth as PiecePropValueSchema; + const formId = propsValue.formId; + + const submissions = []; + let after; + do { + const qs: QueryParams = { limit: '50' }; + if (after) { + qs.after = after; + } + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: `https://api.hubapi.com/form-integrations/v1/submissions/forms/${formId}`, + queryParams: qs, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: authValue.access_token, + }, + }); + after = response.body.paging?.next?.after; + submissions.push(...response.body.results); + } while (after); + + const formFields = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: `https://api.hubapi.com/forms/v2/fields/${formId}`, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: authValue.access_token, + }, + }); + + const fieldMapping = formFields.body.reduce((acc, field) => { + acc[field.name] = { label: field.label, fieldType: field.fieldType }; + return acc; + }, {} as Record); + + const items = []; + + for (const submission of submissions) { + const formattedValues: Record = {}; + + const submissionData = submission.values ?? []; + for (const fieldValue of submissionData) { + const field = fieldMapping[fieldValue.name]; + + if (field) { + const { label, fieldType } = field; + if (fieldType === 'checkbox') { + formattedValues[label] = formattedValues[label] || []; + formattedValues[label].push(fieldValue.value); + } else { + formattedValues[label] = fieldValue.value; + } + } else { + formattedValues[fieldValue.name] = fieldValue.value; + } + } + items.push({ + ...submission, + values: formattedValues, + }); + } + + return items.map((item) => ({ + epochMilliSeconds: item.submittedAt, + data: item, + })); + }, +}; + +export const newFormSubmissionTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-form-submission', + displayName: 'New Form Submission', + description: 'Triggers when a form is submitted.', + type: TriggerStrategy.POLLING, + props: { + formId: formDropdown, + }, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + conversionId: '82800398-30af-48a0-942a-1d0623fce08c', + submittedAt: 1735216921730, + values: { + "First Name": "John", + "Last Name": "Doe", + "Email": "john.doe@example.com", + }, + pageUrl: 'https://share.hsforms.com/1VXAvM044Tcyaa3Y5XRQFSQsuf7d', + }, +}); From 2d14fa1e05ab6cc4448e7e6643768110e22a95fa Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Thu, 26 Dec 2024 19:49:41 +0530 Subject: [PATCH 53/60] feat(hubspot): new email event trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../src/lib/triggers/new-email-event.ts | 147 ++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 36df8b3b5e..a4bfeca369 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -60,6 +60,7 @@ import { newLineItemTrigger } from './lib/triggers/new-line-item'; import { newProductTrigger } from './lib/triggers/new-product'; import { newCustomObjectTrigger } from './lib/triggers/new-custom-object'; import { newFormSubmissionTrigger } from './lib/triggers/new-form-submission'; +import { newEmailEventTrigger } from './lib/triggers/new-email-event'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -154,6 +155,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newEmailEventTrigger, newFormSubmissionTrigger, newOrUpdatedCompanyTrigger, newOrUpdatedContactTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts new file mode 100644 index 0000000000..be84aa8c79 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts @@ -0,0 +1,147 @@ +import { + AuthenticationType, + DedupeStrategy, + httpClient, + HttpMethod, + Polling, + pollingHelper, + QueryParams, +} from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; + +type Props = { + eventType: string; +}; + +type EmailEventResponse = { + events: Array>; + hasMore: boolean; + offset: string; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const eventType = propsValue.eventType; + const isTestMode = lastFetchEpochMS === 0; + + let hasMore = true; + const qs: QueryParams = { limit: '100' }; + if (eventType) { + qs.eventType = eventType; + } + if (lastFetchEpochMS) { + qs.startTimestamp = lastFetchEpochMS.toString(); + } + const emailEvents = []; + + do { + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/email/public/v1/events', + queryParams: qs, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: auth.access_token, + }, + }); + hasMore = response.body.hasMore; + qs.offset = response.body.offset; + for (const event of response.body.events) { + emailEvents.push(event); + } + if (isTestMode) break; + } while (hasMore); + + return emailEvents.map((item) => ({ + epochMilliSeconds: item['created'] as number, + data: item, + })); + }, +}; + +export const newEmailEventTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-email-event', + displayName: 'New Email Event', + description: 'Triggers when all,or specific new email event is available.', + type: TriggerStrategy.POLLING, + props: { + eventType: Property.StaticDropdown({ + displayName: 'Event Type', + required: true, + options: { + disabled: false, + options: [ + { + label: 'Sent', + value: 'SENT', + }, + { + label: 'Dropped', + value: 'DROPPED', + }, + { + label: 'Processed', + value: 'PROCESSED', + }, + { + label: 'Delivered', + value: 'DELIVERED', + }, + { + label: 'Deferred', + value: 'DEFERRED', + }, + { + label: 'Bounce', + value: 'BOUNCE', + }, + { + label: 'Open', + value: 'OPEN', + }, + { + label: 'Click', + value: 'CLICK', + }, + { + label: 'Status Change', + value: 'STATUSCHANGE', + }, + { + label: 'Spam Report', + value: 'SPAMREPORT', + }, + ], + }, + }), + }, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: {}, +}); From 057a38f7ec1f474cec49ea1136a6a11c524203d6 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 11:51:41 +0530 Subject: [PATCH 54/60] feat(hubspot): new blog article trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../src/lib/triggers/new-blog-article.ts | 130 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index a4bfeca369..9dd8942462 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -61,6 +61,7 @@ import { newProductTrigger } from './lib/triggers/new-product'; import { newCustomObjectTrigger } from './lib/triggers/new-custom-object'; import { newFormSubmissionTrigger } from './lib/triggers/new-form-submission'; import { newEmailEventTrigger } from './lib/triggers/new-email-event'; +import { newBlogArticleTrigger } from './lib/triggers/new-blog-article'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -155,6 +156,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newBlogArticleTrigger, newEmailEventTrigger, newFormSubmissionTrigger, newOrUpdatedCompanyTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts new file mode 100644 index 0000000000..d913f5428a --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts @@ -0,0 +1,130 @@ +import { + AuthenticationType, + DedupeStrategy, + httpClient, + HttpMethod, + Polling, + pollingHelper, + QueryParams, +} from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import dayjs from 'dayjs'; + +type Props = { + articleState: string; +}; + +type ListBlogPostsResponse = { + results: Array>; + paging?: { + next?: { + after: string; + }; + }; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const articleState = propsValue.articleState; + const isTestMode = lastFetchEpochMS === 0; + + const qs: QueryParams = { limit: '100', sort: '-createdAt' }; + if (articleState !== 'BOTH') { + qs.state = articleState; + } + if (!isTestMode) { + if(articleState === 'PUBLISHED') { + qs['publishDate__gt']=lastFetchEpochMS.toString(); + } + else + { + qs['createdAt__gt']=lastFetchEpochMS.toString(); + } + } + + const items = []; + + let after; + + do { + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/cms/v3/blogs/posts', + queryParams: qs, + authentication: { type: AuthenticationType.BEARER_TOKEN, token: auth.access_token }, + }); + + after = response.body.paging?.next?.after; + items.push(...response.body.results); + if (isTestMode) { + break; + } + } while (after); + + return items.map((item) => { + return { + epochMilliSeconds: articleState === 'PUBLISHED' ? dayjs(item.publishDate).valueOf() : dayjs(item.createdAt).valueOf(), + data: item, + } + }); + }, +}; + +export const newBlogArticleTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-blog-article', + displayName: 'New COS Blog Article', + description: 'Triggers when a new article is added to your COS blog.', + type: TriggerStrategy.POLLING, + props: { + articleState: Property.StaticDropdown({ + displayName: 'Article State', + required: true, + options: { + disabled: false, + options: [ + { + label: 'Published Only', + value: 'PUBLISHED', + }, + { + label: 'Draft Only', + value: 'DRAFT', + }, + { + label: 'Both', + value: 'BOTH', + }, + ], + }, + }), + }, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: {}, +}); From dd5917de803432d35b618ddcf9a7fc292fb0e859 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 13:12:02 +0530 Subject: [PATCH 55/60] feat(hubspot): new contact in list trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../src/lib/triggers/new-contact-in-list.ts | 161 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 9dd8942462..5b26761de6 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -62,6 +62,7 @@ import { newCustomObjectTrigger } from './lib/triggers/new-custom-object'; import { newFormSubmissionTrigger } from './lib/triggers/new-form-submission'; import { newEmailEventTrigger } from './lib/triggers/new-email-event'; import { newBlogArticleTrigger } from './lib/triggers/new-blog-article'; +import { newContactInListTrigger } from './lib/triggers/new-contact-in-list'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -156,6 +157,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newContactInListTrigger, newBlogArticleTrigger, newEmailEventTrigger, newFormSubmissionTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts new file mode 100644 index 0000000000..4946bed61a --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts @@ -0,0 +1,161 @@ +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + DropdownOption, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; +import { Client } from '@hubspot/api-client'; +import { MarkdownVariant } from '@activepieces/shared'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import dayjs from 'dayjs'; + +type Props = { + listId: string; + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const listId = propsValue.listId; + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + const propertiesToRetrieve = [...defaultContactProperties, ...additionalProperties]; + + const client = new Client({ accessToken: auth.access_token }); + const isTestMode = lastFetchEpochMS === 0; + + let listMembers = []; + let after; + + // Fetch members from the list + do { + const response = await client.crm.lists.membershipsApi.getPageOrderedByAddedToListDate( + listId, + after, + undefined, + isTestMode ? 10 : 100, + ); + after = response.paging?.next?.after; + listMembers.push(...response.results); + if (isTestMode) { + break; + } + } while (after); + + if (!isTestMode) { + listMembers = listMembers.filter( + (member) => dayjs(member.membershipTimestamp).valueOf() > lastFetchEpochMS, + ); + } + + // Fetch detailed contact properties + const contactDetailsResponse = await client.crm.contacts.batchApi.read({ + inputs: listMembers.map((member) => ({ id: member.recordId })), + properties: propertiesToRetrieve, + propertiesWithHistory: [], + }); + + // Merge `membershipTimestamp` with contact properties + const enrichedMembers = contactDetailsResponse.results.map((contact) => { + const correspondingMember = listMembers.find((member) => member.recordId === contact.id); + return { + ...contact, + membershipTimestamp: correspondingMember?.membershipTimestamp, + }; + }); + + return enrichedMembers.map((member) => ({ + epochMilliSeconds: dayjs(member.membershipTimestamp).valueOf(), + data: member, + })); + }, +}; + +export const newContactInListTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-contact-in-list', + displayName: 'New Contact in List', + description: 'Triggers when a new contact is added to the specified list.', + type: TriggerStrategy.POLLING, + props: { + listId: Property.Dropdown({ + displayName: 'Contact List', + refreshers: [], + required: true, + options: async ({ auth }) => { + if (!auth) { + return { + disabled: true, + options: [], + placeholder: 'Please connect your account.', + }; + } + + const authValue = auth as PiecePropValueSchema; + const client = new Client({ accessToken: authValue.access_token }); + let offset = 0; + let hasMore = true; + const options: DropdownOption[] = []; + do { + const response = await client.crm.lists.listsApi.doSearch({ + count: 100, + offset: offset, + }); + for (const list of response.lists) { + options.push({ + label: list.name, + value: list.listId, + }); + } + hasMore = response.hasMore; + offset += 100; + } while (hasMore); + + return { + disabled: false, + options, + }; + }, + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: {}, +}); From 46dd15c47413505aed7c7dacb36c37d4dcdc7846 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 13:57:08 +0530 Subject: [PATCH 56/60] feat(hubspot): new engagement trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../src/lib/triggers/new-contact-in-list.ts | 15 +- .../src/lib/triggers/new-engagement.ts | 146 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 5b26761de6..a333b23151 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -63,6 +63,7 @@ import { newFormSubmissionTrigger } from './lib/triggers/new-form-submission'; import { newEmailEventTrigger } from './lib/triggers/new-email-event'; import { newBlogArticleTrigger } from './lib/triggers/new-blog-article'; import { newContactInListTrigger } from './lib/triggers/new-contact-in-list'; +import { newEngagementTrigger } from './lib/triggers/new-engagement'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -157,6 +158,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newEngagementTrigger, newContactInListTrigger, newBlogArticleTrigger, newEmailEventTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts index 4946bed61a..016e196ff8 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-in-list.ts @@ -157,5 +157,18 @@ export const newContactInListTrigger = createTrigger({ async run(context) { return await pollingHelper.poll(polling, context); }, - sampleData: {}, + sampleData: { + id: '123', + archived: false, + createdAt: '2023-06-13T10:24:42.392Z', + updatedAt: '2023-06-30T06:16:51.869Z', + properties: { + email: 'contact@email.com', + lastname: 'Last', + firstname: 'First', + createdate: '2023-06-13T10:24:42.392Z', + hs_object_id: '123', + lastmodifieddate: '2023-06-30T06:16:51.869Z', + }, + }, }); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts new file mode 100644 index 0000000000..e15b843b84 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts @@ -0,0 +1,146 @@ +import { + AuthenticationType, + DedupeStrategy, + httpClient, + HttpMethod, + Polling, + pollingHelper, + QueryParams, +} from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + Property, + TriggerStrategy, +} from '@activepieces/pieces-framework'; + +type Props = { + eventType?: string; +}; + +type EngagementResponse = { + results: Array>; + hasMore: boolean; + offset: string; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const eventType = propsValue.eventType; + let engagements = []; + + let hasMore = true; + const qs: QueryParams = { limit: '100' }; + do { + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/engagements/v1/engagements/paged', + queryParams: qs, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: auth.access_token, + }, + }); + hasMore = response.body.hasMore; + qs.offset = response.body.offset; + for (const engagement of response.body.results) { + engagements.push(engagement); + } + } while (hasMore); + + const filteredEngagements = eventType + ? engagements.filter((engagement) => engagement.engagement.type === eventType) + : engagements; + + return filteredEngagements.map((item) => ({ + epochMilliSeconds: item.engagement.createdAt as number, + data: item, + })); + }, +}; + +export const newEngagementTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-engagement', + displayName: 'New Engagement', + description: 'Triggers when a new engagement is created.', + type: TriggerStrategy.POLLING, + props: { + eventType: Property.StaticDropdown({ + displayName: 'Event Type', + required: false, + options: { + disabled: false, + options: [ + { + label: 'Note', + value: 'NOTE', + }, + { + label: 'Task', + value: 'TASK', + }, + { + label: 'Meeting', + value: 'MEETING', + }, + { + label: 'Email', + value: 'EMAIL', + }, + { + label: 'Call', + value: 'CALL', + }, + ], + }, + }), + }, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + engagement: { + id: 29090716, + portalId: 62515, + active: true, + createdAt: 1444223400781, + lastUpdated: 1444223400781, + createdBy: 215482, + modifiedBy: 215482, + ownerId: 70, + type: 'NOTE', + timestamp: 1444223400781, + }, + associations: { + contactIds: [247], + companyIds: [], + dealIds: [], + ownerIds: [], + workflowIds: [], + }, + attachments: [], + metadata: { + body: 'This is a test note ', + }, + }, +}); From 4f3ffd54eba7a06d9100fb97f024b27eec50628c Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 14:21:45 +0530 Subject: [PATCH 57/60] feat(hubspot): new email subscription timline trigger --- .../pieces/community/hubspot/src/index.ts | 2 + .../triggers/email-subscriptions-timeline.ts | 101 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/email-subscriptions-timeline.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index a333b23151..ad4ce9c878 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -64,6 +64,7 @@ import { newEmailEventTrigger } from './lib/triggers/new-email-event'; import { newBlogArticleTrigger } from './lib/triggers/new-blog-article'; import { newContactInListTrigger } from './lib/triggers/new-contact-in-list'; import { newEngagementTrigger } from './lib/triggers/new-engagement'; +import { newEmailSubscriptionsTimelineTrigger } from './lib/triggers/email-subscriptions-timeline'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -158,6 +159,7 @@ export const hubspot = createPiece({ }), ], triggers: [ + newEmailSubscriptionsTimelineTrigger, newEngagementTrigger, newContactInListTrigger, newBlogArticleTrigger, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/email-subscriptions-timeline.ts b/packages/pieces/community/hubspot/src/lib/triggers/email-subscriptions-timeline.ts new file mode 100644 index 0000000000..70561641d1 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/email-subscriptions-timeline.ts @@ -0,0 +1,101 @@ +import { + AuthenticationType, + DedupeStrategy, + httpClient, + HttpMethod, + Polling, + pollingHelper, + QueryParams, +} from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { + createTrigger, + PiecePropValueSchema, + TriggerStrategy, +} from '@activepieces/pieces-framework'; + +type SubscriptionTimeLineResponse = { + hasMore: boolean; + offset: string; + timeline: Array>; +}; + +const polling: Polling, Record> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, lastFetchEpochMS }) { + const qs: QueryParams = { limit: '100' }; + if (lastFetchEpochMS) { + qs.startTimestamp = lastFetchEpochMS.toString(); + } + const items = []; + + let hasMore = true; + do { + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/email/public/v1/subscriptions/timeline', + queryParams: qs, + authentication: { + type: AuthenticationType.BEARER_TOKEN, + token: auth.access_token, + }, + }); + hasMore = response.body.hasMore; + qs.offset = response.body.offset; + for (const item of response.body.timeline) { + items.push(item); + } + } while (hasMore); + + return items.map((item) => ({ + epochMilliSeconds: item.timestamp as number, + data: item, + })); + }, +}; + +export const newEmailSubscriptionsTimelineTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-email-subscriptions-timeline', + displayName: 'New Email Subscriptions Timeline', + description: 'Triggers when a new email timeline subscription added for the portal.', + type: TriggerStrategy.POLLING, + props: {}, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + sampleData: { + timestamp: 1401975207000, + portalId: 62515, + recipient: '6d4b537e-c5ac-11e3-a673-00262df65d03@some.email.com', + changes: [ + { + change: 'BOUNCED', + source: 'SOURCE_NON_DELIVERY_REPORT', + portalId: 62515, + changeType: 'PORTAL_BOUNCE', + causedByEvent: { + id: '6d72d39c-87da-3ced-bfdf-5f0213363827', + created: 1401975207000, + }, + }, + ], + }, +}); From cb2213a4e8842ae9b8f5730cfb27507b74d7cbb9 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 15:30:36 +0530 Subject: [PATCH 58/60] feat(hubspot): create blog action --- .../pieces/community/hubspot/src/index.ts | 28 +++--- .../src/lib/actions/create-blog-post.ts | 93 +++++++++++++++++++ .../community/hubspot/src/lib/common/props.ts | 80 +++++++++++++++- .../community/hubspot/src/lib/common/types.ts | 7 ++ 4 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 packages/pieces/community/hubspot/src/lib/actions/create-blog-post.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index ad4ce9c878..8abcd4eaf8 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -65,6 +65,7 @@ import { newBlogArticleTrigger } from './lib/triggers/new-blog-article'; import { newContactInListTrigger } from './lib/triggers/new-contact-in-list'; import { newEngagementTrigger } from './lib/triggers/new-engagement'; import { newEmailSubscriptionsTimelineTrigger } from './lib/triggers/email-subscriptions-timeline'; +import { createBlogPostAction } from './lib/actions/create-blog-post'; export const hubspotAuth = PieceAuth.OAuth2({ authUrl: 'https://app.hubspot.com/oauth/authorize', @@ -115,6 +116,7 @@ export const hubspot = createPiece({ createAssociationsAction, createCompanyAction, createContactAction, + createBlogPostAction, createCustomObjectAction, createDealAction, createLineItemAction, @@ -159,29 +161,29 @@ export const hubspot = createPiece({ }), ], triggers: [ - newEmailSubscriptionsTimelineTrigger, - newEngagementTrigger, - newContactInListTrigger, - newBlogArticleTrigger, - newEmailEventTrigger, - newFormSubmissionTrigger, newOrUpdatedCompanyTrigger, newOrUpdatedContactTrigger, + newDealPropertyChangeTrigger, + newEmailSubscriptionsTimelineTrigger, newOrUpdatedLineItemTrigger, - newTaskAdded, newCompanyAdded, + newCompanyPropertyChangeTrigger, newContactAdded, + newContactInListTrigger, newContactPropertyChangeTrigger, + newBlogArticleTrigger, + newCustomObjectTrigger, newCustomObjectPropertyChangeTrigger, - newDealPropertyChangeTrigger, - newTicketPropertyChangeTrigger, - newCompanyPropertyChangeTrigger, newDealTrigger, - newTicketTrigger, + newEmailEventTrigger, + newEngagementTrigger, + newFormSubmissionTrigger, newLineItemTrigger, newProductTrigger, - newCustomObjectTrigger, + newTicketTrigger, + newTicketPropertyChangeTrigger, + newOrUpdatedProductTrigger, + newTaskAdded, dealStageUpdatedTrigger, - newOrUpdatedProductTrigger ], }); diff --git a/packages/pieces/community/hubspot/src/lib/actions/create-blog-post.ts b/packages/pieces/community/hubspot/src/lib/actions/create-blog-post.ts new file mode 100644 index 0000000000..adecb98c2a --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/actions/create-blog-post.ts @@ -0,0 +1,93 @@ +import { AuthenticationType, httpClient, HttpMethod } from '@activepieces/pieces-common'; +import { hubspotAuth } from '../../'; +import { createAction, Property } from '@activepieces/pieces-framework'; +import { blogAuthorDropdown, blogUrlDropdown } from '../common/props'; + +export const createBlogPostAction = createAction({ + auth: hubspotAuth, + name: 'create-blog-post', + displayName: 'Create COS Blog Post', + description: 'Creates a blog post in you Hubspot COS blog.', + props: { + contentGroupId: blogUrlDropdown, + authorId: blogAuthorDropdown, + status: Property.StaticDropdown({ + displayName: 'Publish This Post?', + required: true, + options: { + disabled: false, + options: [ + { + label: 'Leave As Draft', + value: 'DRAFT', + }, + { + label: 'Publish Immediately', + value: 'PUBLISHED', + }, + ], + }, + }), + slug: Property.ShortText({ + displayName: 'Slug', + required: true, + description: 'The slug of the blog post. This is the URL of the post on your COS blog.', + }), + title: Property.ShortText({ + displayName: 'Blog Post Title', + required: true, + }), + body: Property.LongText({ + displayName: 'Blog Post Content', + required: true, + }), + meta: Property.LongText({ + displayName: 'Meta Description', + required: true, + }), + imageUrl: Property.ShortText({ + displayName: 'Featured Image URL', + required: true, + }), + }, + async run(context) { + const { contentGroupId, authorId, status, slug, title, body, meta, imageUrl } = + context.propsValue; + + const createdPost = await httpClient.sendRequest>({ + method: HttpMethod.POST, + url: 'https://api.hubapi.com/content/api/v2/blog-posts', + authentication: { type: AuthenticationType.BEARER_TOKEN, token: context.auth.access_token }, + body: { + blog_author_id: authorId, + content_group_id: contentGroupId, + featured_image: imageUrl, + use_featured_image: true, + name: title, + slug: slug, + meta_description: meta, + post_body: body, + publish_immediately: status === 'PUBLISHED' ? true : undefined, + }, + }); + + if (status === 'PUBLISHED') { + await httpClient.sendRequest({ + method: HttpMethod.POST, + url: `https://api.hubapi.com/content/api/v2/blog-posts/${createdPost.body['id']}/publish-action`, + authentication: { type: AuthenticationType.BEARER_TOKEN, token: context.auth.access_token }, + body: { + action: 'schedule-publish', + }, + }); + } + + const postDeatils = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: `https://api.hubapi.com/content/api/v2/blog-posts/${createdPost.body['id']}`, + authentication: { type: AuthenticationType.BEARER_TOKEN, token: context.auth.access_token }, + }); + + return postDeatils.body + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index b3d23dd882..94c70fc27c 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -13,7 +13,7 @@ import { HttpMethod, HttpRequest, } from '@activepieces/pieces-common'; -import { WorkflowResponse, HubspotProperty, HubspotFieldType } from './types'; +import { WorkflowResponse, HubspotProperty, HubspotFieldType, ListBlogsResponse } from './types'; import { DEFAULT_COMPANY_PROPERTIES, DEFAULT_CONTACT_PROPERTIES, @@ -913,6 +913,84 @@ export const formDropdown = Property.Dropdown({ }, }); +export const blogUrlDropdown = Property.Dropdown({ + displayName: 'Blog URL', + refreshers: [], + required: true, + options: async ({ auth }) => { + if (!auth) { + return { disabled: true, options: [], placeholder: 'Please connect your account.' }; + } + + const authValue = auth as PiecePropValueSchema; + + const response = await httpClient.sendRequest({ + method: HttpMethod.GET, + url: 'https://api.hubapi.com/content/api/v2/blogs', + authentication: { type: AuthenticationType.BEARER_TOKEN, token: authValue.access_token }, + queryParams: { + limit: '100', + }, + }); + + return { + disabled: false, + options: response.body.objects.map((blog) => { + return { + label: blog.absolute_url, + value: blog.id.toString(), + }; + }), + }; + }, +}); + +export const blogAuthorDropdown = Property.Dropdown({ + displayName: 'Blog Author', + refreshers: [], + required: true, + options: async ({ auth }) => { + if (!auth) { + return { disabled: true, options: [], placeholder: 'Please connect your account.' }; + } + + const authValue = auth as PiecePropValueSchema; + + const client = new Client({ accessToken: authValue.access_token }); + + const options: DropdownOption[] = []; + + let after: string | undefined; + do { + const response = await client.cms.blogs.authors.blogAuthorsApi.getPage( + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + after, + 100, + ); + for (const author of response.results) + { + options.push({ + label: author.name, + value: author.id, + }) + } + + after = response.paging?.next?.after; + } while (after); + + return { + disabled: false, + options, + } + }, +}); + type DropdownParams = { objectType: OBJECT_TYPE; displayName: string; diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 056b7242da..2550f0b20c 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -201,3 +201,10 @@ export declare enum AssociationSpecAssociationCategoryEnum { UserDefined = "USER_DEFINED", IntegratorDefined = "INTEGRATOR_DEFINED" } + +export type ListBlogsResponse = { + objects:Array<{absolute_url:string,id:number}>; + offset:number, + total:number, + limit:number +} \ No newline at end of file From 5a90d84f494815a80edc4b6ef1b91c58f864cb82 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 17:21:22 +0530 Subject: [PATCH 59/60] fix(hubspot): fix after param in pagination --- .../pieces/community/hubspot/src/index.ts | 12 +- .../hubspot/src/lib/common/constants.ts | 43 ++- .../community/hubspot/src/lib/common/props.ts | 3 + .../src/lib/triggers/deal-stage-updated.ts | 247 ++++++------------ .../src/lib/triggers/new-blog-article.ts | 3 + .../src/lib/triggers/new-company-added.ts | 74 ------ .../triggers/new-company-propety-change.ts | 1 + .../hubspot/src/lib/triggers/new-company.ts | 117 +++++++++ .../src/lib/triggers/new-contact-added.ts | 91 ------- .../triggers/new-contact-property-change.ts | 1 + .../hubspot/src/lib/triggers/new-contact.ts | 140 ++++++++++ .../new-custom-object-property-change.ts | 1 + .../src/lib/triggers/new-custom-object.ts | 1 + .../lib/triggers/new-deal-property-change.ts | 1 + .../hubspot/src/lib/triggers/new-deal.ts | 1 + .../src/lib/triggers/new-email-event.ts | 4 +- .../src/lib/triggers/new-engagement.ts | 2 +- .../hubspot/src/lib/triggers/new-line-item.ts | 1 + .../lib/triggers/new-or-updated-company.ts | 1 + .../lib/triggers/new-or-updated-contact.ts | 1 + .../lib/triggers/new-or-updated-line-item.ts | 1 + .../lib/triggers/new-or-updated-product.ts | 1 + .../hubspot/src/lib/triggers/new-product.ts | 1 + .../src/lib/triggers/new-task-added.ts | 100 ------- .../hubspot/src/lib/triggers/new-task.ts | 145 ++++++++++ .../triggers/new-ticket-property-change.ts | 1 + .../hubspot/src/lib/triggers/new-ticket.ts | 1 + 27 files changed, 548 insertions(+), 447 deletions(-) delete mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-company-added.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-company.ts delete mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-contact-added.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-contact.ts delete mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-task-added.ts create mode 100644 packages/pieces/community/hubspot/src/lib/triggers/new-task.ts diff --git a/packages/pieces/community/hubspot/src/index.ts b/packages/pieces/community/hubspot/src/index.ts index 8abcd4eaf8..29404fdafa 100644 --- a/packages/pieces/community/hubspot/src/index.ts +++ b/packages/pieces/community/hubspot/src/index.ts @@ -2,10 +2,10 @@ import { createCustomApiCallAction } from '@activepieces/pieces-common'; import { OAuth2PropertyValue, PieceAuth, createPiece } from '@activepieces/pieces-framework'; import { PieceCategory } from '@activepieces/shared'; import { hubSpotListsAddContactAction } from './lib/actions/add-contact-to-list-action'; -import { newCompanyAdded } from './lib/triggers/new-company-added'; -import { newContactAdded } from './lib/triggers/new-contact-added'; +import { newCompanyTrigger } from './lib/triggers/new-company'; +import { newContactTrigger } from './lib/triggers/new-contact'; import { newDealTrigger } from './lib/triggers/new-deal'; -import { newTaskAdded } from './lib/triggers/new-task-added'; +import { newTaskTrigger } from './lib/triggers/new-task'; import { newTicketTrigger } from './lib/triggers/new-ticket'; import { createDealAction } from './lib/actions/create-deal'; import { updateDealAction } from './lib/actions/update-deal'; @@ -166,9 +166,9 @@ export const hubspot = createPiece({ newDealPropertyChangeTrigger, newEmailSubscriptionsTimelineTrigger, newOrUpdatedLineItemTrigger, - newCompanyAdded, + newCompanyTrigger, newCompanyPropertyChangeTrigger, - newContactAdded, + newContactTrigger, newContactInListTrigger, newContactPropertyChangeTrigger, newBlogArticleTrigger, @@ -183,7 +183,7 @@ export const hubspot = createPiece({ newTicketTrigger, newTicketPropertyChangeTrigger, newOrUpdatedProductTrigger, - newTaskAdded, + newTaskTrigger, dealStageUpdatedTrigger, ], }); diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index 56ba4f8437..be01ceafa1 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -5,6 +5,7 @@ export const enum OBJECT_TYPE { TICKET = 'ticket', PRODUCT = 'product', LINE_ITEM = 'line_item', + TASK = 'task', } export const DEFAULT_CONTACT_PROPERTIES = [ @@ -134,24 +135,42 @@ export const DEFAULT_LINE_ITEM_PROPERTIES = [ export const STANDARD_OBJECT_TYPES = [ { - label: "Contacts", - value: OBJECT_TYPE.CONTACT, + label: 'Contacts', + value: OBJECT_TYPE.CONTACT, }, { - label: "Companies", - value: OBJECT_TYPE.COMPANY, + label: 'Companies', + value: OBJECT_TYPE.COMPANY, }, { - label: "Deals", - value: OBJECT_TYPE.DEAL, + label: 'Deals', + value: OBJECT_TYPE.DEAL, }, { - label: "Tickets", - value: OBJECT_TYPE.TICKET, + label: 'Tickets', + value: OBJECT_TYPE.TICKET, }, { - label: "Line Items", - value: OBJECT_TYPE.LINE_ITEM, + label: 'Line Items', + value: OBJECT_TYPE.LINE_ITEM, }, - - ]; \ No newline at end of file +]; + + + +export const DEFAULT_TASK_PROPERTIES = [ + 'hs_task_body', + 'hubspot_owner_id', + 'hs_task_subject', + 'hs_task_status', + 'hs_task_priority', + 'hs_task_type', + 'hs_created_by', + 'hs_repeat_status', + 'hs_task_completion_date', + 'hs_task_is_completed', + 'hs_timestamp', + 'hs_queue_membership_ids', + 'hs_lastmodifieddate', + 'hs_createdate', +]; diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index 94c70fc27c..f74de2b345 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -21,6 +21,7 @@ import { DEFAULT_LINE_ITEM_PROPERTIES, DEFAULT_PRODUCT_PROPERTIES, DEFAULT_TICKET_PROPERTIES, + DEFAULT_TASK_PROPERTIES, OBJECT_TYPE, STANDARD_OBJECT_TYPES, } from './constants'; @@ -98,6 +99,8 @@ export function getDefaultPropertiesForObject(objectType: OBJECT_TYPE): string[] return DEFAULT_PRODUCT_PROPERTIES; case OBJECT_TYPE.LINE_ITEM: return DEFAULT_LINE_ITEM_PROPERTIES; + case OBJECT_TYPE.TASK: + return DEFAULT_TASK_PROPERTIES; default: return []; } diff --git a/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts b/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts index e59394dbd3..50a0f299d1 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/deal-stage-updated.ts @@ -5,78 +5,74 @@ import { createTrigger, } from '@activepieces/pieces-framework'; -import { - AuthenticationType, - DedupeStrategy, - HttpMethod, - HttpRequest, - Polling, - httpClient, - pollingHelper, -} from '@activepieces/pieces-common'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; import dayjs from 'dayjs'; import { hubspotAuth } from '../../'; import { - ListDealPipelinesResponse, - ListPipelineStagesResponse, - SearchDealsResponse, -} from '../common/types'; + getDefaultPropertiesForObject, + pipelineDropdown, + pipelineStageDropdown, + standardObjectPropertiesDropdown, +} from '../common/props'; +import { OBJECT_TYPE } from '../common/constants'; +import { MarkdownVariant } from '@activepieces/shared'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; + pipelineId?: string; + stageId?: string; +}; -const polling: Polling< - PiecePropValueSchema, - { pipelineId: string; dealStageId: string } -> = { +const polling: Polling, Props> = { strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, propsValue, lastFetchEpochMS }) => { - const items: { - id: string; - createdAt: string; - updatedAt: string; - properties: Record; - }[] = []; + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultDealProperties = getDefaultPropertiesForObject(OBJECT_TYPE.DEAL); + const propertiesToRetrieve = [...defaultDealProperties, ...additionalProperties]; + + const items = []; let after; + do { - const request: HttpRequest = { - method: HttpMethod.POST, - url: 'https://api.hubapi.com/crm/v3/objects/deals/search', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: auth.access_token, - }, - body: { - limit: 100, - filterGroups: [ - { - filters: [ - { - propertyName: 'pipeline', - operator: 'EQ', - value: propsValue.pipelineId, - }, - { propertyName: 'dealstage', operator: 'EQ', value: propsValue.dealStageId }, - ], - }, - ], - sorts: [ - { - propertyName: 'hs_lastmodifieddate', - direction: 'DESCENDING', - }, - ], - after: after, - }, - }; + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.deals.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-hs_lastmodifieddate'], + after, + filterGroups: [ + { + filters: [ + { + propertyName: 'pipeline', + operator: FilterOperatorEnum.Eq, + value: propsValue.pipelineId, + }, + { + propertyName: 'dealstage', + operator: FilterOperatorEnum.Eq, + value: propsValue.stageId, + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); - const response = await httpClient.sendRequest(request); - items.push(...response.body.results); - after = response.body.paging?.next.after; - } while (after !== undefined); return items.map((item) => ({ - epochMilliSeconds: dayjs(item.updatedAt).valueOf(), + epochMilliSeconds: dayjs(item.properties['hs_lastmodifieddate']).valueOf(), data: item, })); }, @@ -84,125 +80,54 @@ const polling: Polling< export const dealStageUpdatedTrigger = createTrigger({ auth: hubspotAuth, - name: 'deal_stage_updated', + name: 'deal-stage-updated', displayName: 'Updated Deal Stage', - description: 'Triggers when a deal enters s specified stage.', + description: 'Triggers when a deal enters a specified stage.', props: { - pipelineId: Property.Dropdown({ - displayName: 'Deal Pipeline', - refreshers: [], + pipelineId: pipelineDropdown({ + objectType: OBJECT_TYPE.DEAL, required: true, - options: async ({ auth }) => { - if (!auth) { - return { - disabled: true, - placeholder: 'Please connect your account first.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/crm/v3/pipelines/deals', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((pipeline) => { - return { - label: pipeline.label, - value: pipeline.id, - }; - }), - }; - }, + displayName: 'Deal Pipeline', }), - dealstageId: Property.Dropdown({ - displayName: 'Deal Stage', - refreshers: ['pipelineId'], + stageId: pipelineStageDropdown({ + objectType: OBJECT_TYPE.DEAL, required: true, - options: async ({ auth, pipelineId }) => { - if (!auth || !pipelineId) { - return { - disabled: true, - placeholder: 'Please connect your account first and select pipeline.', - options: [], - }; - } - const authValue = auth as PiecePropValueSchema; - const request: HttpRequest = { - method: HttpMethod.GET, - url: `https://api.hubapi.com/crm/v3/pipelines/deals/${pipelineId}/stages`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: authValue.access_token, - }, - }; - const response = await httpClient.sendRequest(request); - return { - disabled: false, - options: response.body.results.map((stage) => { - return { - label: stage.label, - value: stage.id, - }; - }), - }; - }, + displayName: 'Deal Stage', + }), + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + dealtype, dealname, amount, description, closedate, createdate, num_associated_contacts, hs_forecast_amount, hs_forecast_probability, hs_manual_forecast_category, hs_next_step, hs_object_id, hs_lastmodifieddate, hubspot_owner_id, hubspot_team_id + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.DEAL, + displayName: 'Additional properties to retrieve', + required: false, }), }, type: TriggerStrategy.POLLING, - async test(context) { - const { store, auth, propsValue, files } = context; - return await pollingHelper.test(polling, { - store, - auth, - propsValue: { - pipelineId: propsValue.pipelineId, - dealStageId: propsValue.dealstageId, - }, - files: files, - }); - }, async onEnable(context) { - const { store, auth, propsValue } = context; await pollingHelper.onEnable(polling, { - store, - auth, - propsValue: { - pipelineId: propsValue.pipelineId, - dealStageId: propsValue.dealstageId, - }, + auth: context.auth, + store: context.store, + propsValue: context.propsValue, }); }, - async onDisable(context) { - const { store, auth, propsValue } = context; await pollingHelper.onDisable(polling, { - store, - auth, - propsValue: { - pipelineId: propsValue.pipelineId, - dealStageId: propsValue.dealstageId, - }, + auth: context.auth, + store: context.store, + propsValue: context.propsValue, }); }, - + async test(context) { + return await pollingHelper.test(polling, context); + }, async run(context) { - const { store, auth, propsValue, files } = context; - return await pollingHelper.poll(polling, { - store, - auth, - propsValue: { - pipelineId: propsValue.pipelineId, - dealStageId: propsValue.dealstageId, - }, - files: files, - }); + return await pollingHelper.poll(polling, context); }, sampleData: { id: '18011922225', diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts index d913f5428a..e89f787244 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-blog-article.ts @@ -62,6 +62,9 @@ const polling: Polling, Props> = { }); after = response.body.paging?.next?.after; + if(response.body.paging?.next?.after){ + qs.after = response.body.paging?.next?.after; + } items.push(...response.body.results); if (isTestMode) { break; diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-company-added.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-company-added.ts deleted file mode 100644 index 854649feaf..0000000000 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-company-added.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - OAuth2PropertyValue, - createTrigger, -} from '@activepieces/pieces-framework'; -import { TriggerStrategy } from '@activepieces/pieces-framework'; -import { - DedupeStrategy, - Polling, - pollingHelper, -} from '@activepieces/pieces-common'; - -import { hubSpotAuthentication } from '../common/props'; -import { hubSpotClient } from '../common/client'; -import dayjs from 'dayjs'; - -const polling: Polling> = { - strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, lastFetchEpochMS }) => { - const currentValues = - ( - await hubSpotClient.searchCompanies(auth.access_token, { - createdAt: lastFetchEpochMS, - }) - ).results ?? []; - const items = currentValues.map((item: { createdAt: string }) => ({ - epochMilliSeconds: dayjs(item.createdAt).valueOf(), - data: item, - })); - return items; - }, -}; - -export const newCompanyAdded = createTrigger({ - auth: hubSpotAuthentication, - name: 'new_company', - displayName: 'New Company Added', - description: 'Trigger when a new company is added.', - props: {}, - type: TriggerStrategy.POLLING, - onEnable: async (context) => { - await pollingHelper.onEnable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - onDisable: async (context) => { - await pollingHelper.onDisable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - run: async (context) => { - return await pollingHelper.poll(polling, context); - }, - test: async (context) => { - return await pollingHelper.test(polling, context); - }, - - sampleData: { - id: '123123123', - archived: false, - createdAt: '2023-07-03T14:48:13.839Z', - updatedAt: '2023-07-03T14:48:14.769Z', - properties: { - name: 'Company Name', - domain: 'company.com', - createdate: '2023-07-03T14:48:13.839Z', - hs_object_id: '123123123', - hs_lastmodifieddate: '2023-07-03T14:48:14.769Z', - }, - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts index dbaf8f47d8..034d766a30 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-company-propety-change.ts @@ -45,6 +45,7 @@ const polling: Polling, Props> = { do { const response = await client.crm.companies.searchApi.doSearch({ limit: 100, + after, sorts: ['-hs_lastmodifieddate'], filterGroups: [ { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-company.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-company.ts new file mode 100644 index 0000000000..91dcb62522 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-company.ts @@ -0,0 +1,117 @@ +import { PiecePropValueSchema, Property, createTrigger } from '@activepieces/pieces-framework'; +import { TriggerStrategy } from '@activepieces/pieces-framework'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import dayjs from 'dayjs'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; +import { hubspotAuth } from '../..'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultCompanyProperties = getDefaultPropertiesForObject(OBJECT_TYPE.COMPANY); + const propertiesToRetrieve = [...defaultCompanyProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.companies.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; +export const newCompanyTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-company', + displayName: 'New Company', + description: 'Trigger when a new company is added.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + name, domain, industry, about_us, phone, address, address2, city, state, zip, country, website, type, description, founded_year, hs_createdate, hs_lastmodifieddate, hs_object_id, is_public, timezone, total_money_raised, total_revenue, owneremail, ownername, numberofemployees, annualrevenue, lifecyclestage, createdate, web_technologies + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.COMPANY, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + + sampleData: { + id: '123123123', + archived: false, + createdAt: '2023-07-03T14:48:13.839Z', + updatedAt: '2023-07-03T14:48:14.769Z', + properties: { + name: 'Company Name', + domain: 'company.com', + createdate: '2023-07-03T14:48:13.839Z', + hs_object_id: '123123123', + hs_lastmodifieddate: '2023-07-03T14:48:14.769Z', + }, + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-added.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-added.ts deleted file mode 100644 index 5c7d037a43..0000000000 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-added.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { - OAuth2PropertyValue, - createTrigger, -} from '@activepieces/pieces-framework'; -import { TriggerStrategy } from '@activepieces/pieces-framework'; -import { - DedupeStrategy, - Polling, - pollingHelper, -} from '@activepieces/pieces-common'; - -import { hubSpotAuthentication } from '../common/props'; -import { hubSpotClient } from '../common/client'; -import dayjs from 'dayjs'; -import { hubspotCommon } from '../common'; - -const polling: Polling> = { - strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, lastFetchEpochMS, propsValue }) => { - const wantedFields = propsValue['contactProps']; - let fixedFields: string[]; - if (wantedFields === undefined) { - fixedFields = ['firstname', 'lastname', 'phone', 'email']; - } else { - fixedFields = wantedFields.map((field: { name: string }) => { - return field.name; - }); - fixedFields.push('firstname'); - fixedFields.push('lastname'); - fixedFields.push('phone'); - fixedFields.push('email'); - } - const currentValues = - ( - await hubSpotClient.searchContacts(auth.access_token, fixedFields, { - createdAt: lastFetchEpochMS, - }) - ).results ?? []; - const items = currentValues.map((item: { createdAt: string }) => ({ - epochMilliSeconds: dayjs(item.createdAt).valueOf(), - data: item, - })); - return items; - }, -}; - -export const newContactAdded = createTrigger({ - auth: hubSpotAuthentication, - name: 'new_contact', - displayName: 'New Contact Added', - description: 'Trigger when a new contact is added.', - props: { - contactProps: hubspotCommon.choose_props, - }, - type: TriggerStrategy.POLLING, - onEnable: async (context) => { - await pollingHelper.onEnable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - onDisable: async (context) => { - await pollingHelper.onDisable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - run: async (context) => { - return await pollingHelper.poll(polling, context); - }, - test: async (context) => { - return await pollingHelper.test(polling, context); - }, - - sampleData: { - id: '123', - archived: false, - createdAt: '2023-06-13T10:24:42.392Z', - updatedAt: '2023-06-30T06:16:51.869Z', - properties: { - email: 'contact@email.com', - lastname: 'Last', - firstname: 'First', - createdate: '2023-06-13T10:24:42.392Z', - hs_object_id: '123', - lastmodifieddate: '2023-06-30T06:16:51.869Z', - }, - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts index ed8c103f4c..8054944fd4 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact-property-change.ts @@ -46,6 +46,7 @@ const polling: Polling, Props> = { do { const response = await client.crm.contacts.searchApi.doSearch({ limit: 100, + after, sorts: ['-lastmodifieddate'], filterGroups: [ { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-contact.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-contact.ts new file mode 100644 index 0000000000..943204f458 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-contact.ts @@ -0,0 +1,140 @@ +import { PiecePropValueSchema, Property, createTrigger } from '@activepieces/pieces-framework'; +import { TriggerStrategy } from '@activepieces/pieces-framework'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; + +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; +import dayjs from 'dayjs'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; +import { hubspotAuth } from '../..'; +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultContactProperties = getDefaultPropertiesForObject(OBJECT_TYPE.CONTACT); + const propertiesToRetrieve = [...defaultContactProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.contacts.searchApi.doSearch({ + limit: isTest ? 10 : 100, + properties: propertiesToRetrieve, + sorts: ['-createdate'], + after, + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newContactTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-contact', + displayName: 'New Contact', + description: 'Trigger when new contact is available.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + firstname, lastname, email, company, website, mobilephone, phone, fax, address, city, state, zip, salutation, country, jobtitle, hs_createdate, hs_email_domain, hs_object_id, lastmodifieddate, hs_persona, hs_language, lifecyclestage, createdate, numemployees, annualrevenue, industry + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.CONTACT, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + + sampleData: { + createdAt: '2024-12-06T10:52:58.322Z', + archived: false, + id: '82665997707', + properties: { + address: null, + annualrevenue: null, + city: 'Brisbane', + company: 'HubSpot', + country: null, + createdate: '2024-12-06T10:52:58.322Z', + email: 'emailmaria@hubspot.com', + fax: null, + firstname: 'Maria', + hs_createdate: null, + hs_email_domain: 'hubspot.com', + hs_language: null, + hs_object_id: '82665997707', + hs_persona: null, + industry: null, + jobtitle: 'Salesperson', + lastmodifieddate: '2024-12-20T12:50:35.201Z', + lastname: 'Johnson (Sample Contact)', + lifecyclestage: 'lead', + mobilephone: null, + numemployees: null, + phone: null, + salutation: null, + state: null, + website: 'http://www.HubSpot.com', + zip: null, + }, + updatedAt: '2024-12-20T12:50:35.201Z', + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts index 4c73c7e6ac..edff0165a4 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object-property-change.ts @@ -51,6 +51,7 @@ const polling: Polling, Props> = { do { const response = await client.crm.objects.searchApi.doSearch(customObjectType, { limit: 100, + after, sorts: ['-hs_lastmodifieddate'], filterGroups: [ { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts index 5e67c7e0aa..f2dab8b711 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-custom-object.ts @@ -45,6 +45,7 @@ const polling: Polling, Props> = { const isTest = lastFetchEpochMS === 0; const response = await client.crm.objects.searchApi.doSearch(customObjectType, { limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-hs_createdate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts index ea1e1509a1..e0213c8da3 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-deal-property-change.ts @@ -45,6 +45,7 @@ const polling: Polling, Props> = { do { const response = await client.crm.deals.searchApi.doSearch({ limit: 100, + after, sorts: ['-hs_lastmodifieddate'], filterGroups: [ { diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts index 3c88e4efdf..4d18a36b32 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-deal.ts @@ -30,6 +30,7 @@ const polling: Polling, Props> = { const isTest = lastFetchEpochMS === 0; const response = await client.crm.deals.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-createdate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts index be84aa8c79..9a718bb8c4 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-email-event.ts @@ -16,7 +16,7 @@ import { } from '@activepieces/pieces-framework'; type Props = { - eventType: string; + eventType?: string; }; type EmailEventResponse = { @@ -75,7 +75,7 @@ export const newEmailEventTrigger = createTrigger({ props: { eventType: Property.StaticDropdown({ displayName: 'Event Type', - required: true, + required: false, options: { disabled: false, options: [ diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts index e15b843b84..5e4cd1bdce 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts @@ -69,7 +69,7 @@ export const newEngagementTrigger = createTrigger({ type: TriggerStrategy.POLLING, props: { eventType: Property.StaticDropdown({ - displayName: 'Event Type', + displayName: 'Type', required: false, options: { disabled: false, diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts index 9dc5b5705e..9d2da15ba4 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-line-item.ts @@ -34,6 +34,7 @@ const polling: Polling, Props> = { const isTest = lastFetchEpochMS === 0; const response = await client.crm.lineItems.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-createdate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts index f39c44089d..9df1c8bc58 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-company.ts @@ -33,6 +33,7 @@ const polling: Polling< const isTest = lastFetchEpochMS === 0; const response = await client.crm.companies.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-hs_lastmodifieddate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts index 75f8d10b8a..da50b3d5c0 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-contact.ts @@ -33,6 +33,7 @@ const polling: Polling< const isTest = lastFetchEpochMS === 0; const response = await client.crm.contacts.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-lastmodifieddate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts index 98d54a9618..52ea24649d 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-line-item.ts @@ -33,6 +33,7 @@ const polling: Polling< const isTest = lastFetchEpochMS === 0; const response = await client.crm.lineItems.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-hs_lastmodifieddate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts index d6a18f2707..0f5552759f 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-or-updated-product.ts @@ -33,6 +33,7 @@ const polling: Polling< const isTest = lastFetchEpochMS === 0; const response = await client.crm.products.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-hs_lastmodifieddate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts index e0aa1623af..d23cc25e4e 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-product.ts @@ -34,6 +34,7 @@ const polling: Polling, Props> = { const isTest = lastFetchEpochMS === 0; const response = await client.crm.products.searchApi.doSearch({ limit: isTest ? 10 : 100, + after, properties: propertiesToRetrieve, sorts: ['-createdate'], filterGroups: isTest diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-task-added.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-task-added.ts deleted file mode 100644 index f4381dc9d3..0000000000 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-task-added.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - OAuth2PropertyValue, - createTrigger, -} from '@activepieces/pieces-framework'; -import { TriggerStrategy } from '@activepieces/pieces-framework'; -import { - DedupeStrategy, - Polling, - pollingHelper, -} from '@activepieces/pieces-common'; -import { hubSpotClient } from '../common/client'; -import dayjs from 'dayjs'; -import { hubspotAuth } from '../..'; - -const polling: Polling = { - strategy: DedupeStrategy.TIMEBASED, - items: async ({ auth, lastFetchEpochMS }) => { - const currentValues = - ( - await hubSpotClient.tasks.getTasksAfterLastSearch( - auth.access_token, - lastFetchEpochMS - ) - ).results ?? []; - const items = currentValues.map((item: { createdAt: string }) => ({ - epochMilliSeconds: dayjs(item.createdAt).valueOf(), - data: item, - })); - return items; - }, -}; - -export const newTaskAdded = createTrigger({ - auth: hubspotAuth, - name: 'new_task', - displayName: 'New Task', - description: 'Trigger when a new task is added.', - props: {}, - type: TriggerStrategy.POLLING, - onEnable: async (context) => { - await pollingHelper.onEnable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - onDisable: async (context) => { - await pollingHelper.onDisable(polling, { - auth: context.auth, - store: context.store, - propsValue: context.propsValue, - }); - }, - run: async (context) => { - return await pollingHelper.poll(polling, context); - }, - test: async (context) => { - return await pollingHelper.test(polling, context); - }, - - sampleData: { - results: [ - { - id: '18156543966', - properties: { - hs_created_by: '5605286', - hs_created_by_user_id: '5605286', - hs_createdate: '2023-06-13T09:42:37.557Z', - hs_modified_by: '5605286', - hs_num_associated_companies: '0', - hs_num_associated_contacts: '1', - hs_num_associated_deals: '0', - hs_num_associated_tickets: '0', - hs_product_name: null, - hs_read_only: null, - hs_repeat_status: null, - hs_task_body: null, - hs_task_completion_count: '0', - hs_task_completion_date: null, - hs_task_is_all_day: 'false', - hs_task_is_completed: '0', - hs_task_is_completed_call: '0', - hs_task_is_completed_email: '0', - hs_task_is_completed_linked_in: '0', - hs_task_is_completed_sequence: '0', - hs_task_repeat_interval: null, - hs_task_status: 'NOT_STARTED', - hs_task_subject: 'My Test Task', - hs_task_type: 'TODO', - hs_updated_by_user_id: '5605286', - hubspot_owner_id: '1041576162', - hs_timestamp: '2023-06-16T05:00:00Z', - }, - createdAt: '2023-06-13T09:42:37.557Z', - updatedAt: '2023-06-13T10:03:41.073Z', - archived: false, - }, - ], - }, -}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-task.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-task.ts new file mode 100644 index 0000000000..fa903ab9b6 --- /dev/null +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-task.ts @@ -0,0 +1,145 @@ +import { PiecePropValueSchema, Property, createTrigger } from '@activepieces/pieces-framework'; +import { TriggerStrategy } from '@activepieces/pieces-framework'; +import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common'; +import dayjs from 'dayjs'; +import { hubspotAuth } from '../..'; +import { MarkdownVariant } from '@activepieces/shared'; +import { OBJECT_TYPE } from '../common/constants'; +import { getDefaultPropertiesForObject, standardObjectPropertiesDropdown } from '../common/props'; + +import { Client } from '@hubspot/api-client'; +import { FilterOperatorEnum } from '../common/types'; + +type Props = { + additionalPropertiesToRetrieve?: string | string[]; +}; + +const polling: Polling, Props> = { + strategy: DedupeStrategy.TIMEBASED, + async items({ auth, propsValue, lastFetchEpochMS }) { + const client = new Client({ accessToken: auth.access_token }); + + const additionalProperties = propsValue.additionalPropertiesToRetrieve ?? []; + const defaultTaskProperties = getDefaultPropertiesForObject(OBJECT_TYPE.TASK); + const propertiesToRetrieve = [...defaultTaskProperties, ...additionalProperties]; + + const items = []; + let after; + + do { + const isTest = lastFetchEpochMS === 0; + const response = await client.crm.objects.tasks.searchApi.doSearch({ + limit: isTest ? 10 : 100, + after, + properties: propertiesToRetrieve, + sorts: ['-hs_createdate'], + filterGroups: isTest + ? [] + : [ + { + filters: [ + { + propertyName: 'hs_createdate', + operator: FilterOperatorEnum.Gt, + value: lastFetchEpochMS.toString(), + }, + ], + }, + ], + }); + after = response.paging?.next?.after; + items.push(...response.results); + + // Stop fetching if it's a test + if (isTest) break; + } while (after); + + return items.map((item) => ({ + epochMilliSeconds: dayjs(item.properties['hs_createdate']).valueOf(), + data: item, + })); + }, +}; + +export const newTaskTrigger = createTrigger({ + auth: hubspotAuth, + name: 'new-task', + displayName: 'New Task', + description: 'Trigger when a new task is added.', + props: { + markdown: Property.MarkDown({ + variant: MarkdownVariant.INFO, + value: `### Properties to retrieve: + + hs_task_subject, hs_task_type, hs_task_priority, hubspot_owner_id, hs_timestamp, hs_queue_membership_ids, hs_lastmodifieddate,hs_createdate + + **Specify here a list of additional properties to retrieve**`, + }), + additionalPropertiesToRetrieve: standardObjectPropertiesDropdown({ + objectType: OBJECT_TYPE.TASK, + displayName: 'Additional properties to retrieve', + required: false, + }), + }, + type: TriggerStrategy.POLLING, + async onEnable(context) { + await pollingHelper.onEnable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async onDisable(context) { + await pollingHelper.onDisable(polling, { + auth: context.auth, + store: context.store, + propsValue: context.propsValue, + }); + }, + async test(context) { + return await pollingHelper.test(polling, context); + }, + async run(context) { + return await pollingHelper.poll(polling, context); + }, + + sampleData: { + results: [ + { + id: '18156543966', + properties: { + hs_created_by: '5605286', + hs_created_by_user_id: '5605286', + hs_createdate: '2023-06-13T09:42:37.557Z', + hs_modified_by: '5605286', + hs_num_associated_companies: '0', + hs_num_associated_contacts: '1', + hs_num_associated_deals: '0', + hs_num_associated_tickets: '0', + hs_product_name: null, + hs_read_only: null, + hs_repeat_status: null, + hs_task_body: null, + hs_task_completion_count: '0', + hs_task_completion_date: null, + hs_task_is_all_day: 'false', + hs_task_is_completed: '0', + hs_task_is_completed_call: '0', + hs_task_is_completed_email: '0', + hs_task_is_completed_linked_in: '0', + hs_task_is_completed_sequence: '0', + hs_task_repeat_interval: null, + hs_task_status: 'NOT_STARTED', + hs_task_subject: 'My Test Task', + hs_task_type: 'TODO', + hs_updated_by_user_id: '5605286', + hubspot_owner_id: '1041576162', + hs_timestamp: '2023-06-16T05:00:00Z', + }, + createdAt: '2023-06-13T09:42:37.557Z', + updatedAt: '2023-06-13T10:03:41.073Z', + archived: false, + }, + ], + }, +}); diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts index c14332e889..e5677d6c94 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket-property-change.ts @@ -46,6 +46,7 @@ const polling: Polling, Props> = { const response = await client.crm.tickets.searchApi.doSearch({ limit: 100, sorts: ['-hs_lastmodifieddate'], + after, filterGroups: [ { filters: [ diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts index 3f7f72fc75..38dcee4650 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-ticket.ts @@ -31,6 +31,7 @@ const polling: Polling, Props> = { const response = await client.crm.tickets.searchApi.doSearch({ limit: isTest ? 10 : 100, properties: propertiesToRetrieve, + after, sorts: ['-createdate'], filterGroups: isTest ? [] From 3c9be15773424376406a8ccb26a43ee45974a820 Mon Sep 17 00:00:00 2001 From: Kishan Parmar Date: Fri, 27 Dec 2024 17:32:42 +0530 Subject: [PATCH 60/60] chore: remove duplicate client code --- .../pieces/community/hubspot/package.json | 2 +- .../hubspot/src/lib/common/client.ts | 321 ------------------ .../hubspot/src/lib/common/constants.ts | 37 +- .../community/hubspot/src/lib/common/index.ts | 211 ------------ .../community/hubspot/src/lib/common/props.ts | 60 +--- .../community/hubspot/src/lib/common/types.ts | 201 ++--------- .../src/lib/triggers/new-engagement.ts | 2 +- 7 files changed, 58 insertions(+), 776 deletions(-) delete mode 100644 packages/pieces/community/hubspot/src/lib/common/client.ts delete mode 100644 packages/pieces/community/hubspot/src/lib/common/index.ts diff --git a/packages/pieces/community/hubspot/package.json b/packages/pieces/community/hubspot/package.json index eada8f401e..955f9ddfec 100644 --- a/packages/pieces/community/hubspot/package.json +++ b/packages/pieces/community/hubspot/package.json @@ -1,4 +1,4 @@ { "name": "@activepieces/piece-hubspot", - "version": "0.5.9" + "version": "0.6.0" } diff --git a/packages/pieces/community/hubspot/src/lib/common/client.ts b/packages/pieces/community/hubspot/src/lib/common/client.ts deleted file mode 100644 index a9bdd435b6..0000000000 --- a/packages/pieces/community/hubspot/src/lib/common/client.ts +++ /dev/null @@ -1,321 +0,0 @@ -import { - AuthenticationType, - HttpMethod, - HttpRequest, - httpClient, -} from '@activepieces/pieces-common'; -import { - Contact, - HubSpotAddContactsToListRequest, - HubSpotAddContactsToListResponse, - HubSpotContactsCreateOrUpdateResponse, - HubSpotListsResponse, - HubSpotRequest, -} from './types'; - -const API = 'https://api.hubapi.com'; - -export const hubSpotClient = { - contacts: { - async createOrUpdate({ - token, - email, - contact, - }: ContactsCreateOrUpdateParams): Promise { - const properties = Object.entries(contact).map(([property, value]) => ({ - property, - value, - })); - - const request: HttpRequest = { - method: HttpMethod.POST, - url: `${API}/contacts/v1/contact/createOrUpdate/email/${email}`, - body: { - properties, - }, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token, - }, - }; - - const response = await httpClient.sendRequest(request); - return response.body; - }, - }, - - lists: { - async getStaticLists({ token }: GetStaticListsParams): Promise { - const request: HttpRequest = { - method: HttpMethod.GET, - url: `${API}/contacts/v1/lists/static`, - queryParams: { - count: '250', - offset: '0', - }, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token, - }, - }; - - const response = await httpClient.sendRequest(request); - return response.body; - }, - - async addContact({ - token, - listId, - email, - }: ListsAddContactParams): Promise { - const request: HttpRequest = { - method: HttpMethod.POST, - url: `${API}/contacts/v1/lists/${listId}/add`, - body: { - emails: [email], - }, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token, - }, - }; - - const response = await httpClient.sendRequest(request); - return response.body; - }, - }, - - tasks: { - async getTasksAfterLastSearch(accessToken: string, lastFetchEpochMS: number) { - const request: HttpRequest = { - method: HttpMethod.POST, - url: `${API}/crm/v3/objects/tasks/search`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - body: { - filters: [ - { - propertyName: 'hs_createdate', - operator: 'GT', - value: lastFetchEpochMS, - }, - ], - properties: [ - 'hs_task_body', - 'hubspot_owner_id', - 'hs_task_subject', - 'hs_task_status', - 'hs_task_priority', - 'hs_task_type', - 'hs_created_by', - 'hs_created_by_user_id', - 'hs_modified_by', - 'hs_num_associated_companies', - 'hs_num_associated_contacts', - 'hs_num_associated_deals', - 'hs_num_associated_tickets', - 'hs_product_name', - 'hs_read_only', - 'hs_repeat_status', - 'hs_task_completion_count', - 'hs_task_completion_date', - 'hs_task_is_all_day', - 'hs_task_is_completed', - 'hs_task_is_completed_call', - 'hs_task_is_completed_email', - 'hs_task_is_completed_linked_in', - 'hs_task_is_completed_sequence', - 'hs_task_repeat_interval', - 'hs_updated_by_user_id', - 'hs_timestamp', - ], - limit: 100, - }, - }; - - const response = await httpClient.sendRequest(request); - return response.body; - }, - }, - - async searchCompanies( - accessToken: string, - filters?: { - createdAt?: number; - createdAtOperator?: string; - }, - ) { - const searchParams = []; - - if (filters && filters.createdAt) { - searchParams.push({ - propertyName: 'createdate', - operator: filters.createdAtOperator ?? 'GT', - value: filters.createdAt, - }); - } - - const response = await httpClient.sendRequest({ - method: HttpMethod.POST, - url: `${API}/crm/v3/objects/companies/search`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - body: { - filters: searchParams, - }, - }); - - return response.body; - }, - - async searchContacts( - accessToken: string, - wantedFields: string[], - filters?: { - createdAt?: number; - createdAtOperator?: string; - }, - ) { - const searchParams = []; - - if (filters && filters.createdAt) { - searchParams.push({ - propertyName: 'createdate', - operator: filters.createdAtOperator ?? 'GT', - value: filters.createdAt, - }); - } - const requestBody: Record = { - filters: searchParams, - properties: wantedFields, - }; - - const response = await httpClient.sendRequest({ - method: HttpMethod.POST, - url: `${API}/crm/v3/objects/contacts/search`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - body: requestBody, - }); - - return response.body; - }, - - async searchDeals( - accessToken: string, - filters?: { - createdAt?: number; - createdAtOperator?: string; - }, - ) { - const searchParams = []; - - if (filters && filters.createdAt) { - searchParams.push({ - propertyName: 'createdate', - operator: filters.createdAtOperator ?? 'GT', - value: filters.createdAt, - }); - } - - const response = await httpClient.sendRequest({ - method: HttpMethod.POST, - url: `${API}/crm/v3/objects/deals/search`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - body: { - filters: searchParams, - }, - }); - - return response.body; - }, - - async searchTickets( - accessToken: string, - filters?: { - createdAt?: number; - createdAtOperator?: string; - }, - ) { - const searchParams = []; - - if (filters && filters.createdAt) { - searchParams.push({ - propertyName: 'createdate', - operator: filters.createdAtOperator ?? 'GT', - value: filters.createdAt, - }); - } - - const response = await httpClient.sendRequest({ - method: HttpMethod.POST, - url: `${API}/crm/v3/objects/tickets/search`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - body: { - filters: searchParams, - }, - }); - - return response.body; - }, - async listContactOwners(accessToken: string, email?: string) { - const response = await httpClient.sendRequest({ - method: HttpMethod.GET, - url: `${API}/crm/v3/owners`, - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: accessToken, - }, - headers: { - 'Content-Type': 'application/json', - }, - queryParams: { - email: email!, - }, - }); - return response.body; - }, -}; - -type ContactsCreateOrUpdateParams = { - token: string; - email: string; - contact: Partial; -}; - -type GetStaticListsParams = { - token: string; -}; - -type ListsAddContactParams = { - token: string; - listId: number; - email: string; -}; diff --git a/packages/pieces/community/hubspot/src/lib/common/constants.ts b/packages/pieces/community/hubspot/src/lib/common/constants.ts index be01ceafa1..54f02d75cd 100644 --- a/packages/pieces/community/hubspot/src/lib/common/constants.ts +++ b/packages/pieces/community/hubspot/src/lib/common/constants.ts @@ -133,6 +133,25 @@ export const DEFAULT_LINE_ITEM_PROPERTIES = [ 'hs_term_in_months', ]; + + +export const DEFAULT_TASK_PROPERTIES = [ + 'hs_task_body', + 'hubspot_owner_id', + 'hs_task_subject', + 'hs_task_status', + 'hs_task_priority', + 'hs_task_type', + 'hs_created_by', + 'hs_repeat_status', + 'hs_task_completion_date', + 'hs_task_is_completed', + 'hs_timestamp', + 'hs_queue_membership_ids', + 'hs_lastmodifieddate', + 'hs_createdate', +]; + export const STANDARD_OBJECT_TYPES = [ { label: 'Contacts', @@ -156,21 +175,3 @@ export const STANDARD_OBJECT_TYPES = [ }, ]; - - -export const DEFAULT_TASK_PROPERTIES = [ - 'hs_task_body', - 'hubspot_owner_id', - 'hs_task_subject', - 'hs_task_status', - 'hs_task_priority', - 'hs_task_type', - 'hs_created_by', - 'hs_repeat_status', - 'hs_task_completion_date', - 'hs_task_is_completed', - 'hs_timestamp', - 'hs_queue_membership_ids', - 'hs_lastmodifieddate', - 'hs_createdate', -]; diff --git a/packages/pieces/community/hubspot/src/lib/common/index.ts b/packages/pieces/community/hubspot/src/lib/common/index.ts deleted file mode 100644 index ca33d23d8d..0000000000 --- a/packages/pieces/community/hubspot/src/lib/common/index.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { - AuthenticationType, - HttpMethod, - HttpRequest, - httpClient, -} from '@activepieces/pieces-common'; -import { - CheckboxProperty, - DateTimeProperty, - FileProperty, - LongTextProperty, - NumberProperty, - OAuth2PropertyValue, - Property, - ShortTextProperty, -} from '@activepieces/pieces-framework'; -import { hubSpotClient } from './client'; -import { HubspotFieldType } from './types'; - - - -interface HubspotProperty { - name: string; - label: string; - description: string; - type: string; - fieldType: HubspotFieldType; - options: []; -} - -type DynamicPropsValue = - | ShortTextProperty - | LongTextProperty - | CheckboxProperty - | DateTimeProperty - | FileProperty - | NumberProperty; - -export const hubspotCommon = { - choose_props: Property.MultiSelectDropdown({ - displayName: 'Properties', - description: 'Choose extra properties to add to the contact', - required: false, - refreshers: ['auth'], - options: async ({ auth }) => { - const connection = auth as OAuth2PropertyValue; - if (!connection) { - return { - disabled: true, - options: [], - placeholder: 'please authenticate your account first before selecting properties', - }; - } - try { - const request: HttpRequest = { - method: HttpMethod.GET, - url: 'https://api.hubapi.com/properties/v1/contacts/properties', - authentication: { - type: AuthenticationType.BEARER_TOKEN, - token: connection.access_token, - }, - }; - const result = await httpClient.sendRequest(request); - - const properties = result.body.map((property: any) => { - return { - label: property.label, - value: property, - }; - }); - - return { - disabled: false, - options: properties, - }; - } catch (error) { - return { - disabled: true, - options: [], - placeholder: 'An error occurred while fetching properties', - }; - } - }, - }), - dynamicProperties: Property.DynamicProperties({ - displayName: 'Dynamic Properties', - description: 'Extra properties to add to the contact', - required: false, - refreshers: ['choose_props'], - props: async ({ auth, choose_props }) => { - const all_props = choose_props as HubspotProperty[]; - - if (!all_props) { - return {}; - } - - const fields: any = {}; - - for (const prop of all_props) { - switch (prop.fieldType) { - case HubspotFieldType.BooleanCheckBox: - fields[prop.name] = Property.Checkbox({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.Date: - fields[prop.name] = Property.DateTime({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.File: - fields[prop.name] = Property.File({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.Number: - fields[prop.name] = Property.Number({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.CalculationEquation: - case HubspotFieldType.PhoneNumber: - case HubspotFieldType.Text: - fields[prop.name] = Property.ShortText({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.TextArea: - case HubspotFieldType.Html: - fields[prop.name] = Property.LongText({ - displayName: prop.label, - description: prop.description, - required: false, - }); - break; - case HubspotFieldType.CheckBox: - fields[prop.name] = Property.StaticMultiSelectDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: prop.options.map((option: any) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - break; - case HubspotFieldType.Select: - case HubspotFieldType.Radio: - if (prop.name === 'hubspot_owner_id') { - try { - const res = - (await hubSpotClient.listContactOwners(auth.access_token as string)).results ?? - []; - fields[prop.name] = Property.StaticDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: res.map((owner: { id: string; email: string }) => { - return { - label: owner.email, - value: owner.id, - }; - }), - }, - }); - } catch (error) { - return { - disabled: true, - options: [], - placeholder: 'An error occurred while fetching contact owner list.', - }; - } - } else { - fields[prop.name] = Property.StaticDropdown({ - displayName: prop.label, - description: prop.description, - required: false, - options: { - options: prop.options.map((option: any) => { - return { - label: option.label, - value: option.value, - }; - }), - }, - }); - } - break; - } - } - - return fields; - }, - }), -}; - diff --git a/packages/pieces/community/hubspot/src/lib/common/props.ts b/packages/pieces/community/hubspot/src/lib/common/props.ts index f74de2b345..6725e38012 100644 --- a/packages/pieces/community/hubspot/src/lib/common/props.ts +++ b/packages/pieces/community/hubspot/src/lib/common/props.ts @@ -2,11 +2,9 @@ import { DropdownOption, DynamicPropsValue, OAuth2PropertyValue, - PieceAuth, PiecePropValueSchema, Property, } from '@activepieces/pieces-framework'; -import { hubSpotClient } from './client'; import { AuthenticationType, httpClient, @@ -28,22 +26,6 @@ import { import { Client } from '@hubspot/api-client'; import { hubspotAuth } from '../../'; -export const hubSpotAuthentication = PieceAuth.OAuth2({ - authUrl: 'https://app.hubspot.com/oauth/authorize', - tokenUrl: 'https://api.hubapi.com/oauth/v1/token', - required: true, - scope: [ - 'crm.lists.read', - 'crm.lists.write', - 'crm.objects.contacts.read', - 'crm.objects.contacts.write', - 'crm.objects.companies.read', - 'crm.objects.deals.read', - 'tickets', - 'forms', - ], -}); - const buildEmptyList = ({ placeholder }: { placeholder: string }) => { return { disabled: true, @@ -52,39 +34,6 @@ const buildEmptyList = ({ placeholder }: { placeholder: string }) => { }; }; -export const hubSpotListIdDropdown = Property.Dropdown({ - displayName: 'List', - refreshers: [], - description: 'List to add contact to', - required: true, - options: async ({ auth }) => { - if (!auth) { - return buildEmptyList({ - placeholder: 'Please select an authentication', - }); - } - - const token = (auth as OAuth2PropertyValue).access_token; - const listsResponse = await hubSpotClient.lists.getStaticLists({ token }); - - if (listsResponse.lists.length === 0) { - return buildEmptyList({ - placeholder: 'No lists found! Please create a list.', - }); - } - - const options = listsResponse.lists.map((list) => ({ - label: list.name, - value: list.listId, - })); - - return { - disabled: false, - options, - }; - }, -}); - export function getDefaultPropertiesForObject(objectType: OBJECT_TYPE): string[] { switch (objectType) { case OBJECT_TYPE.CONTACT: @@ -976,21 +925,20 @@ export const blogAuthorDropdown = Property.Dropdown({ after, 100, ); - for (const author of response.results) - { + for (const author of response.results) { options.push({ label: author.name, value: author.id, - }) + }); } - + after = response.paging?.next?.after; } while (after); return { disabled: false, options, - } + }; }, }); diff --git a/packages/pieces/community/hubspot/src/lib/common/types.ts b/packages/pieces/community/hubspot/src/lib/common/types.ts index 2550f0b20c..17599ec787 100644 --- a/packages/pieces/community/hubspot/src/lib/common/types.ts +++ b/packages/pieces/community/hubspot/src/lib/common/types.ts @@ -1,39 +1,3 @@ -export type Contact = { - email: string; - firstname: string; - lastname: string; - website: string; - company: string; - phone: string; - address: string; - city: string; - state: string; - zip: string; -}; - -export type RequestProperty = { - property: string; - value: string; -}; - -export type HubSpotRequest = { - properties: RequestProperty[]; -}; - -export type HubSpotContactsCreateOrUpdateResponse = { - vid: string; - isNew: boolean; -}; - -export type HubSpotList = { - listId: number; - name: string; -}; - -export type HubSpotListsResponse = { - lists: HubSpotList[]; -}; - export type HubSpotAddContactsToListResponse = { updated: number[]; discarded: number[]; @@ -41,144 +5,45 @@ export type HubSpotAddContactsToListResponse = { invalidEmails: string[]; }; -export type HubSpotAddContactsToListRequest = { - emails: string[]; -}; -export type OwnerResponse = { - id: string; - email: string; - firstName: string; - lastName: string; - userId: number; - createdAt: string; - updatedAt: string; - archived: boolean; -}; -export type DealStageResponse = { - label: string; - displayOrder: number; - id: string; - createdAt: string; - updatedAt: string; - archived: boolean; -}; -export type PropertyResponse = { - updatedAt: string; - createdAt: string; +export type HubspotProperty = { name: string; label: string; - type: string; - fieldType: string; description: string; + hidden?: boolean; + type: string; groupName: string; - options: Array<{ - label: string; - value: string; - displayOrder: number; - hidden: boolean; - }>; - displayOrder: number; - calculated: boolean; - externalOptions: boolean; - hasUniqueValue: boolean; - hidden: boolean; - hubspotDefined: boolean; - modificationMetadata: { + fieldType: string; + referencedObjectType?: string; + modificationMetadata?: { archivable: boolean; readOnlyDefinition: boolean; - readOnlyOptions: boolean; readOnlyValue: boolean; }; - formField: boolean; -}; -export type DealPipelineResponse = { - label: string; - displayOrder: number; - id: string; - stages: Array; - createdAt: string; - updatedAt: string; - archived: boolean; + options: Array<{ label: string; value: string }>; }; -export type ListDealPipelinesResponse = { - results: Array; -}; -export type ListPipelineStagesResponse = { - results: Array; -}; -export type ListOwnersResponse = { - results: Array; -}; - -export type ListPropertiesResponse = { - results: Array; -}; - -export type SearchDealsResponse = { - total: number; - results: Array<{ - id: string; - createdAt: string; - updatedAt: string; - archived: boolean; - properties: Record; - }>; - paging?: { - next: { - link: string; - after: string; - }; - }; -}; -export type HubspotProperty= { +export type WorkflowResponse = { + id: number; + insertAt: number; + updatedAt: number; name: string; - label: string; - description: string; - hidden?:boolean; - type: string; - groupName:string; - fieldType: string; - referencedObjectType?:string; - modificationMetadata?:{ - archivable: boolean; - readOnlyDefinition: boolean; - readOnlyValue: boolean; - } - options: Array<{label:string,value:string}>; - -} - -export type HubspotPropertyGroup = { - name: string; - label: string; - displayOrder: number; - archived: boolean; + enabled: boolean; }; -export type WorkflowResponse = -{ - id:number; - insertAt:number; - updatedAt:number; - name:string; - enabled:boolean -} - export enum FilterOperatorEnum { - Eq = "EQ", - Neq = "NEQ", - Lt = "LT", - Lte = "LTE", - Gt = "GT", - Gte = "GTE", - Between = "BETWEEN", - In = "IN", - NotIn = "NOT_IN", - HasProperty = "HAS_PROPERTY", - NotHasProperty = "NOT_HAS_PROPERTY", - ContainsToken = "CONTAINS_TOKEN", - NotContainsToken = "NOT_CONTAINS_TOKEN", + Eq = 'EQ', + Neq = 'NEQ', + Lt = 'LT', + Lte = 'LTE', + Gt = 'GT', + Gte = 'GTE', + Between = 'BETWEEN', + In = 'IN', + NotIn = 'NOT_IN', + HasProperty = 'HAS_PROPERTY', + NotHasProperty = 'NOT_HAS_PROPERTY', + ContainsToken = 'CONTAINS_TOKEN', + NotContainsToken = 'NOT_CONTAINS_TOKEN', } export enum HubspotFieldType { @@ -197,14 +62,14 @@ export enum HubspotFieldType { } export declare enum AssociationSpecAssociationCategoryEnum { - HubspotDefined = "HUBSPOT_DEFINED", - UserDefined = "USER_DEFINED", - IntegratorDefined = "INTEGRATOR_DEFINED" + HubspotDefined = 'HUBSPOT_DEFINED', + UserDefined = 'USER_DEFINED', + IntegratorDefined = 'INTEGRATOR_DEFINED', } export type ListBlogsResponse = { - objects:Array<{absolute_url:string,id:number}>; - offset:number, - total:number, - limit:number -} \ No newline at end of file + objects: Array<{ absolute_url: string; id: number }>; + offset: number; + total: number; + limit: number; +}; diff --git a/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts index 5e4cd1bdce..1e73b2d36b 100644 --- a/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts +++ b/packages/pieces/community/hubspot/src/lib/triggers/new-engagement.ts @@ -29,7 +29,7 @@ const polling: Polling, Props> = { strategy: DedupeStrategy.TIMEBASED, async items({ auth, propsValue, lastFetchEpochMS }) { const eventType = propsValue.eventType; - let engagements = []; + const engagements = []; let hasMore = true; const qs: QueryParams = { limit: '100' };