node setup

This commit is contained in:
Rupenieks 2020-04-30 14:03:36 +02:00
parent 976e02efcc
commit 9ac9ff3557
7 changed files with 723 additions and 0 deletions

View file

@ -0,0 +1,23 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
export class AgileCrmApi implements ICredentialType {
name = 'agileCrmApi';
displayName = 'AgileCRM API';
properties = [
{
displayName: 'Email',
name: 'email',
type: 'string' as NodePropertyTypes,
default: '',
},
{
displayName: 'API Key',
name: 'apiKey',
type: 'string' as NodePropertyTypes,
default: '',
},
];
}

View file

@ -0,0 +1,148 @@
import { IExecuteFunctions } from 'n8n-core';
import {
INodeExecutionData,
INodeType,
INodeTypeDescription,
IDataObject
} from 'n8n-workflow';
import {
contactOperations,
contactFields
} from './ContactDescription';
import { agileCrmApiRequest, validateJSON} from './GenericFunctions';
import { IContact, IProperty } from './ContactInterface';
export class AgileCrm implements INodeType {
description: INodeTypeDescription = {
displayName: 'AgileCRM',
name: 'agileCrm',
icon: 'file:agilecrm.png',
group: ['transform'],
version: 1,
description: 'Consume AgileCRM API',
defaults: {
name: 'AgileCRM',
color: '#772244',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'agileCrmApi',
required: true,
}
],
properties: [
// Node properties which the user gets displayed and
// can change on the node.
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Contact',
value: 'contact'
}
],
default: 'contact',
description: 'Resource to consume.',
},
// CONTACT
...contactOperations,
...contactFields,
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const length = items.length as unknown as number;
let responseData;
const qs: IDataObject = {};
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 === 'contact'){
if(operation === 'get'){
const contactId = this.getNodeParameter('contactId', i) as string;
const endpoint = `api/contacts/${contactId}`;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint);
}
if(operation === 'getAll'){
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
if (returnAll) {
const endpoint = `api/contacts`;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint);
} else {
const limit = this.getNodeParameter('limit', i) as number;
const endpoint = `api/contacts?page_size=${limit}`;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint);
}
}
if(operation === 'create'){
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
const body: IContact = {};
if (jsonParameters) {
const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string;
if (additionalFieldsJson !== '' ) {
if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson));
} else {
throw new Error('Additional fields must be a valid JSON');
}
}
} else {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
if (additionalFields.starValue) {
body.star_value = additionalFields.starValue as string;
}
if (additionalFields.leadScore) {
body.lead_score = additionalFields.leadScore as string;
}
if (additionalFields.tags) {
body.tags = additionalFields.tags as string[];
}
if (additionalFields.properties) {
body.properties = (additionalFields.properties as IDataObject).property as IDataObject[];
}
}
const endpoint = 'api/contacts';
console.log(body);
responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body);
}
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {
returnData.push(responseData as IDataObject);
}
}
}
return [this.helpers.returnJsonArray(returnData)];
}
}

View file

@ -0,0 +1,473 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const contactOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'contact',
],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Get a contact',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all contacts',
},
{
name: 'Create',
value: 'create',
description: 'Create a new contact',
},
],
default: 'get',
description: 'The operation to perform.',
},
] as INodeProperties[];
export const contactFields = [
/* -------------------------------------------------------------------------- */
/* contact:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Contact ID',
name: 'contactId',
type: 'string',
required: true,
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'get',
],
},
},
default: '',
description: 'Unique identifier for a particular contact',
},
/* -------------------------------------------------------------------------- */
/* contact:get all */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
},
},
default: false,
description: 'If all results should be returned or only up to a given limit.',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
}
},
/* -------------------------------------------------------------------------- */
/* ticket:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'JSON Parameters',
name: 'jsonParameters',
type: 'boolean',
default: false,
description: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
},
},
},
{
displayName: ' Additional Fields',
name: 'additionalFieldsJson',
type: 'json',
typeOptions: {
alwaysOpenEditWindow: true,
},
default: '',
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
jsonParameters: [
true,
],
},
},
description: `Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-contacts---companies-api" target="_blank">here</a>.`,
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'contact',
],
operation: [
'create',
],
jsonParameters: [
false,
],
},
},
options: [
{
displayName: 'Star Value',
name: 'starValue',
type: 'options',
default: '',
required: false,
description: 'Rating of contact (Max value 5). This is not applicable for companies.',
options: [
{
name: '0',
value: 0
},
{
name: '1',
value: 1
},
{
name: '2',
value: 2
},
{
name: '3',
value: 3
},
{
name: '4',
value: 4
},
{
name: '5',
value: 5
},
]
},
{
displayName: 'Lead Score',
name: 'leadScore',
type: 'number',
default: '',
description: 'Score of contact. This is not applicable for companies.',
required: false,
typeOptions: {
minValue: 0
}
},
{
displayName: 'Tags',
name: 'tags',
type: 'string',
typeOptions: {
multipleValues: true,
multipleValueButtonText: 'Add Tag',
},
default: [],
placeholder: 'Tag',
description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.',
},
{
displayName: 'Properties',
name: 'properties',
type: 'fixedCollection',
default: {},
description: 'Contact properties are represented by list of JSON objects, each JSON object should follow the prototype shown. Custom fields will have type as CUSTOM and others will have type as SYSTEM.',
required: true,
typeOptions: {
multipleValues: true,
},
options: [
{
displayName: 'Property',
name: 'property',
values: [
{
displayName: 'Type',
name: 'type',
type: 'options',
default: 'SYSTEM',
required: true,
description: 'Type of the field.',
options: [
{
name: 'SYSTEM',
value: 'SYSTEM',
},
{
name: 'CUSTOM',
value: 'CUSTOM'
}
]
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
required: true,
description: 'Name of the field.'
},
{
displayName: 'Sub Type',
name: 'subType',
default: '',
required: false,
type: 'options',
description: 'Name of the field.',
displayOptions: {
show: {
type: [
'SYSTEM'
],
name: [
'email'
]
}
},
options: [
{
name: 'Work',
value: 'work',
},
{
name: 'Personal',
value: 'personal',
}
]
},
{
displayName: 'Sub Type',
name: 'subType',
default: '',
required: false,
type: 'options',
description: 'Name of the field.',
displayOptions: {
show: {
type: [
'SYSTEM'
],
name: [
'phone'
]
}
},
options: [
{
name: 'Work',
value: 'work',
},
{
name: 'Home',
value: 'home',
},
{
name: 'Mobile',
value: 'mobile',
},
{
name: 'Main',
value: 'main',
},
{
name: 'Home Fax',
value: 'homeFax',
},
{
name: 'Work Fax',
value: 'workFax',
},
{
name: 'Other',
value: 'other',
},
]
},
{
displayName: 'Sub Type',
name: 'subType',
default: '',
required: false,
type: 'options',
description: 'Name of the field.',
displayOptions: {
show: {
type: [
'SYSTEM'
],
name: [
'address'
]
}
},
options: [
{
name: 'Home',
value: 'home',
},
{
name: 'Postal',
value: 'postal',
},
{
name: 'Office',
value: 'office',
},
]
},
{
displayName: 'Sub Type',
name: 'subType',
default: '',
required: false,
type: 'options',
description: 'Name of the field.',
displayOptions: {
show: {
type: [
'SYSTEM'
],
name: [
'website'
]
}
},
options: [
{
name: 'URL',
value: 'url',
},
{
name: 'SKYPE',
value: 'skype',
},
{
name: 'TWITTER',
value: 'twitter',
},
{
name: 'LINKEDIN',
value: 'linkedin',
},
{
name: 'FACEBOOK',
value: 'facebook',
},
{
name: 'XING',
value: 'xing',
},
{
name: 'FEED',
value: 'feed',
},
{
name: 'GOOGLE_PLUS',
value: 'googlePlus',
},
{
name: 'FLICKR',
value: 'flickr',
},
{
name: 'GITHUB',
value: 'github',
},
{
name: 'YOUTUBE',
value: 'youtube',
},
]
},
{
displayName: 'Sub Type',
name: 'subType',
default: '',
required: false,
type: 'string',
description: 'Name of the field.',
displayOptions: {
show: {
type: [
'CUSTOM'
],
}
}
},
{
displayName: 'Value',
name: 'value',
default: '',
required: false,
type: 'string',
description: 'Value of the property.'
},
]
}
]
},
],
},
] as INodeProperties[];

View file

@ -0,0 +1,18 @@
import {
IDataObject,
} from 'n8n-workflow';
export interface IProperty {
type: string;
name: string;
subtype?: string;
value?: string;
}
export interface IContact {
star_value?: string;
lead_score?: string;
tags?: string[];
properties?: IDataObject[];
}

View file

@ -0,0 +1,59 @@
import {
OptionsWithUri,
} from 'request';
import {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IExecuteSingleFunctions,
} from 'n8n-core';
import {
IDataObject,
} from 'n8n-workflow';
export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise<any> {
const node = this.getNodeParameter('credentials', 1);
const credentials = this.getCredentials('agileCrmApi');
const options: OptionsWithUri = {
method,
headers: {
'Accept': 'application/json',
},
body: body! || {},
auth: {
username: credentials!.email as string,
password: credentials!.apiKey as string
},
uri: uri || `https://n8nio.agilecrm.com/dev/${endpoint}`,
json: true
};
try {
return await this.helpers.request!(options);
} catch (error) {
if (error.response && error.response.body && error.response.body.errors) {
const errorMessages = error.response.body.errors.map((e: IDataObject) => e.message);
throw new Error(`AgileCRM error response [${error.statusCode}]: ${errorMessages.join(' | ')}`);
}
throw error;
}
}
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any
let result;
try {
result = JSON.parse(json!);
} catch (exception) {
result = undefined;
}
return result;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -27,6 +27,7 @@
"n8n": {
"credentials": [
"dist/credentials/ActiveCampaignApi.credentials.js",
"dist/credentials/AgileCrm.credentials.js",
"dist/credentials/AcuitySchedulingApi.credentials.js",
"dist/credentials/AirtableApi.credentials.js",
"dist/credentials/Amqp.credentials.js",
@ -113,6 +114,7 @@
"nodes": [
"dist/nodes/ActiveCampaign/ActiveCampaign.node.js",
"dist/nodes/ActiveCampaign/ActiveCampaignTrigger.node.js",
"dist/nodes/AgileCrm/AgileCrm.node.js",
"dist/nodes/Airtable/Airtable.node.js",
"dist/nodes/AcuityScheduling/AcuitySchedulingTrigger.node.js",
"dist/nodes/Amqp/Amqp.node.js",