diff --git a/packages/cli/BREAKING-CHANGES.md b/packages/cli/BREAKING-CHANGES.md index 9269427ae0..c0c008a5f8 100644 --- a/packages/cli/BREAKING-CHANGES.md +++ b/packages/cli/BREAKING-CHANGES.md @@ -2,6 +2,28 @@ This list shows all the versions which include breaking changes and how to upgrade. +## 0.83.0 + +### What changed? + +In the Active Campaign Node, we have changed how the operation `getAll` works on various resources to keep consistency across them. To achive this a new parameter called 'Simple' was added. + +### When is action necessary? + +When one of the following resources/operations is used: + +| Resource | Operation | +|--|--| +| Deal | Get All | +| Connector | Get All | +| E-commerce Order | Get All | +| E-commerce Customer | Get All | +| E-commerce Order Products | Get All | + +### How to upgrade: + +Open the affected resource/operation and set the parameter `Simple` to false. + ## 0.79.0 ### What changed? diff --git a/packages/nodes-base/nodes/ActiveCampaign/AccountContactDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/AccountContactDescription.ts new file mode 100644 index 0000000000..5a88c8a4e9 --- /dev/null +++ b/packages/nodes-base/nodes/ActiveCampaign/AccountContactDescription.ts @@ -0,0 +1,175 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const accountContactOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'accountContact', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an association', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an association', + }, + { + name: 'Update', + value: 'update', + description: 'Update an association', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const accountContactFields = [ + // ---------------------------------- + // accountContact:create + // ---------------------------------- + { + displayName: 'Account ID', + name: 'account', + type: 'number', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'accountContact', + ], + }, + }, + description: 'Account ID', + }, + { + displayName: 'Contact ID', + name: 'contact', + type: 'number', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'accountContact', + ], + }, + }, + description: 'Contact ID', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'accountContact', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Job title', + name: 'jobTitle', + type: 'string', + default: '', + description: 'Job Title of the contact at the account', + }, + ], + }, + // ---------------------------------- + // accountContact:delete + // ---------------------------------- + { + displayName: 'Account Contact ID', + name: 'accountContactId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'accountContact', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the account contact to delete.', + }, + // ---------------------------------- + // accountContact:update + // ---------------------------------- + { + displayName: 'Account Contact ID', + name: 'accountContactId', + type: 'number', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'accountContact', + ], + }, + }, + description: 'Account ID', + }, + + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + description: 'The fields to update.', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'accountContact', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Job title', + name: 'jobTitle', + type: 'string', + default: '', + description: 'Job Title of the contact at the account', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/AccountDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/AccountDescription.ts new file mode 100644 index 0000000000..bc91bcef0d --- /dev/null +++ b/packages/nodes-base/nodes/ActiveCampaign/AccountDescription.ts @@ -0,0 +1,302 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; + +export const accountOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'account', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create an account', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete an account', + }, + { + name: 'Get', + value: 'get', + description: 'Get data of an account', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get data of all accounts', + }, + { + name: 'Update', + value: 'update', + description: 'Update an account', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const accountFields = [ + // ---------------------------------- + // contact:create + // ---------------------------------- + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'account', + ], + }, + }, + description: 'Account\'s name.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'account', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Account URL', + name: 'accountUrl', + type: 'string', + default: '', + description: `Account's website`, + }, + { + displayName: 'Fields', + name: 'fields', + placeholder: 'Add Custom Fields', + description: 'Adds a custom fields to set also values which have not been predefined.', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'property', + displayName: 'Field', + values: [ + { + displayName: 'Field ID', + name: 'customFieldId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getAccountCustomFields', + }, + default: '', + description: 'ID of the field to set.', + }, + { + displayName: 'Field Value', + name: 'fieldValue', + type: 'string', + default: '', + description: 'Value of the field to set.', + }, + ], + }, + ], + }, + ], + }, + + // ---------------------------------- + // contact:update + // ---------------------------------- + { + displayName: 'Account ID', + name: 'accountId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'account', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the account to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + description: 'The fields to update.', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'account', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + description: 'Account\'s name.', + }, + { + displayName: 'Account URL', + name: 'accountUrl', + type: 'string', + default: '', + description: 'Account\'s website', + }, + { + displayName: 'Fields', + name: 'fields', + placeholder: 'Add Fields', + description: 'Adds a custom fields to set also values which have not been predefined.', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'property', + displayName: 'Field', + values: [ + { + displayName: 'Field ID', + name: 'customFieldId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getAccountCustomFields', + }, + default: '', + description: 'ID of the field to set.', + }, + { + displayName: 'Field Value', + name: 'fieldValue', + type: 'string', + default: '', + description: 'Value of the field to set.', + }, + ], + }, + ], + }, + ], + }, + // ---------------------------------- + // account:delete + // ---------------------------------- + { + displayName: 'Account ID', + name: 'accountId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'account', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the account to delete.', + }, + // ---------------------------------- + // account:get + // ---------------------------------- + { + displayName: 'Account ID', + name: 'accountId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'account', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the account to get.', + }, + // ---------------------------------- + // account:getAll + // ---------------------------------- + ...activeCampaignDefaultGetAllProperties('account', 'getAll'), + { + displayName: 'Filters', + name: 'filters', + type: 'collection', + placeholder: 'Add Filter', + displayOptions: { + show: { + operation: [ + 'getAll', + ], + resource: [ + 'account', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Search', + name: 'search', + type: 'string', + default: '', + description: 'Search by name', + }, + ], + }, + +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/ActiveCampaign.node.ts b/packages/nodes-base/nodes/ActiveCampaign/ActiveCampaign.node.ts index a7b47f6e20..1683ff5b09 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/ActiveCampaign.node.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/ActiveCampaign.node.ts @@ -7,6 +7,8 @@ import { INodeTypeDescription, INodeExecutionData, INodeType, + ILoadOptionsFunctions, + INodePropertyOptions, } from 'n8n-workflow'; import { @@ -45,12 +47,31 @@ import { connectionFields } from './ConnectionDescription'; +import { + accountFields, + accountOperations +} from "./AccountDescription"; + +import { + tagFields, + tagOperations +} from "./TagDescription"; + +import { + accountContactFields, + accountContactOperations +} from "./AccountContactDescription"; + +import { + contactTagFields, + contactTagOperations, +} from "./ContactTagDescription"; + interface CustomProperty { name: string; value: string; } - /** * Add the additional fields to the body * @@ -63,6 +84,10 @@ function addAdditionalFields(body: IDataObject, additionalFields: IDataObject) { for (const customProperty of (additionalFields.customProperties as IDataObject)!.property! as CustomProperty[]) { body[customProperty.name] = customProperty.value; } + } else if (key === 'fieldValues' && (additionalFields.fieldValues as IDataObject).property !== undefined) { + body.fieldValues = (additionalFields.fieldValues as IDataObject).property; + } else if (key === 'fields' && (additionalFields.fields as IDataObject).property !== undefined) { + body.fields = (additionalFields.fields as IDataObject).property; } else { body[key] = additionalFields[key]; } @@ -88,7 +113,7 @@ export class ActiveCampaign implements INodeType { { name: 'activeCampaignApi', required: true, - } + }, ], properties: [ // ---------------------------------- @@ -99,18 +124,30 @@ export class ActiveCampaign implements INodeType { name: 'resource', type: 'options', options: [ + { + name: 'Account', + value: 'account', + }, + { + name: 'Account Contact', + value: 'accountContact', + }, { name: 'Contact', value: 'contact', }, { - name: 'Deal', - value: 'deal', + name: 'Contact Tag', + value: 'contactTag', }, { name: 'Connection', value: 'connection' }, + { + name: 'Deal', + value: 'deal', + }, { name: 'E-commerce Order', value: 'ecommerceOrder', @@ -122,7 +159,11 @@ export class ActiveCampaign implements INodeType { { name: 'E-commerce Order Products', value: 'ecommerceOrderProducts' - } + }, + { + name: 'Tag', + value: 'tag', + }, ], default: 'contact', description: 'The resource to operate on.', @@ -131,7 +172,11 @@ export class ActiveCampaign implements INodeType { // ---------------------------------- // operations // ---------------------------------- + ...accountOperations, ...contactOperations, + ...accountContactOperations, + ...contactTagOperations, + ...tagOperations, ...dealOperations, ...connectionOperations, ...ecomOrderOperations, @@ -141,6 +186,26 @@ export class ActiveCampaign implements INodeType { // ---------------------------------- // fields // ---------------------------------- + // ---------------------------------- + // tag + // ---------------------------------- + ...tagFields, + + // ---------------------------------- + // tag + // ---------------------------------- + ...contactTagFields, + + // ---------------------------------- + // account + // ---------------------------------- + ...accountFields, + + // ---------------------------------- + // account + // ---------------------------------- + ...accountContactFields, + // ---------------------------------- // contact // ---------------------------------- @@ -174,6 +239,40 @@ export class ActiveCampaign implements INodeType { ], }; + methods = { + loadOptions: { + // Get all the available custom fields to display them to user so that he can + // select them easily + async getContactCustomFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { fields } = await activeCampaignApiRequest.call(this, 'GET', '/api/3/fields', {}); + for (const field of fields) { + const fieldName = field.title; + const fieldId = field.id; + returnData.push({ + name: fieldName, + value: fieldId, + }); + } + return returnData; + }, + // Get all the available custom fields to display them to user so that he can + // select them easily + async getAccountCustomFields(this: ILoadOptionsFunctions): Promise { + const returnData: INodePropertyOptions[] = []; + const { accountCustomFieldMeta: fields } = await activeCampaignApiRequest.call(this, 'GET', '/api/3/accountCustomFieldMeta', {}); + for (const field of fields) { + const fieldName = field.fieldLabel; + const fieldId = field.id; + returnData.push({ + name: fieldName, + value: fieldId, + }); + } + return returnData; + }, + }, + }; async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); @@ -254,11 +353,24 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; returnAll = this.getNodeParameter('returnAll', i) as boolean; + const simple = this.getNodeParameter('simple', i, true) as boolean; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } - dataKey = 'contacts'; + Object.assign(qs, additionalFields); + + if (qs.orderBy) { + qs[qs.orderBy as string] = true; + delete qs.orderBy; + } + + if (simple === true) { + dataKey = 'contacts'; + } + endpoint = `/api/3/contacts`; } else if (operation === 'update') { @@ -278,6 +390,246 @@ export class ActiveCampaign implements INodeType { const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; addAdditionalFields(body.contact as IDataObject, updateFields); + } else { + throw new Error(`The operation "${operation}" is not known`); + } + } else if (resource === 'account') { + if (operation === 'create') { + // ---------------------------------- + // account:create + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = '/api/3/accounts'; + + dataKey = 'account'; + + body.account = { + name: this.getNodeParameter('name', i) as string, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + addAdditionalFields(body.account as IDataObject, additionalFields); + + } else if (operation === 'delete') { + // ---------------------------------- + // account:delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const accountId = this.getNodeParameter('accountId', i) as number; + endpoint = `/api/3/accounts/${accountId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // account:get + // ---------------------------------- + + requestMethod = 'GET'; + + const accountId = this.getNodeParameter('accountId', i) as number; + endpoint = `/api/3/accounts/${accountId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // account:getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const simple = this.getNodeParameter('simple', i, true) as boolean; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + if (returnAll === false) { + qs.limit = this.getNodeParameter('limit', i) as number; + } + + if (simple === true) { + dataKey = 'accounts'; + } + + endpoint = `/api/3/accounts`; + + const filters = this.getNodeParameter('filters', i) as IDataObject; + Object.assign(qs, filters); + + } else if (operation === 'update') { + // ---------------------------------- + // account:update + // ---------------------------------- + + requestMethod = 'PUT'; + + const accountId = this.getNodeParameter('accountId', i) as number; + endpoint = `/api/3/accounts/${accountId}`; + + dataKey = 'account'; + + body.account = {} as IDataObject; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + addAdditionalFields(body.account as IDataObject, updateFields); + + } else { + throw new Error(`The operation "${operation}" is not known`); + } + } else if (resource === 'accountContact') { + if (operation === 'create') { + // ---------------------------------- + // account:create + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = '/api/3/accountContacts'; + + dataKey = 'accountContact'; + + body.accountContact = { + contact: this.getNodeParameter('contact', i) as string, + account: this.getNodeParameter('account', i) as string, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + addAdditionalFields(body.account as IDataObject, additionalFields); + + } else if (operation === 'update') { + // ---------------------------------- + // accountContact:update + // ---------------------------------- + + requestMethod = 'PUT'; + + const accountContactId = this.getNodeParameter('accountContactId', i) as number; + endpoint = `/api/3/accountContacts/${accountContactId}`; + + dataKey = 'accountContact'; + + body.accountContact = {} as IDataObject; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + addAdditionalFields(body.accountContact as IDataObject, updateFields); + + } else if (operation === 'delete') { + // ---------------------------------- + // accountContact:delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const accountContactId = this.getNodeParameter('accountContactId', i) as number; + endpoint = `/api/3/accountContacts/${accountContactId}`; + + } else { + throw new Error(`The operation "${operation}" is not known`); + } + } else if (resource === 'contactTag') { + if (operation === 'add') { + // ---------------------------------- + // contactTag:add + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = '/api/3/contactTags'; + + dataKey = 'contactTag'; + + body.contactTag = { + contact: this.getNodeParameter('contactId', i) as string, + tag: this.getNodeParameter('tagId', i) as string, + } as IDataObject; + + } else if (operation === 'remove') { + // ---------------------------------- + // contactTag:remove + // ---------------------------------- + + requestMethod = 'DELETE'; + + const contactTagId = this.getNodeParameter('contactTagId', i) as number; + endpoint = `/api/3/contactTags/${contactTagId}`; + + } else { + throw new Error(`The operation "${operation}" is not known`); + } + } else if (resource === 'tag') { + if (operation === 'create') { + // ---------------------------------- + // tag:create + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = '/api/3/tags'; + + dataKey = 'tag'; + + body.tag = { + tag: this.getNodeParameter('name', i) as string, + tagType: this.getNodeParameter('tagType', i) as string, + } as IDataObject; + + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + addAdditionalFields(body.tag as IDataObject, additionalFields); + + } else if (operation === 'delete') { + // ---------------------------------- + // tag:delete + // ---------------------------------- + + requestMethod = 'DELETE'; + + const tagId = this.getNodeParameter('tagId', i) as number; + endpoint = `/api/3/tags/${tagId}`; + + } else if (operation === 'get') { + // ---------------------------------- + // tag:get + // ---------------------------------- + + requestMethod = 'GET'; + + const tagId = this.getNodeParameter('tagId', i) as number; + endpoint = `/api/3/tags/${tagId}`; + + } else if (operation === 'getAll') { + // ---------------------------------- + // tags:getAll + // ---------------------------------- + + requestMethod = 'GET'; + + const simple = this.getNodeParameter('simple', i, true) as boolean; + returnAll = this.getNodeParameter('returnAll', i) as boolean; + if (returnAll === false) { + qs.limit = this.getNodeParameter('limit', i) as number; + } + + if (simple === true) { + dataKey = 'tags'; + } + + endpoint = `/api/3/tags`; + + } else if (operation === 'update') { + // ---------------------------------- + // tags:update + // ---------------------------------- + + requestMethod = 'PUT'; + + const tagId = this.getNodeParameter('tagId', i) as number; + endpoint = `/api/3/tags/${tagId}`; + + dataKey = 'tag'; + + body.tag = {} as IDataObject; + + const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; + addAdditionalFields(body.tag as IDataObject, updateFields); + } else { throw new Error(`The operation "${operation}" is not known`); } @@ -358,11 +710,16 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + const simple = this.getNodeParameter('simple', i, true) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } + if (simple === true) { + dataKey = 'deals'; + } + endpoint = `/api/3/deals`; } else if (operation === 'createNote') { @@ -455,11 +812,16 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + const simple = this.getNodeParameter('simple', i, true) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } + if (simple === true) { + dataKey = 'connections'; + } + endpoint = `/api/3/connections`; } else { @@ -548,11 +910,16 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + const simple = this.getNodeParameter('simple', i, true) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } + if (simple === true) { + dataKey = 'ecomOrders'; + } + endpoint = `/api/3/ecomOrders`; } else { @@ -633,11 +1000,16 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + const simple = this.getNodeParameter('simple', i, true) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } + if (simple === true) { + dataKey = 'ecomCustomers'; + } + endpoint = `/api/3/ecomCustomers`; } else { @@ -662,6 +1034,8 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + //dataKey = 'ecomOrderProducts'; + const orderId = this.getNodeParameter('orderId', i) as number; endpoint = `/api/3/ecomOrders/${orderId}/orderProducts`; @@ -672,11 +1046,16 @@ export class ActiveCampaign implements INodeType { requestMethod = 'GET'; + const simple = this.getNodeParameter('simple', i, true) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll === false) { qs.limit = this.getNodeParameter('limit', i) as number; } + if (simple === true) { + dataKey = 'ecomOrderProducts'; + } + endpoint = `/api/3/ecomOrderProducts`; } else { @@ -703,4 +1082,4 @@ export class ActiveCampaign implements INodeType { return [this.helpers.returnJsonArray(returnData)]; } -} \ No newline at end of file +} diff --git a/packages/nodes-base/nodes/ActiveCampaign/ConnectionDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/ConnectionDescription.ts index e962e4041d..20700a3746 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/ConnectionDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/ConnectionDescription.ts @@ -1,4 +1,10 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from "n8n-workflow"; + +import { + activeCampaignDefaultGetAllProperties, +} from "./GenericFunctions"; export const connectionOperations = [ { @@ -278,45 +284,6 @@ export const connectionFields = [ // ---------------------------------- // connection:getAll // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'connection', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'connection', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, + ...activeCampaignDefaultGetAllProperties('connection', 'getAll'), + ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/ContactDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/ContactDescription.ts index 25b42b3678..ce492cd8d9 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/ContactDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/ContactDescription.ts @@ -1,4 +1,10 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; export const contactOperations = [ { @@ -100,6 +106,42 @@ export const contactFields = [ }, default: {}, options: [ + { + displayName: 'Custom Fields', + name: 'fieldValues', + placeholder: 'Add Custom Fields', + description: 'Adds a custom fields to set also values which have not been predefined.', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'property', + displayName: 'Custom Field', + values: [ + { + displayName: 'Field ID', + name: 'field', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getContactCustomFields', + }, + default: '', + description: 'ID of the field to set.', + }, + { + displayName: 'Field Value', + name: 'value', + type: 'string', + default: '', + description: 'Value of the field to set.', + }, + ] + }, + ], + }, { displayName: 'First Name', name: 'firstName', @@ -121,39 +163,6 @@ export const contactFields = [ default: '', description: 'Phone number of the contact.', }, - { - displayName: 'Custom Properties', - name: 'customProperties', - placeholder: 'Add Custom Property', - description: 'Adds a custom property to set also values which have not been predefined.', - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - default: {}, - options: [ - { - name: 'property', - displayName: 'Property', - values: [ - { - displayName: 'Property Name', - name: 'name', - type: 'string', - default: '', - description: 'Name of the property to set.', - }, - { - displayName: 'Property Value', - name: 'value', - type: 'string', - default: '', - description: 'Value of the property to set.', - }, - ] - }, - ], - }, ], }, @@ -196,6 +205,42 @@ export const contactFields = [ }, default: {}, options: [ + { + displayName: 'Custom Fields', + name: 'fieldValues', + placeholder: 'Add Custom Fields', + description: 'Adds a custom fields to set also values which have not been predefined.', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + }, + default: {}, + options: [ + { + name: 'property', + displayName: 'Custom Field', + values: [ + { + displayName: 'Field ID', + name: 'field', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getContactCustomFields', + }, + default: '', + description: 'ID of the field to set.', + }, + { + displayName: 'Field Value', + name: 'value', + type: 'string', + default: '', + description: 'Value of the field to set.', + }, + ] + }, + ], + }, { displayName: 'Email', name: 'email', @@ -224,39 +269,6 @@ export const contactFields = [ default: '', description: 'Phone number of the contact.', }, - { - displayName: 'Custom Properties', - name: 'customProperties', - placeholder: 'Add Custom Property', - description: 'Adds a custom property to set also values which have not been predefined.', - type: 'fixedCollection', - typeOptions: { - multipleValues: true, - }, - default: {}, - options: [ - { - name: 'property', - displayName: 'Property', - values: [ - { - displayName: 'Property Name', - name: 'name', - type: 'string', - default: '', - description: 'Name of the property to set.', - }, - { - displayName: 'Property Value', - name: 'value', - type: 'string', - default: '', - description: 'Value of the property to set.', - }, - ] - }, - ], - }, ], }, @@ -307,10 +319,12 @@ export const contactFields = [ // ---------------------------------- // contact:getAll // ---------------------------------- + ...activeCampaignDefaultGetAllProperties('contact', 'getAll'), { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', displayOptions: { show: { operation: [ @@ -321,31 +335,179 @@ export const contactFields = [ ], }, }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'contact', - ], - returnAll: [ - false, - ], + default: {}, + options: [ + { + displayName: 'Datetime', + name: 'datetime', + type: 'dateTime', + default: '', + description: 'Contacts created on the specified date', }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + description: 'Email address of the contact you want to get', + }, + { + displayName: 'Email Like', + name: 'email_like', + type: 'string', + default: '', + description: 'Filter contacts that contain the given value in the email address', + }, + { + displayName: 'Exclude', + name: 'exclude', + type: 'string', + default: '', + description: 'Exclude from the response the contact with the given ID', + }, + { + displayName: 'Form ID', + name: 'formid', + type: 'string', + default: '', + description: 'Filter contacts associated with the given form', + }, + { + displayName: 'List ID', + name: 'listid', + type: 'string', + default: '', + description: 'Filter contacts associated with the given list', + }, + { + displayName: 'Search', + name: 'search', + type: 'string', + default: '', + description: 'Filter contacts that match the given value in the contact names, organization, phone or email', + }, + { + displayName: 'Segment ID', + name: 'segmentid', + type: 'string', + default: '', + description: 'Return only contacts that match a list segment', + }, + { + displayName: 'Series ID', + name: 'seriesid', + type: 'string', + default: '', + description: 'Filter contacts associated with the given automation', + }, + { + displayName: 'Status', + name: 'status', + type: 'options', + options: [ + { + name: 'Any', + value: -1, + }, + { + name: 'Unconfirmed', + value: 0, + }, + { + name: 'Active', + value: 1, + }, + { + name: 'Unsubscribed', + value: 2, + }, + { + name: 'Bounced', + value: 3, + }, + ], + default: '', + }, + { + displayName: 'Tag ID', + name: 'tagid', + type: 'string', + default: '', + description: 'Filter contacts associated with the given tag', + }, + { + displayName: 'Created Before', + name: 'filters[created_before]', + type: 'dateTime', + default: '', + description: 'Filter contacts that were created prior to this date', + }, + { + displayName: 'Created After', + name: 'filters[created_after]', + type: 'dateTime', + default: '', + description: 'Filter contacts that were created after this date', + }, + { + displayName: 'Updated Before', + name: 'filters[updated_before]', + type: 'dateTime', + default: '', + description: 'Filter contacts that were updated before this date', + }, + { + displayName: 'Updated After', + name: 'filters[updated_after]', + type: 'dateTime', + default: '', + description: 'Filter contacts that were updated after this date', + }, + { + displayName: 'Wait ID', + name: 'waitid', + type: 'string', + default: '', + description: 'Filter by contacts in the wait queue of an automation block', + }, + { + displayName: 'Order By', + name: 'orderBy', + type: 'options', + options: [ + { + name: 'Creation Date', + value: 'orders[cdate]', + description: 'Order contacts by creation date', + }, + { + name: 'Email', + value: 'orders[email]', + description: 'Order contacts by email', + }, + { + name: 'First Name', + value: 'orders[first_name]', + description: 'Order contacts by first name', + }, + { + name: 'Last Name', + value: 'orders[last_name]', + description: 'Order contacts by last name', + }, + { + name: 'Name', + value: 'orders[name]', + description: 'Order contacts by full name', + }, + { + name: 'Score', + value: 'orders[score]', + description: 'Order contacts by score', + }, + ], + default: '', + }, + ], }, ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/ContactTagDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/ContactTagDescription.ts new file mode 100644 index 0000000000..59e823d9a6 --- /dev/null +++ b/packages/nodes-base/nodes/ActiveCampaign/ContactTagDescription.ts @@ -0,0 +1,95 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const contactTagOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'contactTag', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'add', + description: 'Add a tag to a contact', + }, + { + name: 'Remove', + value: 'remove', + description: 'Remove a tag from a contact', + }, + ], + default: 'add', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const contactTagFields = [ + // ---------------------------------- + // contactTag:add + // ---------------------------------- + { + displayName: 'Tag ID', + name: 'tagId', + type: 'number', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'add', + ], + resource: [ + 'contactTag', + ], + }, + }, + description: 'Tag ID', + }, + { + displayName: 'Contact ID', + name: 'contactId', + type: 'number', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'add', + ], + resource: [ + 'contactTag', + ], + }, + }, + description: 'Contact ID', + }, + // ---------------------------------- + // contactTag:delete + // ---------------------------------- + { + displayName: 'Contact Tag ID', + name: 'contactTagId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'remove', + ], + resource: [ + 'contactTag', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the contact tag to delete.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/DealDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/DealDescription.ts index 9d61c43395..95bd83bf89 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/DealDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/DealDescription.ts @@ -1,6 +1,14 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from "n8n-workflow"; -import { allCurrencies } from './currencies'; +import { + allCurrencies, +} from './currencies'; + +import { + activeCampaignDefaultGetAllProperties, +} from "./GenericFunctions"; export const dealOperations = [ { @@ -387,47 +395,7 @@ export const dealFields = [ // ---------------------------------- // deal:getAll // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'deal', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'deal', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, + ...activeCampaignDefaultGetAllProperties('deal', 'getAll'), // ---------------------------------- // dealNote:create diff --git a/packages/nodes-base/nodes/ActiveCampaign/EcomCustomerDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/EcomCustomerDescription.ts index 2b8b0d33cd..0093074413 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/EcomCustomerDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/EcomCustomerDescription.ts @@ -1,4 +1,10 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; export const ecomCustomerOperations = [ { @@ -246,45 +252,5 @@ export const ecomCustomerFields = [ // ---------------------------------- // ecommerceCustomer:getAll // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceCustomer', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceCustomer', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, + ...activeCampaignDefaultGetAllProperties('ecommerceCustomer', 'getAll'), ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/EcomOrderDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/EcomOrderDescription.ts index 752b551ad1..b57d9b966a 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/EcomOrderDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/EcomOrderDescription.ts @@ -1,6 +1,14 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from "n8n-workflow"; -import { allCurrencies } from './currencies'; +import { + allCurrencies, +} from './currencies'; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; export const ecomOrderOperations = [ { @@ -672,45 +680,6 @@ export const ecomOrderFields = [ // ---------------------------------- // ecommerceOrder:getAll // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceOrder', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceOrder', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, + ...activeCampaignDefaultGetAllProperties('ecommerceOrder', 'getAll'), + ] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/EcomOrderProductsDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/EcomOrderProductsDescription.ts index 1f53c47f0b..5613bff044 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/EcomOrderProductsDescription.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/EcomOrderProductsDescription.ts @@ -1,4 +1,10 @@ -import { INodeProperties } from "n8n-workflow"; +import { + INodeProperties, +} from "n8n-workflow"; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; export const ecomOrderProductsOperations = [ { @@ -80,45 +86,5 @@ export const ecomOrderProductsFields = [ // ---------------------------------- // ecommerceOrderProducts:getAll // ---------------------------------- - { - displayName: 'Return All', - name: 'returnAll', - type: 'boolean', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceOrderProducts', - ], - }, - }, - default: false, - description: 'If all results should be returned or only up to a given limit.', - }, - { - displayName: 'Limit', - name: 'limit', - type: 'number', - displayOptions: { - show: { - operation: [ - 'getAll', - ], - resource: [ - 'ecommerceOrderProducts', - ], - returnAll: [ - false, - ], - }, - }, - typeOptions: { - minValue: 1, - maxValue: 500, - }, - default: 100, - description: 'How many results to return.', - }, -] as INodeProperties[]; \ No newline at end of file + ...activeCampaignDefaultGetAllProperties('ecommerceOrderProducts', 'getAll'), +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts index 833e334b92..99ebaed623 100644 --- a/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ActiveCampaign/GenericFunctions.ts @@ -4,7 +4,7 @@ import { } from 'n8n-core'; import { - IDataObject, ILoadOptionsFunctions, + IDataObject, ILoadOptionsFunctions, INodeProperties, } from 'n8n-workflow'; import { OptionsWithUri } from 'request'; @@ -49,6 +49,8 @@ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFu options.body = body; } + console.log(options); + try { const responseData = await this.helpers.request!(options); @@ -124,3 +126,66 @@ export async function activeCampaignApiRequestAllItems(this: IHookFunctions | IE return returnData; } + +export function activeCampaignDefaultGetAllProperties (resource: string, operation: string): INodeProperties [] { + return [ + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + operation: [ + operation, + ], + resource: [ + resource, + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + displayOptions: { + show: { + operation: [ + operation, + ], + resource: [ + resource, + ], + returnAll: [ + false, + ], + }, + }, + typeOptions: { + minValue: 1, + maxValue: 500, + }, + default: 100, + description: 'How many results to return.', + }, + { + displayName: 'Simple', + name: 'simple', + type: 'boolean', + displayOptions: { + show: { + operation: [ + operation, + ], + resource: [ + resource, + ], + }, + }, + default: true, + description: 'When set to true a simplify version of the response will be used else the raw data will be used', + }, + ]; +} diff --git a/packages/nodes-base/nodes/ActiveCampaign/TagDescription.ts b/packages/nodes-base/nodes/ActiveCampaign/TagDescription.ts new file mode 100644 index 0000000000..87f307fcda --- /dev/null +++ b/packages/nodes-base/nodes/ActiveCampaign/TagDescription.ts @@ -0,0 +1,232 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +import { + activeCampaignDefaultGetAllProperties, +} from './GenericFunctions'; + +export const tagOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'tag', + ], + }, + }, + options: [ + { + name: 'Create', + value: 'create', + description: 'Create a tag', + }, + { + name: 'Delete', + value: 'delete', + description: 'Delete a tag', + }, + { + name: 'Get', + value: 'get', + description: 'Get data of a tag', + }, + { + name: 'Get All', + value: 'getAll', + description: 'Get data of all tags', + }, + { + name: 'Update', + value: 'update', + description: 'Update a tag', + }, + ], + default: 'create', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const tagFields = [ + // ---------------------------------- + // contact:create + // ---------------------------------- + { + displayName: 'Type', + name: 'tagType', + type: 'options', + default: 'contact', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'tag', + ], + }, + }, + options: [ + { + name: 'Contact', + value: 'contact', + description: 'Tag contact', + }, + { + name: 'Template', + value: 'template', + description: 'Tag template', + }, + ], + description: 'Tag-type of the new tag', + }, + { + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'tag', + ], + }, + }, + description: 'Name of the new tag', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'create', + ], + resource: [ + 'tag', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'Description of the new tag', + }, + ], + }, + // ---------------------------------- + // tag:update + // ---------------------------------- + { + displayName: 'Tag ID', + name: 'tagId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'tag', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the tag to update.', + }, + { + displayName: 'Update Fields', + name: 'updateFields', + type: 'collection', + description: 'The fields to update.', + placeholder: 'Add Field', + displayOptions: { + show: { + operation: [ + 'update', + ], + resource: [ + 'tag', + ], + }, + }, + default: {}, + options: [ + { + displayName: 'Tag', + name: 'tag', + type: 'string', + default: '', + description: 'Name of the contact.', + }, + { + displayName: 'Description', + name: 'description', + type: 'string', + default: '', + description: 'Description of the tag being updated', + }, + ], + }, + // ---------------------------------- + // tag:delete + // ---------------------------------- + { + displayName: 'Tag ID', + name: 'tagId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'delete', + ], + resource: [ + 'tag', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the tag to delete.', + }, + // ---------------------------------- + // contact:get + // ---------------------------------- + { + displayName: 'Tag ID', + name: 'tagId', + type: 'number', + displayOptions: { + show: { + operation: [ + 'get', + ], + resource: [ + 'tag', + ], + }, + }, + default: 0, + required: true, + description: 'ID of the tag to get.', + }, + // ---------------------------------- + // tag:getAll + // ---------------------------------- + ...activeCampaignDefaultGetAllProperties('tag', 'getAll') +] as INodeProperties[];