diff --git a/packages/nodes-base/credentials/ClearbitApi.credentials.ts b/packages/nodes-base/credentials/ClearbitApi.credentials.ts new file mode 100644 index 0000000000..26432c2286 --- /dev/null +++ b/packages/nodes-base/credentials/ClearbitApi.credentials.ts @@ -0,0 +1,17 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class ClearbitApi implements ICredentialType { + name = 'clearbitApi'; + displayName = 'Clearbit API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Clearbit/Clearbit.node.ts b/packages/nodes-base/nodes/Clearbit/Clearbit.node.ts new file mode 100644 index 0000000000..e589f17621 --- /dev/null +++ b/packages/nodes-base/nodes/Clearbit/Clearbit.node.ts @@ -0,0 +1,154 @@ +import { + IExecuteFunctions, +} from 'n8n-core'; +import { + IDataObject, + INodeExecutionData, + INodeType, + INodeTypeDescription, +} from 'n8n-workflow'; +import { + clearbitApiRequest, +} from './GenericFunctions'; +import { + companyFields, + companyOperations, +} from './CompanyDescription'; +import { + personOperations, + personFields, +} from './PersonDescription'; + +export class Clearbit implements INodeType { + description: INodeTypeDescription = { + displayName: 'Clearbit', + name: 'clearbit', + icon: 'file:clearbit.png', + group: ['output'], + version: 1, + subtitle: '={{$parameter["operation"] + ":" + $parameter["resource"]}}', + description: 'Consume Clearbit API', + defaults: { + name: 'Clearbit', + color: '#219ef9', + }, + inputs: ['main'], + outputs: ['main'], + credentials: [ + { + name: 'clearbitApi', + required: true, + } + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + options: [ + { + name: 'Company', + value: 'company', + description: 'The Company API allows you to look up a company by their domain', + }, + { + name: 'Person', + value: 'person', + description: `The Person API lets you retrieve social information associated with an email address,
+ such as a person’s name, location and Twitter handle.` + }, + ], + default: 'company', + description: 'Resource to consume.', + }, + ...companyOperations, + ...companyFields, + ...personOperations, + ...personFields, + ], + }; + + async execute(this: IExecuteFunctions): Promise { + const items = this.getInputData(); + const returnData: IDataObject[] = []; + const length = items.length as unknown as number; + const qs: IDataObject = {}; + let responseData; + const resource = this.getNodeParameter('resource', 0) as string; + const operation = this.getNodeParameter('operation', 0) as string; + for (let i = 0; i < length; i++) { + if (resource === 'person') { + if (operation === 'enrich') { + const email = this.getNodeParameter('email', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + qs.email = email; + if (additionalFields.webhookUrl) { + qs.webhook_url = additionalFields.webhookUrl as string; + } + if (additionalFields.givenName) { + qs.given_name = additionalFields.givenName as string; + } + if (additionalFields.familyName) { + qs.family_name = additionalFields.familyName as string; + } + if (additionalFields.ipAddress) { + qs.ip_address = additionalFields.ipAddress as string; + } + if (additionalFields.location) { + qs.location = additionalFields.location as string; + } + if (additionalFields.company) { + qs.company = additionalFields.company as string; + } + if (additionalFields.companyDomain) { + qs.company_domain = additionalFields.companyDomain as string; + } + if (additionalFields.linkedin) { + qs.linkedin = additionalFields.linkedin as string; + } + if (additionalFields.twitter) { + qs.twitter = additionalFields.twitter as string; + } + if (additionalFields.facebook) { + qs.facebook = additionalFields.facebook as string; + } + responseData = await clearbitApiRequest.call(this, 'GET', resource, '/v2/people/find', {}, qs); + } + } + if (resource === 'company') { + if (operation === 'enrich') { + const domain = this.getNodeParameter('domain', i) as string; + const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; + qs.domain = domain; + if (additionalFields.webhookUrl) { + qs.webhook_url = additionalFields.webhookUrl as string; + } + if (additionalFields.companyName) { + qs.company_name = additionalFields.companyName as string; + } + if (additionalFields.linkedin) { + qs.linkedin = additionalFields.linkedin as string; + } + if (additionalFields.twitter) { + qs.twitter = additionalFields.twitter as string; + } + if (additionalFields.facebook) { + qs.facebook = additionalFields.facebook as string; + } + responseData = await clearbitApiRequest.call(this, 'GET', resource, '/v2/companies/find', {}, qs); + } + if (operation === 'autocomplete') { + const name = this.getNodeParameter('name', i) as string; + qs.query = name; + responseData = await clearbitApiRequest.call(this, 'GET', 'autocomplete', '/v1/companies/suggest', {}, qs); + } + } + if (Array.isArray(responseData)) { + returnData.push.apply(returnData, responseData as IDataObject[]); + } else { + returnData.push(responseData as IDataObject); + } + } + return [this.helpers.returnJsonArray(returnData)]; + } +} diff --git a/packages/nodes-base/nodes/Clearbit/CompanyDescription.ts b/packages/nodes-base/nodes/Clearbit/CompanyDescription.ts new file mode 100644 index 0000000000..abd998051c --- /dev/null +++ b/packages/nodes-base/nodes/Clearbit/CompanyDescription.ts @@ -0,0 +1,130 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const companyOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'company', + ], + }, + }, + options: [ + { + name: 'Enrich', + value: 'enrich', + description: 'Lets you look up person and company data based on an email or domain', + }, + { + name: 'Autocomplete', + value: 'autocomplete', + description: 'lets you auto-complete company names and retreive logo and domain', + }, + ], + default: 'enrich', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const companyFields = [ + +/* -------------------------------------------------------------------------- */ +/* company:enrich */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Domain', + name: 'domain', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'enrich', + ], + }, + }, + description: 'The domain to look up.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'enrich', + ], + }, + }, + options: [ + { + displayName: 'Webhook URL', + name: 'webhookUrl', + type: 'string', + default: '', + description: 'A webhook URL that results will be sent to.', + }, + { + displayName: 'Company Name', + name: 'companyName', + type: 'string', + default: '', + description: 'The name of the company.', + }, + { + displayName: 'Linkedin', + name: 'linkedin', + type: 'string', + default: '', + description: 'The LinkedIn URL for the company.', + }, + { + displayName: 'Twitter', + name: 'twitter', + type: 'string', + default: '', + description: 'The Twitter handle for the company.', + }, + { + displayName: 'Facebook', + name: 'facebook', + type: 'string', + default: '', + description: 'The Facebook URL for the company.', + }, + ], + }, +/* -------------------------------------------------------------------------- */ +/* company:autocomplete */ +/* -------------------------------------------------------------------------- */ +{ + displayName: 'Name', + name: 'name', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'company', + ], + operation: [ + 'autocomplete', + ], + }, + }, + description: 'Name is the partial name of the company.', +}, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts new file mode 100644 index 0000000000..bfe38e8991 --- /dev/null +++ b/packages/nodes-base/nodes/Clearbit/GenericFunctions.ts @@ -0,0 +1,32 @@ +import { OptionsWithUri } from 'request'; +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; +import { IDataObject } from 'n8n-workflow'; + +export async function clearbitApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, api: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('clearbitApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + let options: OptionsWithUri = { + headers: { Authorization: `Bearer ${credentials.apiKey}`}, + method, + qs, + body, + uri: uri ||`https://${api}.clearbit.com${resource}`, + json: true + }; + options = Object.assign({}, options, option); + if (Object.keys(options.body).length === 0) { + delete options.body; + } + try { + return await this.helpers.request!(options); + } catch (err) { + throw new Error(err); + } +} diff --git a/packages/nodes-base/nodes/Clearbit/PersonDescription.ts b/packages/nodes-base/nodes/Clearbit/PersonDescription.ts new file mode 100644 index 0000000000..a91fa0744e --- /dev/null +++ b/packages/nodes-base/nodes/Clearbit/PersonDescription.ts @@ -0,0 +1,139 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const personOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'person', + ], + }, + }, + options: [ + { + name: 'Enrich', + value: 'enrich', + description: 'Lets you look up person and company data based on an email or domain', + }, + ], + default: 'enrich', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const personFields = [ + +/* -------------------------------------------------------------------------- */ +/* person:enrich */ +/* -------------------------------------------------------------------------- */ + { + displayName: 'Email', + name: 'email', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'enrich', + ], + }, + }, + description: 'The email address to look up.', + }, + { + displayName: 'Additional Fields', + name: 'additionalFields', + type: 'collection', + placeholder: 'Add Field', + default: {}, + displayOptions: { + show: { + resource: [ + 'person', + ], + operation: [ + 'enrich', + ], + }, + }, + options: [ + { + displayName: 'Webhook URL', + name: 'webhookUrl', + type: 'string', + default: '', + description: 'A webhook URL that results will be sent to.', + }, + { + displayName: 'Given Name', + name: 'givenName', + type: 'string', + default: '', + description: 'First name of person.', + }, + { + displayName: 'Family Name', + name: 'familyName', + type: 'string', + default: '', + description: 'Last name of person. If you have this, passing this is strongly recommended to improve match rates.', + }, + { + displayName: 'IP Address', + name: 'ipAddress', + type: 'string', + default: '', + description: 'IP address of the person. If you have this, passing this is strongly recommended to improve match rates.', + }, + { + displayName: 'Location', + name: 'location', + type: 'string', + default: '', + description: 'The city or country where the person resides.', + }, + { + displayName: 'Company', + name: 'company', + type: 'string', + default: '', + description: 'The name of the person’s employer.', + }, + { + displayName: 'Company Domain', + name: 'companyDomain', + type: 'string', + default: '', + description: 'The domain for the person’s employer.', + }, + { + displayName: 'Linkedin', + name: 'linkedin', + type: 'string', + default: '', + description: 'The LinkedIn URL for the person.', + }, + { + displayName: 'Twitter', + name: 'twitter', + type: 'string', + default: '', + description: 'The Twitter handle for the person.', + }, + { + displayName: 'Facebook', + name: 'facebook', + type: 'string', + default: '', + description: 'The Facebook URL for the person.', + }, + ], + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Clearbit/clearbit.png b/packages/nodes-base/nodes/Clearbit/clearbit.png new file mode 100644 index 0000000000..69af5011c9 Binary files /dev/null and b/packages/nodes-base/nodes/Clearbit/clearbit.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index d3fe3ad092..5d52182543 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -38,6 +38,7 @@ "dist/credentials/ClickUpApi.credentials.js", "dist/credentials/CodaApi.credentials.js", "dist/credentials/CopperApi.credentials.js", + "dist/credentials/ClearbitApi.credentials.js", "dist/credentials/DisqusApi.credentials.js", "dist/credentials/DropboxApi.credentials.js", "dist/credentials/EventbriteApi.credentials.js", @@ -112,6 +113,7 @@ "dist/nodes/ClickUp/ClickUpTrigger.node.js", "dist/nodes/Coda/Coda.node.js", "dist/nodes/Copper/CopperTrigger.node.js", + "dist/nodes/Clearbit/Clearbit.node.js", "dist/nodes/Cron.node.js", "dist/nodes/Discord/Discord.node.js", "dist/nodes/Disqus/Disqus.node.js",