Add list and list-entry resources to Affinity Node (#1387)

This commit is contained in:
Ricardo Espinoza 2021-01-30 12:47:27 -05:00 committed by GitHub
parent 05df13a887
commit db417da464
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 506 additions and 40 deletions

View file

@ -1,6 +1,7 @@
import {
IExecuteFunctions,
} from 'n8n-core';
import {
IDataObject,
ILoadOptionsFunctions,
@ -9,27 +10,40 @@ import {
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import {
affinityApiRequest,
affinityApiRequestAllItems,
} from './GenericFunctions';
import {
organizationFields,
organizationOperations,
} from './OrganizationDescription';
import {
personFields,
personOperations,
} from './PersonDescription';
import {
listFields,
listOperations,
} from './ListDescription';
import {
listEntryFields,
listEntryOperations,
} from './ListEntryDescription';
import {
IOrganization,
} from './OrganizationInterface';
import {
IPerson,
} from './PersonInterface';
import { snakeCase } from 'change-case';
export class Affinity implements INodeType {
description: INodeTypeDescription = {
displayName: 'Affinity',
@ -57,6 +71,14 @@ export class Affinity implements INodeType {
name: 'resource',
type: 'options',
options: [
{
name: 'List',
value: 'list',
},
{
name: 'List Entry',
value: 'listEntry',
},
{
name: 'Organization',
value: 'organization',
@ -69,6 +91,10 @@ export class Affinity implements INodeType {
default: 'organization',
description: 'Resource to consume.',
},
...listOperations,
...listFields,
...listEntryOperations,
...listEntryFields,
...organizationOperations,
...organizationFields,
...personOperations,
@ -101,7 +127,7 @@ export class Affinity implements INodeType {
for (const person of persons) {
let personName = `${person.first_name} ${person.last_name}`;
if (person.primary_email !== null) {
personName+= ` (${person.primary_email})`;
personName += ` (${person.primary_email})`;
}
const personId = person.id;
returnData.push({
@ -111,6 +137,19 @@ export class Affinity implements INodeType {
}
return returnData;
},
// Get all the available lists to display them to user so that he can
// select them easily
async getLists(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const lists = await affinityApiRequest.call(this, 'GET', `/lists`);
for (const list of lists) {
returnData.push({
name: list.name,
value: list.id,
});
}
return returnData;
},
},
};
@ -123,6 +162,59 @@ export class Affinity implements INodeType {
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 === 'list') {
//https://api-docs.affinity.co/#get-a-specific-list
if (operation === 'get') {
const listId = this.getNodeParameter('listId', i) as string;
responseData = await affinityApiRequest.call(this, 'GET', `/lists/${listId}`, {}, qs);
}
//https://api-docs.affinity.co/#get-all-lists
if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
responseData = await affinityApiRequest.call(this, 'GET', `/lists`, {}, qs);
if (returnAll === false) {
const limit = this.getNodeParameter('limit', i) as number;
responseData = responseData.splice(0, limit);
}
}
}
if (resource === 'listEntry') {
//https://api-docs.affinity.co/#create-a-new-list-entry
if (operation === 'create') {
const listId = this.getNodeParameter('listId', i) as string;
const entityId = this.getNodeParameter('entityId', i) as string;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const body: IDataObject = {
entity_id: parseInt(entityId, 10),
};
Object.assign(body, additionalFields);
responseData = await affinityApiRequest.call(this, 'POST', `/lists/${listId}/list-entries`, body);
}
//https://api-docs.affinity.co/#get-a-specific-list-entry
if (operation === 'get') {
const listId = this.getNodeParameter('listId', i) as string;
const listEntryId = this.getNodeParameter('listEntryId', i) as string;
responseData = await affinityApiRequest.call(this, 'GET', `/lists/${listId}/list-entries/${listEntryId}`, {}, qs);
}
//https://api-docs.affinity.co/#get-all-list-entries
if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const listId = this.getNodeParameter('listId', i) as string;
if (returnAll === true) {
responseData = await affinityApiRequestAllItems.call(this, 'list_entries', 'GET', `/lists/${listId}/list-entries`, {}, qs);
} else {
qs.page_size = this.getNodeParameter('limit', i) as number;
responseData = await affinityApiRequest.call(this, 'GET', `/lists/${listId}/list-entries`, {}, qs);
responseData = responseData.list_entries;
}
}
//https://api-docs.affinity.co/#delete-a-specific-list-entry
if (operation === 'delete') {
const listId = this.getNodeParameter('listId', i) as string;
const listEntryId = this.getNodeParameter('listEntryId', i) as string;
responseData = await affinityApiRequest.call(this, 'DELETE', `/lists/${listId}/list-entries/${listEntryId}`, {}, qs);
}
}
if (resource === 'person') {
//https://api-docs.affinity.co/#create-a-new-person
if (operation === 'create') {
@ -166,7 +258,7 @@ export class Affinity implements INodeType {
if (options.withInteractionDates) {
qs.with_interaction_dates = options.withInteractionDates as boolean;
}
responseData = await affinityApiRequest.call(this,'GET', `/persons/${personId}`, {}, qs);
responseData = await affinityApiRequest.call(this, 'GET', `/persons/${personId}`, {}, qs);
}
//https://api-docs.affinity.co/#search-for-persons
if (operation === 'getAll') {
@ -230,7 +322,7 @@ export class Affinity implements INodeType {
if (options.withInteractionDates) {
qs.with_interaction_dates = options.withInteractionDates as boolean;
}
responseData = await affinityApiRequest.call(this,'GET', `/organizations/${organizationId}`, {}, qs);
responseData = await affinityApiRequest.call(this, 'GET', `/organizations/${organizationId}`, {}, qs);
}
//https://api-docs.affinity.co/#search-for-organizations
if (operation === 'getAll') {

View file

@ -1,4 +1,6 @@
import { OptionsWithUri } from 'request';
import {
OptionsWithUri,
} from 'request';
import {
BINARY_ENCODING,
@ -6,7 +8,11 @@ import {
ILoadOptionsFunctions,
} from 'n8n-core';
import { IDataObject, IHookFunctions, IWebhookFunctions } from 'n8n-workflow';
import {
IDataObject,
IHookFunctions,
IWebhookFunctions,
} from 'n8n-workflow';
export async function affinityApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
@ -38,12 +44,13 @@ export async function affinityApiRequest(this: IExecuteFunctions | IWebhookFunct
delete options.qs;
}
options = Object.assign({}, options, option);
console.log(options);
try {
return await this.helpers.request!(options);
} catch (error) {
if (error.response) {
const errorMessage = error.response.body.message || error.response.body.description || error.message;
throw new Error(`Affinity error response: ${errorMessage}`);
throw new Error(`Affinity error response [${error.statusCode}]: ${errorMessage}`);
}
throw error;
}

View file

@ -0,0 +1,100 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const listOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'list',
],
},
},
options: [
{
name: 'Get',
value: 'get',
description: 'Get a list',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all lists',
},
],
default: 'get',
description: 'The operation to perform.',
},
] as INodeProperties[];
export const listFields = [
/* -------------------------------------------------------------------------- */
/* list:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'List ID',
name: 'listId',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'list',
],
operation: [
'get',
],
},
},
description: 'The unique id of the list object to be retrieved.',
},
/* -------------------------------------------------------------------------- */
/* list:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: [
'list',
],
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: [
'list',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
typeOptions: {
minValue: 1,
maxValue: 10,
},
default: 5,
description: 'How many results to return.',
},
] as INodeProperties[];

View file

@ -0,0 +1,263 @@
import {
INodeProperties,
} from 'n8n-workflow';
export const listEntryOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'listEntry',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a list entry',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a list entry',
},
{
name: 'Get',
value: 'get',
description: 'Get a list entry',
},
{
name: 'Get All',
value: 'getAll',
description: 'Get all list entries',
},
],
default: 'create',
description: 'The operation to perform.',
},
] as INodeProperties[];
export const listEntryFields = [
/* -------------------------------------------------------------------------- */
/* listEntry:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'List ID',
name: 'listId',
type: 'options',
required: true,
typeOptions: {
loadOptionsMethod: 'getLists',
},
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'create',
],
},
},
description: 'The unique id of the list whose list entries are to be retrieved.',
},
{
displayName: 'Entity ID',
name: 'entityId',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'create',
],
},
},
description: 'The unique id of the entity (person, organization, or opportunity) to add to this list.',
},
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'create',
],
},
},
options: [
{
displayName: 'Creator ID',
name: 'creator_id',
type: 'string',
default: '',
description: `The id of a Person resource who should be recorded as adding the entry to the list. <br/>
Must be a person who can access Affinity. If not provided the creator defaults to the owner of the API key.`,
},
],
},
/* -------------------------------------------------------------------------- */
/* listEntry:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'List ID',
name: 'listId',
type: 'options',
required: true,
typeOptions: {
loadOptionsMethod: 'getLists',
},
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'get',
],
},
},
description: 'The unique id of the list that contains the specified list_entry_id.',
},
{
displayName: 'List Entry ID',
name: 'listEntryId',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'get',
],
},
},
description: 'The unique id of the list entry object to be retrieved.',
},
/* -------------------------------------------------------------------------- */
/* listEntry:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'List ID',
name: 'listId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getLists',
},
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'getAll',
],
},
},
default: '',
description: 'The unique id of the list whose list entries are to be retrieved.',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
resource: [
'listEntry',
],
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: [
'listEntry',
],
operation: [
'getAll',
],
returnAll: [
false,
],
},
},
typeOptions: {
minValue: 1,
maxValue: 10,
},
default: 5,
description: 'How many results to return.',
},
/* -------------------------------------------------------------------------- */
/* listEntry:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'List ID',
name: 'listId',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getLists',
},
required: true,
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'delete',
],
},
},
description: 'The unique id of the list that contains the specified list_entry_id.',
},
{
displayName: 'List Entry ID',
name: 'listEntryId',
type: 'string',
required: true,
default: '',
displayOptions: {
show: {
resource: [
'listEntry',
],
operation: [
'delete',
],
},
},
description: 'The unique id of the list entry object to be deleted.',
},
] as INodeProperties[];

View file

@ -1,4 +1,6 @@
import { INodeProperties } from 'n8n-workflow';
import {
INodeProperties,
} from 'n8n-workflow';
export const organizationOperations = [
{
@ -46,9 +48,9 @@ export const organizationOperations = [
export const organizationFields = [
/* -------------------------------------------------------------------------- */
/* organization:create */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* organization:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Name',
name: 'name',
@ -114,9 +116,9 @@ export const organizationFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* organization:update */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* organization:update */
/* -------------------------------------------------------------------------- */
{
displayName: 'Organization ID',
name: 'organizationId',
@ -178,9 +180,9 @@ export const organizationFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* organization:get */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* organization:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Organization ID',
name: 'organizationId',
@ -225,9 +227,9 @@ export const organizationFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* organization:getAll */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* organization:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
@ -302,9 +304,9 @@ export const organizationFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* organization:delete */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* organization:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Organization ID',
name: 'organizationId',

View file

@ -1,4 +1,6 @@
import { INodeProperties } from 'n8n-workflow';
import {
INodeProperties,
} from 'n8n-workflow';
export const personOperations = [
{
@ -46,9 +48,9 @@ export const personOperations = [
export const personFields = [
/* -------------------------------------------------------------------------- */
/* person:create */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* person:create */
/* -------------------------------------------------------------------------- */
{
displayName: 'Fist Name',
name: 'firstName',
@ -136,9 +138,9 @@ export const personFields = [
placeholder: 'info@example.com',
default: [],
},
/* -------------------------------------------------------------------------- */
/* person:update */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* person:update */
/* -------------------------------------------------------------------------- */
{
displayName: 'Person ID',
name: 'personId',
@ -222,9 +224,9 @@ export const personFields = [
placeholder: 'info@example.com',
default: [],
},
/* -------------------------------------------------------------------------- */
/* person:get */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* person:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Person ID',
name: 'personId',
@ -269,9 +271,9 @@ export const personFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* person:getAll */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* person:getAll */
/* -------------------------------------------------------------------------- */
{
displayName: 'Return All',
name: 'returnAll',
@ -346,9 +348,9 @@ export const personFields = [
},
],
},
/* -------------------------------------------------------------------------- */
/* person:delete */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* person:delete */
/* -------------------------------------------------------------------------- */
{
displayName: 'Person ID',
name: 'personId',