refactor: Format nodes-base package (A-F) (#3800)

* 🔨 prettier formated nodes - A

* 🔨 prettier formated nodes - B

*  prettier formated nodes - C

*  prettier formated nodes - D

*  prettier formated nodes - E-F

* 🎨 Adjust nodes-base formatting command (#3805)

* Format additional files in nodes A-F (#3811)

*  fixes

* 🎨 Add Mindee to ignored dirs

Co-authored-by: Iván Ovejero <ivov.src@gmail.com>
This commit is contained in:
Michael Kret 2022-08-01 23:47:55 +03:00 committed by GitHub
parent 2c17e6f3ca
commit 0ecbb4a19d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
411 changed files with 12906 additions and 20148 deletions

View file

@ -1,3 +1,4 @@
dist
packages/editor-ui packages/editor-ui
packages/design-system packages/design-system
*package.json *package.json
@ -6,81 +7,6 @@ packages/design-system
!packages/nodes-base/test !packages/nodes-base/test
!packages/nodes-base/nodes !packages/nodes-base/nodes
packages/nodes-base/nodes/ActionNetwork
packages/nodes-base/nodes/ActiveCampaign
packages/nodes-base/nodes/AcuityScheduling
packages/nodes-base/nodes/Affinity
packages/nodes-base/nodes/AgileCrm
packages/nodes-base/nodes/Airtable
packages/nodes-base/nodes/Amqp
packages/nodes-base/nodes/ApiTemplateIo
packages/nodes-base/nodes/Asana
packages/nodes-base/nodes/Automizy
packages/nodes-base/nodes/Autopilot
packages/nodes-base/nodes/Aws
packages/nodes-base/nodes/BambooHr
packages/nodes-base/nodes/Bannerbear
packages/nodes-base/nodes/Baserow
packages/nodes-base/nodes/Beeminder
packages/nodes-base/nodes/Bitbucket
packages/nodes-base/nodes/Bitly
packages/nodes-base/nodes/Bitwarden
packages/nodes-base/nodes/Box
packages/nodes-base/nodes/Brandfetch
packages/nodes-base/nodes/Bubble
packages/nodes-base/nodes/Cal
packages/nodes-base/nodes/Calendly
packages/nodes-base/nodes/Chargebee
packages/nodes-base/nodes/CircleCi
packages/nodes-base/nodes/Cisco
packages/nodes-base/nodes/Clearbit
packages/nodes-base/nodes/ClickUp
packages/nodes-base/nodes/Clockify
packages/nodes-base/nodes/Cockpit
packages/nodes-base/nodes/Coda
packages/nodes-base/nodes/CoinGecko
packages/nodes-base/nodes/Compression
packages/nodes-base/nodes/Contentful
packages/nodes-base/nodes/ConvertKit
packages/nodes-base/nodes/Copper
packages/nodes-base/nodes/Cortex
packages/nodes-base/nodes/CrateDb
packages/nodes-base/nodes/Cron
packages/nodes-base/nodes/Crypto
packages/nodes-base/nodes/CustomerIo
packages/nodes-base/nodes/DateTime
packages/nodes-base/nodes/DeepL
packages/nodes-base/nodes/Demio
packages/nodes-base/nodes/Dhl
packages/nodes-base/nodes/Discord
packages/nodes-base/nodes/Discourse
packages/nodes-base/nodes/Disqus
packages/nodes-base/nodes/Drift
packages/nodes-base/nodes/Dropbox
packages/nodes-base/nodes/Dropcontact
packages/nodes-base/nodes/EditImage
packages/nodes-base/nodes/Egoi
packages/nodes-base/nodes/Elastic
packages/nodes-base/nodes/EmailReadImap
packages/nodes-base/nodes/EmailSend
packages/nodes-base/nodes/Emelia
packages/nodes-base/nodes/ERPNext
packages/nodes-base/nodes/ErrorTrigger
packages/nodes-base/nodes/Eventbrite
packages/nodes-base/nodes/ExecuteCommand
packages/nodes-base/nodes/ExecuteWorkflow
packages/nodes-base/nodes/Facebook
packages/nodes-base/nodes/Figma
packages/nodes-base/nodes/FileMaker
packages/nodes-base/nodes/Flow
packages/nodes-base/nodes/FormIo
packages/nodes-base/nodes/Formstack
packages/nodes-base/nodes/Freshdesk
packages/nodes-base/nodes/Freshservice
packages/nodes-base/nodes/FreshworksCrm
packages/nodes-base/nodes/Ftp
packages/nodes-base/nodes/Function
packages/nodes-base/nodes/FunctionItem
packages/nodes-base/nodes/GetResponse packages/nodes-base/nodes/GetResponse
packages/nodes-base/nodes/Ghost packages/nodes-base/nodes/Ghost
packages/nodes-base/nodes/Git packages/nodes-base/nodes/Git
@ -139,6 +65,7 @@ packages/nodes-base/nodes/Medium
packages/nodes-base/nodes/Merge packages/nodes-base/nodes/Merge
packages/nodes-base/nodes/MessageBird packages/nodes-base/nodes/MessageBird
packages/nodes-base/nodes/Microsoft packages/nodes-base/nodes/Microsoft
packages/nodes-base/nodes/Mindee
packages/nodes-base/nodes/Misp packages/nodes-base/nodes/Misp
packages/nodes-base/nodes/Mocean packages/nodes-base/nodes/Mocean
packages/nodes-base/nodes/MondayCom packages/nodes-base/nodes/MondayCom

View file

@ -83,7 +83,8 @@ export class ERPNextApi implements ICredentialType {
}; };
test: ICredentialTestRequest = { test: ICredentialTestRequest = {
request: { request: {
baseURL: '={{$credentials.environment === "cloudHosted" ? "https://" + $credentials.subdomain + ".erpnext.com" : $credentials.domain}}', baseURL:
'={{$credentials.environment === "cloudHosted" ? "https://" + $credentials.subdomain + ".erpnext.com" : $credentials.domain}}',
url: '/api/resource/Doctype', url: '/api/resource/Doctype',
skipSslCertificateValidation: '={{ $credentials.allowUnauthorizedCerts }}', skipSslCertificateValidation: '={{ $credentials.allowUnauthorizedCerts }}',
}, },

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -138,7 +136,6 @@ export class ActionNetwork implements INodeType {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
try { try {
if (resource === 'attendance') { if (resource === 'attendance') {
// ********************************************************************** // **********************************************************************
// attendance // attendance
// ********************************************************************** // **********************************************************************
@ -146,7 +143,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/attendances // https://actionnetwork.org/docs/v2/attendances
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// attendance: create // attendance: create
// ---------------------------------------- // ----------------------------------------
@ -158,9 +154,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/events/${eventId}/attendances`; const endpoint = `/events/${eventId}/attendances`;
response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body); response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// attendance: get // attendance: get
// ---------------------------------------- // ----------------------------------------
@ -170,9 +164,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/events/${eventId}/attendances/${attendanceId}`; const endpoint = `/events/${eventId}/attendances/${attendanceId}`;
response = await actionNetworkApiRequest.call(this, 'GET', endpoint); response = await actionNetworkApiRequest.call(this, 'GET', endpoint);
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// attendance: getAll // attendance: getAll
// ---------------------------------------- // ----------------------------------------
@ -181,11 +173,8 @@ export class ActionNetwork implements INodeType {
const endpoint = `/events/${eventId}/attendances`; const endpoint = `/events/${eventId}/attendances`;
response = await handleListing.call(this, 'GET', endpoint); response = await handleListing.call(this, 'GET', endpoint);
} }
} else if (resource === 'event') { } else if (resource === 'event') {
// ********************************************************************** // **********************************************************************
// event // event
// ********************************************************************** // **********************************************************************
@ -193,7 +182,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/events // https://actionnetwork.org/docs/v2/events
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// event: create // event: create
// ---------------------------------------- // ----------------------------------------
@ -210,9 +198,7 @@ export class ActionNetwork implements INodeType {
} }
response = await actionNetworkApiRequest.call(this, 'POST', '/events', body); response = await actionNetworkApiRequest.call(this, 'POST', '/events', body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// event: get // event: get
// ---------------------------------------- // ----------------------------------------
@ -220,19 +206,14 @@ export class ActionNetwork implements INodeType {
const eventId = this.getNodeParameter('eventId', i); const eventId = this.getNodeParameter('eventId', i);
response = await actionNetworkApiRequest.call(this, 'GET', `/events/${eventId}`); response = await actionNetworkApiRequest.call(this, 'GET', `/events/${eventId}`);
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// event: getAll // event: getAll
// ---------------------------------------- // ----------------------------------------
response = await handleListing.call(this, 'GET', '/events'); response = await handleListing.call(this, 'GET', '/events');
} }
} else if (resource === 'person') { } else if (resource === 'person') {
// ********************************************************************** // **********************************************************************
// person // person
// ********************************************************************** // **********************************************************************
@ -240,7 +221,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/people // https://actionnetwork.org/docs/v2/people
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// person: create // person: create
// ---------------------------------------- // ----------------------------------------
@ -260,27 +240,25 @@ export class ActionNetwork implements INodeType {
} }
response = await actionNetworkApiRequest.call(this, 'POST', '/people', body); response = await actionNetworkApiRequest.call(this, 'POST', '/people', body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// person: get // person: get
// ---------------------------------------- // ----------------------------------------
const personId = this.getNodeParameter('personId', i); const personId = this.getNodeParameter('personId', i);
response = await actionNetworkApiRequest.call(this, 'GET', `/people/${personId}`) as PersonResponse; response = (await actionNetworkApiRequest.call(
this,
'GET',
`/people/${personId}`,
)) as PersonResponse;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// person: getAll // person: getAll
// ---------------------------------------- // ----------------------------------------
response = await handleListing.call(this, 'GET', '/people') as PersonResponse[]; response = (await handleListing.call(this, 'GET', '/people')) as PersonResponse[];
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------------- // ----------------------------------------
// person: update // person: update
// ---------------------------------------- // ----------------------------------------
@ -300,11 +278,8 @@ export class ActionNetwork implements INodeType {
} }
response = await actionNetworkApiRequest.call(this, 'PUT', `/people/${personId}`, body); response = await actionNetworkApiRequest.call(this, 'PUT', `/people/${personId}`, body);
} }
} else if (resource === 'petition') { } else if (resource === 'petition') {
// ********************************************************************** // **********************************************************************
// petition // petition
// ********************************************************************** // **********************************************************************
@ -312,7 +287,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/petitions // https://actionnetwork.org/docs/v2/petitions
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// petition: create // petition: create
// ---------------------------------------- // ----------------------------------------
@ -329,9 +303,7 @@ export class ActionNetwork implements INodeType {
} }
response = await actionNetworkApiRequest.call(this, 'POST', '/petitions', body); response = await actionNetworkApiRequest.call(this, 'POST', '/petitions', body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// petition: get // petition: get
// ---------------------------------------- // ----------------------------------------
@ -340,17 +312,13 @@ export class ActionNetwork implements INodeType {
const endpoint = `/petitions/${petitionId}`; const endpoint = `/petitions/${petitionId}`;
response = await actionNetworkApiRequest.call(this, 'GET', endpoint); response = await actionNetworkApiRequest.call(this, 'GET', endpoint);
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// petition: getAll // petition: getAll
// ---------------------------------------- // ----------------------------------------
response = await handleListing.call(this, 'GET', '/petitions'); response = await handleListing.call(this, 'GET', '/petitions');
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------------- // ----------------------------------------
// petition: update // petition: update
// ---------------------------------------- // ----------------------------------------
@ -369,12 +337,14 @@ export class ActionNetwork implements INodeType {
); );
} }
response = await actionNetworkApiRequest.call(this, 'PUT', `/petitions/${petitionId}`, body); response = await actionNetworkApiRequest.call(
this,
'PUT',
`/petitions/${petitionId}`,
body,
);
} }
} else if (resource === 'signature') { } else if (resource === 'signature') {
// ********************************************************************** // **********************************************************************
// signature // signature
// ********************************************************************** // **********************************************************************
@ -382,7 +352,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/signatures // https://actionnetwork.org/docs/v2/signatures
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// signature: create // signature: create
// ---------------------------------------- // ----------------------------------------
@ -400,9 +369,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/petitions/${petitionId}/signatures`; const endpoint = `/petitions/${petitionId}/signatures`;
response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body); response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// signature: get // signature: get
// ---------------------------------------- // ----------------------------------------
@ -412,9 +379,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/petitions/${petitionId}/signatures/${signatureId}`; const endpoint = `/petitions/${petitionId}/signatures/${signatureId}`;
response = await actionNetworkApiRequest.call(this, 'GET', endpoint); response = await actionNetworkApiRequest.call(this, 'GET', endpoint);
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// signature: getAll // signature: getAll
// ---------------------------------------- // ----------------------------------------
@ -423,9 +388,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/petitions/${petitionId}/signatures`; const endpoint = `/petitions/${petitionId}/signatures`;
response = await handleListing.call(this, 'GET', endpoint); response = await handleListing.call(this, 'GET', endpoint);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------------- // ----------------------------------------
// signature: update // signature: update
// ---------------------------------------- // ----------------------------------------
@ -447,11 +410,8 @@ export class ActionNetwork implements INodeType {
const endpoint = `/petitions/${petitionId}/signatures/${signatureId}`; const endpoint = `/petitions/${petitionId}/signatures/${signatureId}`;
response = await actionNetworkApiRequest.call(this, 'PUT', endpoint, body); response = await actionNetworkApiRequest.call(this, 'PUT', endpoint, body);
} }
} else if (resource === 'tag') { } else if (resource === 'tag') {
// ********************************************************************** // **********************************************************************
// tag // tag
// ********************************************************************** // **********************************************************************
@ -459,7 +419,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/tags // https://actionnetwork.org/docs/v2/tags
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------------- // ----------------------------------------
// tag: create // tag: create
// ---------------------------------------- // ----------------------------------------
@ -469,9 +428,7 @@ export class ActionNetwork implements INodeType {
} as IDataObject; } as IDataObject;
response = await actionNetworkApiRequest.call(this, 'POST', '/tags', body); response = await actionNetworkApiRequest.call(this, 'POST', '/tags', body);
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------------- // ----------------------------------------
// tag: get // tag: get
// ---------------------------------------- // ----------------------------------------
@ -479,19 +436,14 @@ export class ActionNetwork implements INodeType {
const tagId = this.getNodeParameter('tagId', i); const tagId = this.getNodeParameter('tagId', i);
response = await actionNetworkApiRequest.call(this, 'GET', `/tags/${tagId}`); response = await actionNetworkApiRequest.call(this, 'GET', `/tags/${tagId}`);
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------------- // ----------------------------------------
// tag: getAll // tag: getAll
// ---------------------------------------- // ----------------------------------------
response = await handleListing.call(this, 'GET', '/tags'); response = await handleListing.call(this, 'GET', '/tags');
} }
} else if (resource === 'personTag') { } else if (resource === 'personTag') {
// ********************************************************************** // **********************************************************************
// personTag // personTag
// ********************************************************************** // **********************************************************************
@ -499,7 +451,6 @@ export class ActionNetwork implements INodeType {
// https://actionnetwork.org/docs/v2/taggings // https://actionnetwork.org/docs/v2/taggings
if (operation === 'add') { if (operation === 'add') {
// ---------------------------------------- // ----------------------------------------
// personTag: add // personTag: add
// ---------------------------------------- // ----------------------------------------
@ -511,9 +462,7 @@ export class ActionNetwork implements INodeType {
const endpoint = `/tags/${tagId}/taggings`; const endpoint = `/tags/${tagId}/taggings`;
response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body); response = await actionNetworkApiRequest.call(this, 'POST', endpoint, body);
} else if (operation === 'remove') { } else if (operation === 'remove') {
// ---------------------------------------- // ----------------------------------------
// personTag: remove // personTag: remove
// ---------------------------------------- // ----------------------------------------
@ -523,23 +472,19 @@ export class ActionNetwork implements INodeType {
const endpoint = `/tags/${tagId}/taggings/${taggingId}`; const endpoint = `/tags/${tagId}/taggings/${taggingId}`;
response = await actionNetworkApiRequest.call(this, 'DELETE', endpoint); response = await actionNetworkApiRequest.call(this, 'DELETE', endpoint);
} }
} }
const simplify = this.getNodeParameter('simple', i, false) as boolean; const simplify = this.getNodeParameter('simple', i, false) as boolean;
if (simplify) { if (simplify) {
response = operation === 'getAll' response =
? response.map((i: Response) => simplifyResponse(i, resource)) operation === 'getAll'
: simplifyResponse(response, resource); ? response.map((i: Response) => simplifyResponse(i, resource))
: simplifyResponse(response, resource);
} }
Array.isArray(response) Array.isArray(response) ? returnData.push(...response) : returnData.push(response);
? returnData.push(...response)
: returnData.push(response);
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ error: error.message }); returnData.push({ error: error.message });

View file

@ -1,21 +1,10 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { IDataObject, ILoadOptionsFunctions, NodeApiError } from 'n8n-workflow';
IDataObject,
ILoadOptionsFunctions,
NodeApiError,
} from 'n8n-workflow';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { flow, omit } from 'lodash';
flow,
omit,
} from 'lodash';
import { import {
AllFieldsUi, AllFieldsUi,
@ -71,7 +60,7 @@ export async function handleListing(
qs.perPage = 25; // max qs.perPage = 25; // max
qs.page = 1; qs.page = 1;
const returnAll = options?.returnAll ?? this.getNodeParameter('returnAll', 0, false) as boolean; const returnAll = options?.returnAll ?? (this.getNodeParameter('returnAll', 0, false) as boolean);
const limit = this.getNodeParameter('limit', 0, 0) as number; const limit = this.getNodeParameter('limit', 0, 0) as number;
const itemsKey = toItemsKey(endpoint); const itemsKey = toItemsKey(endpoint);
@ -102,7 +91,6 @@ export async function handleListing(
* Convert an endpoint to the key needed to access data in the response. * Convert an endpoint to the key needed to access data in the response.
*/ */
const toItemsKey = (endpoint: string) => { const toItemsKey = (endpoint: string) => {
// handle two-resource endpoint // handle two-resource endpoint
if ( if (
endpoint.includes('/signatures') || endpoint.includes('/signatures') ||
@ -131,7 +119,6 @@ export const makeOsdiLink = (personId: string) => {
export const isPrimary = (field: FieldWithPrimaryField) => field.primary; export const isPrimary = (field: FieldWithPrimaryField) => field.primary;
// ---------------------------------------- // ----------------------------------------
// field adjusters // field adjusters
// ---------------------------------------- // ----------------------------------------
@ -150,9 +137,7 @@ function adjustPhoneNumbers(allFields: AllFieldsUi) {
return { return {
...omit(allFields, ['phone_numbers']), ...omit(allFields, ['phone_numbers']),
phone_numbers: [ phone_numbers: [allFields.phone_numbers.phone_numbers_fields],
allFields.phone_numbers.phone_numbers_fields,
],
}; };
} }
@ -209,7 +194,7 @@ function adjustLocation(allFields: AllFieldsUi) {
function adjustTargets(allFields: AllFieldsUi) { function adjustTargets(allFields: AllFieldsUi) {
if (!allFields.target) return allFields; if (!allFields.target) return allFields;
const adjusted = allFields.target.split(',').map(value => ({ name: value })); const adjusted = allFields.target.split(',').map((value) => ({ name: value }));
return { return {
...omit(allFields, ['target']), ...omit(allFields, ['target']),
@ -217,7 +202,6 @@ function adjustTargets(allFields: AllFieldsUi) {
}; };
} }
// ---------------------------------------- // ----------------------------------------
// payload adjusters // payload adjusters
// ---------------------------------------- // ----------------------------------------
@ -232,7 +216,6 @@ export const adjustPetitionPayload = adjustTargets;
export const adjustEventPayload = adjustLocation; export const adjustEventPayload = adjustLocation;
// ---------------------------------------- // ----------------------------------------
// resource loaders // resource loaders
// ---------------------------------------- // ----------------------------------------
@ -242,9 +225,10 @@ async function loadResource(this: ILoadOptionsFunctions, resource: string) {
} }
export const resourceLoaders = { export const resourceLoaders = {
async getTags(this: ILoadOptionsFunctions) { async getTags(this: ILoadOptionsFunctions) {
const tags = await loadResource.call(this, 'tags') as Array<{ name: string } & LinksFieldContainer>; const tags = (await loadResource.call(this, 'tags')) as Array<
{ name: string } & LinksFieldContainer
>;
return tags.map((tag) => ({ name: tag.name, value: extractId(tag) })); return tags.map((tag) => ({ name: tag.name, value: extractId(tag) }));
}, },
@ -254,9 +238,14 @@ export const resourceLoaders = {
const endpoint = `/tags/${tagId}/taggings`; const endpoint = `/tags/${tagId}/taggings`;
// two-resource endpoint, so direct call // two-resource endpoint, so direct call
const taggings = await handleListing.call( const taggings = (await handleListing.call(
this, 'GET', endpoint, {}, {}, { returnAll: true }, this,
) as LinksFieldContainer[]; 'GET',
endpoint,
{},
{},
{ returnAll: true },
)) as LinksFieldContainer[];
return taggings.map((tagging) => { return taggings.map((tagging) => {
const taggingId = extractId(tagging); const taggingId = extractId(tagging);
@ -269,7 +258,6 @@ export const resourceLoaders = {
}, },
}; };
// ---------------------------------------- // ----------------------------------------
// response simplifiers // response simplifiers
// ---------------------------------------- // ----------------------------------------
@ -281,12 +269,7 @@ export const simplifyResponse = (response: Response, resource: Resource) => {
return simplifyPetitionResponse(response as PetitionResponse); return simplifyPetitionResponse(response as PetitionResponse);
} }
const fieldsToSimplify = [ const fieldsToSimplify = ['identifiers', '_links', 'action_network:sponsor', 'reminders'];
'identifiers',
'_links',
'action_network:sponsor',
'reminders',
];
return { return {
id: extractId(response), id: extractId(response),
@ -294,14 +277,8 @@ export const simplifyResponse = (response: Response, resource: Resource) => {
}; };
}; };
const simplifyPetitionResponse = (response: PetitionResponse) => { const simplifyPetitionResponse = (response: PetitionResponse) => {
const fieldsToSimplify = [ const fieldsToSimplify = ['identifiers', '_links', 'action_network:hidden', '_embedded'];
'identifiers',
'_links',
'action_network:hidden',
'_embedded',
];
return { return {
id: extractId(response), id: extractId(response),
@ -331,7 +308,7 @@ const simplifyPersonResponse = (response: PersonResponse) => {
...{ phone_number: phoneNumber[0].number || '' }, ...{ phone_number: phoneNumber[0].number || '' },
...{ ...{
postal_address: { postal_address: {
...postalAddress && omit(postalAddress[0], 'address_lines'), ...(postalAddress && omit(postalAddress[0], 'address_lines')),
address_lines: postalAddress[0].address_lines ?? '', address_lines: postalAddress[0].address_lines ?? '',
}, },
}, },

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { makeSimpleField } from './SharedFields';
makeSimpleField,
} from './SharedFields';
export const attendanceOperations: INodeProperties[] = [ export const attendanceOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const attendanceOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance',
],
}, },
}, },
options: [ options: [
@ -53,12 +47,8 @@ export const attendanceFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -71,12 +61,8 @@ export const attendanceFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -94,12 +80,8 @@ export const attendanceFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -112,12 +94,8 @@ export const attendanceFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -135,12 +113,8 @@ export const attendanceFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -152,12 +126,8 @@ export const attendanceFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -172,15 +142,9 @@ export const attendanceFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['attendance'],
'attendance', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },

View file

@ -1,11 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { eventAdditionalFieldsOptions, makeSimpleField } from './SharedFields';
eventAdditionalFieldsOptions,
makeSimpleField,
} from './SharedFields';
export const eventOperations: INodeProperties[] = [ export const eventOperations: INodeProperties[] = [
{ {
@ -15,9 +10,7 @@ export const eventOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event',
],
}, },
}, },
options: [ options: [
@ -54,12 +47,8 @@ export const eventFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -72,12 +61,8 @@ export const eventFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -90,12 +75,8 @@ export const eventFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: eventAdditionalFieldsOptions, options: eventAdditionalFieldsOptions,
@ -113,12 +94,8 @@ export const eventFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -135,12 +112,8 @@ export const eventFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -155,15 +128,9 @@ export const eventFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['event'],
'event', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },

View file

@ -1,11 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { makeSimpleField, personAdditionalFieldsOptions } from './SharedFields';
makeSimpleField,
personAdditionalFieldsOptions,
} from './SharedFields';
export const personOperations: INodeProperties[] = [ export const personOperations: INodeProperties[] = [
{ {
@ -15,9 +10,7 @@ export const personOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person',
],
}, },
}, },
options: [ options: [
@ -60,12 +53,8 @@ export const personFields: INodeProperties[] = [
description: 'Persons email addresses', description: 'Persons email addresses',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: [ options: [
@ -78,14 +67,14 @@ export const personFields: INodeProperties[] = [
name: 'address', name: 'address',
type: 'string', type: 'string',
default: '', default: '',
description: 'Person\'s email address', description: "Person's email address",
}, },
{ {
displayName: 'Primary', displayName: 'Primary',
name: 'primary', name: 'primary',
type: 'hidden', type: 'hidden',
default: true, default: true,
description: 'Whether this is the person\'s primary email address', description: "Whether this is the person's primary email address",
}, },
{ {
displayName: 'Status', displayName: 'Status',
@ -132,12 +121,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: personAdditionalFieldsOptions, options: personAdditionalFieldsOptions,
@ -155,12 +140,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -177,12 +158,8 @@ export const personFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -198,15 +175,9 @@ export const personFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },
@ -224,12 +195,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -242,12 +209,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
options: personAdditionalFieldsOptions, options: personAdditionalFieldsOptions,

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const personTagOperations: INodeProperties[] = [ export const personTagOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const personTagOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['personTag'],
'personTag',
],
}, },
}, },
options: [ options: [
@ -38,7 +34,8 @@ export const personTagFields: INodeProperties[] = [
{ {
displayName: 'Tag Name or ID', displayName: 'Tag Name or ID',
name: 'tagId', name: 'tagId',
description: 'ID of the tag to add. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the tag to add. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
type: 'options', type: 'options',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
@ -47,12 +44,8 @@ export const personTagFields: INodeProperties[] = [
default: [], default: [],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['personTag'],
'personTag', operation: ['add'],
],
operation: [
'add',
],
}, },
}, },
}, },
@ -65,12 +58,8 @@ export const personTagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['personTag'],
'personTag', operation: ['add'],
],
operation: [
'add',
],
}, },
}, },
}, },
@ -81,7 +70,8 @@ export const personTagFields: INodeProperties[] = [
{ {
displayName: 'Tag Name or ID', displayName: 'Tag Name or ID',
name: 'tagId', name: 'tagId',
description: 'ID of the tag whose tagging to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the tag whose tagging to delete. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
type: 'options', type: 'options',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
@ -90,36 +80,27 @@ export const personTagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['personTag'],
'personTag', operation: ['remove'],
],
operation: [
'remove',
],
}, },
}, },
}, },
{ {
displayName: 'Tagging Name or ID', displayName: 'Tagging Name or ID',
name: 'taggingId', name: 'taggingId',
description: 'ID of the tagging to remove. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the tagging to remove. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
type: 'options', type: 'options',
typeOptions: { typeOptions: {
loadOptionsDependsOn: [ loadOptionsDependsOn: ['tagId'],
'tagId',
],
loadOptionsMethod: 'getTaggings', loadOptionsMethod: 'getTaggings',
}, },
required: true, required: true,
default: [], default: [],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['personTag'],
'personTag', operation: ['remove'],
],
operation: [
'remove',
],
}, },
}, },
}, },

View file

@ -1,11 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { makeSimpleField, petitionAdditionalFieldsOptions } from './SharedFields';
makeSimpleField,
petitionAdditionalFieldsOptions,
} from './SharedFields';
export const petitionOperations: INodeProperties[] = [ export const petitionOperations: INodeProperties[] = [
{ {
@ -15,9 +10,7 @@ export const petitionOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition',
],
}, },
}, },
options: [ options: [
@ -59,12 +52,8 @@ export const petitionFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -77,12 +66,8 @@ export const petitionFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -95,12 +80,8 @@ export const petitionFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: petitionAdditionalFieldsOptions, options: petitionAdditionalFieldsOptions,
@ -118,12 +99,8 @@ export const petitionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -140,12 +117,8 @@ export const petitionFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -160,15 +133,9 @@ export const petitionFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },
@ -186,12 +153,8 @@ export const petitionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -204,12 +167,8 @@ export const petitionFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['petition'],
'petition', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
options: petitionAdditionalFieldsOptions, options: petitionAdditionalFieldsOptions,

View file

@ -1,11 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { Operation, Resource } from '../types';
Operation,
Resource,
} from '../types';
export const languageOptions: INodeProperties['options'] = [ export const languageOptions: INodeProperties['options'] = [
{ {
@ -80,21 +75,22 @@ const postalAddressesFields: INodeProperties[] = [
name: 'primary', name: 'primary',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether this is the person\'s primary address', description: "Whether this is the person's primary address",
}, },
{ {
displayName: 'Address Line', displayName: 'Address Line',
name: 'address_lines', name: 'address_lines',
type: 'string', // The Action Network API expects a string array but ignores any string beyond the first, so this input field is simplified to string. type: 'string', // The Action Network API expects a string array but ignores any string beyond the first, so this input field is simplified to string.
default: '', default: '',
description: 'Line for a person\'s address', description: "Line for a person's address",
}, },
{ {
displayName: 'Locality', displayName: 'Locality',
name: 'locality', name: 'locality',
type: 'string', type: 'string',
default: '', default: '',
description: 'City or other local administrative area. If blank, this will be filled in based on Action Network\'s geocoding.', description:
"City or other local administrative area. If blank, this will be filled in based on Action Network's geocoding.",
}, },
{ {
displayName: 'Region', displayName: 'Region',
@ -188,7 +184,7 @@ export const eventAdditionalFieldsOptions: INodeProperties['options'] = [
name: 'instructions', name: 'instructions',
type: 'string', type: 'string',
default: '', default: '',
description: 'Event\'s instructions for activists, visible after they RSVP. HTML supported.', description: "Event's instructions for activists, visible after they RSVP. HTML supported.",
}, },
{ {
displayName: 'Location', displayName: 'Location',
@ -265,14 +261,14 @@ export const personAdditionalFieldsOptions: INodeProperties['options'] = [
name: 'number', name: 'number',
type: 'string', type: 'string',
default: '', default: '',
description: 'Person\'s mobile number, in international format without the plus sign', description: "Person's mobile number, in international format without the plus sign",
}, },
{ {
displayName: 'Primary', displayName: 'Primary',
name: 'primary', name: 'primary',
type: 'hidden', type: 'hidden',
default: true, default: true,
description: 'Whether this is the person\'s primary phone number', description: "Whether this is the person's primary phone number",
}, },
{ {
displayName: 'Status', displayName: 'Status',
@ -367,12 +363,8 @@ export const makeSimpleField = (resource: Resource, operation: Operation): INode
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: [resource],
resource, operation: [operation],
],
operation: [
operation,
],
}, },
}, },
default: true, default: true,

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { makeSimpleField } from './SharedFields';
makeSimpleField,
} from './SharedFields';
export const signatureOperations: INodeProperties[] = [ export const signatureOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const signatureOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature',
],
}, },
}, },
options: [ options: [
@ -58,12 +52,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -76,12 +66,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -94,12 +80,8 @@ export const signatureFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: [ options: [
@ -125,12 +107,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -143,12 +121,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -166,12 +140,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -183,12 +153,8 @@ export const signatureFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -203,15 +169,9 @@ export const signatureFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },
@ -229,12 +189,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -247,12 +203,8 @@ export const signatureFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -265,12 +217,8 @@ export const signatureFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['signature'],
'signature', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
options: [ options: [

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { makeSimpleField } from './SharedFields';
makeSimpleField,
} from './SharedFields';
export const tagOperations: INodeProperties[] = [ export const tagOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const tagOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag',
],
}, },
}, },
options: [ options: [
@ -53,12 +47,8 @@ export const tagFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -76,12 +66,8 @@ export const tagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
}, },
@ -98,12 +84,8 @@ export const tagFields: INodeProperties[] = [
description: 'Whether to return all results or only up to a given limit', description: 'Whether to return all results or only up to a given limit',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -118,15 +100,9 @@ export const tagFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },

View file

@ -1,12 +1,18 @@
import { languageOptions } from './descriptions/SharedFields'; import { languageOptions } from './descriptions/SharedFields';
export type Resource = 'attendance' | 'event' | 'person' | 'personTag' | 'petition' | 'signature' | 'tag'; export type Resource =
| 'attendance'
| 'event'
| 'person'
| 'personTag'
| 'petition'
| 'signature'
| 'tag';
export type Operation = 'create' | 'delete' | 'get' | 'getAll' | 'update' | 'add' | 'remove'; export type Operation = 'create' | 'delete' | 'get' | 'getAll' | 'update' | 'add' | 'remove';
// @ts-ignore // @ts-ignore
export type LanguageCodes = typeof languageOptions[number]['value'] export type LanguageCodes = typeof languageOptions[number]['value'];
// ---------------------------------------- // ----------------------------------------
// UI fields // UI fields
@ -19,25 +25,25 @@ export type AllFieldsUi = {
languages_spoken: LanguageCodes; languages_spoken: LanguageCodes;
target: string; target: string;
location: LocationUi; location: LocationUi;
} };
export type EmailAddressUi = { export type EmailAddressUi = {
email_addresses_fields: EmailAddressField, email_addresses_fields: EmailAddressField;
} };
export type EmailAddressField = { export type EmailAddressField = {
primary: boolean; primary: boolean;
address: string; address: string;
status: EmailStatus; status: EmailStatus;
} };
type BaseStatus = 'subscribed' | 'unsubscribed' | 'bouncing' | 'previous bounce'; type BaseStatus = 'subscribed' | 'unsubscribed' | 'bouncing' | 'previous bounce';
type EmailStatus = BaseStatus | 'spam complaint' | 'previous spam complaint'; type EmailStatus = BaseStatus | 'spam complaint' | 'previous spam complaint';
type PhoneNumberUi = { type PhoneNumberUi = {
phone_numbers_fields: PhoneNumberField[], phone_numbers_fields: PhoneNumberField[];
} };
export type PhoneNumberField = { export type PhoneNumberField = {
primary: boolean; primary: boolean;
@ -46,12 +52,12 @@ export type PhoneNumberField = {
}; };
type PostalAddressesUi = { type PostalAddressesUi = {
postal_addresses_fields: PostalAddressField[], postal_addresses_fields: PostalAddressField[];
} };
type LocationUi = { type LocationUi = {
postal_addresses_fields: PostalAddressField, postal_addresses_fields: PostalAddressField;
} };
export type PostalAddressField = { export type PostalAddressField = {
primary: boolean; primary: boolean;
@ -61,17 +67,16 @@ export type PostalAddressField = {
postal_code: string; postal_code: string;
country: string; country: string;
language: LanguageCodes; language: LanguageCodes;
location: { location_fields: LatitudeLongitude } location: { location_fields: LatitudeLongitude };
} };
type LatitudeLongitude = { type LatitudeLongitude = {
latitude: string; latitude: string;
longitude: string; longitude: string;
} };
export type FieldWithPrimaryField = EmailAddressField | PhoneNumberField | PostalAddressField; export type FieldWithPrimaryField = EmailAddressField | PhoneNumberField | PostalAddressField;
// ---------------------------------------- // ----------------------------------------
// responses // responses
// ---------------------------------------- // ----------------------------------------
@ -90,7 +95,6 @@ export type PersonResponse = Response & {
export type PetitionResponse = Response & { _embedded: { 'osdi:creator': PersonResponse } }; export type PetitionResponse = Response & { _embedded: { 'osdi:creator': PersonResponse } };
// ---------------------------------------- // ----------------------------------------
// utils // utils
// ---------------------------------------- // ----------------------------------------

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const accountContactOperations: INodeProperties[] = [ export const accountContactOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const accountContactOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['accountContact'],
'accountContact',
],
}, },
}, },
options: [ options: [
@ -51,12 +47,8 @@ export const accountContactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
}, },
@ -68,12 +60,8 @@ export const accountContactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
}, },
@ -84,12 +72,8 @@ export const accountContactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
default: {}, default: {},
@ -112,12 +96,8 @@ export const accountContactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
default: 0, default: 0,
@ -135,12 +115,8 @@ export const accountContactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
description: 'Account ID', description: 'Account ID',
@ -154,12 +130,8 @@ export const accountContactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['accountContact'],
],
resource: [
'accountContact',
],
}, },
}, },
default: {}, default: {},

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const accountOperations: INodeProperties[] = [ export const accountOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const accountOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['account'],
'account',
],
}, },
}, },
options: [ options: [
@ -67,15 +61,11 @@ export const accountFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
description: 'Account\'s name', description: "Account's name",
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -84,12 +74,8 @@ export const accountFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: {}, default: {},
@ -99,7 +85,7 @@ export const accountFields: INodeProperties[] = [
name: 'accountUrl', name: 'accountUrl',
type: 'string', type: 'string',
default: '', default: '',
description: 'Account\'s website', description: "Account's website",
}, },
{ {
displayName: 'Fields', displayName: 'Fields',
@ -124,7 +110,8 @@ export const accountFields: INodeProperties[] = [
loadOptionsMethod: 'getAccountCustomFields', loadOptionsMethod: 'getAccountCustomFields',
}, },
default: '', default: '',
description: 'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Field Value', displayName: 'Field Value',
@ -149,12 +136,8 @@ export const accountFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: 0, default: 0,
@ -169,12 +152,8 @@ export const accountFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: {}, default: {},
@ -184,14 +163,14 @@ export const accountFields: INodeProperties[] = [
name: 'name', name: 'name',
type: 'string', type: 'string',
default: '', default: '',
description: 'Account\'s name', description: "Account's name",
}, },
{ {
displayName: 'Account URL', displayName: 'Account URL',
name: 'accountUrl', name: 'accountUrl',
type: 'string', type: 'string',
default: '', default: '',
description: 'Account\'s website', description: "Account's website",
}, },
{ {
displayName: 'Fields', displayName: 'Fields',
@ -216,7 +195,8 @@ export const accountFields: INodeProperties[] = [
loadOptionsMethod: 'getAccountCustomFields', loadOptionsMethod: 'getAccountCustomFields',
}, },
default: '', default: '',
description: 'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Field Value', displayName: 'Field Value',
@ -240,12 +220,8 @@ export const accountFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: 0, default: 0,
@ -261,12 +237,8 @@ export const accountFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: 0, default: 0,
@ -284,12 +256,8 @@ export const accountFields: INodeProperties[] = [
placeholder: 'Add Filter', placeholder: 'Add Filter',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['account'],
],
resource: [
'account',
],
}, },
}, },
default: {}, default: {},
@ -303,5 +271,4 @@ export const accountFields: INodeProperties[] = [
}, },
], ],
}, },
]; ];

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -18,65 +16,32 @@ import {
IProduct, IProduct,
} from './GenericFunctions'; } from './GenericFunctions';
import { import { contactFields, contactOperations } from './ContactDescription';
contactFields,
contactOperations,
} from './ContactDescription';
import { import { dealFields, dealOperations } from './DealDescription';
dealFields,
dealOperations,
} from './DealDescription';
import { import { ecomOrderFields, ecomOrderOperations } from './EcomOrderDescription';
ecomOrderFields,
ecomOrderOperations,
} from './EcomOrderDescription';
import { import { ecomCustomerFields, ecomCustomerOperations } from './EcomCustomerDescription';
ecomCustomerFields,
ecomCustomerOperations,
} from './EcomCustomerDescription';
import { import {
ecomOrderProductsFields, ecomOrderProductsFields,
ecomOrderProductsOperations, ecomOrderProductsOperations,
} from './EcomOrderProductsDescription'; } from './EcomOrderProductsDescription';
import { import { connectionFields, connectionOperations } from './ConnectionDescription';
connectionFields,
connectionOperations,
} from './ConnectionDescription';
import { import { accountFields, accountOperations } from './AccountDescription';
accountFields,
accountOperations
} from './AccountDescription';
import { import { tagFields, tagOperations } from './TagDescription';
tagFields,
tagOperations
} from './TagDescription';
import { import { accountContactFields, accountContactOperations } from './AccountContactDescription';
accountContactFields,
accountContactOperations
} from './AccountContactDescription';
import { import { contactListFields, contactListOperations } from './ContactListDescription';
contactListFields,
contactListOperations,
} from './ContactListDescription';
import { import { contactTagFields, contactTagOperations } from './ContactTagDescription';
contactTagFields,
contactTagOperations,
} from './ContactTagDescription';
import { import { listFields, listOperations } from './ListDescription';
listFields,
listOperations,
} from './ListDescription';
interface CustomProperty { interface CustomProperty {
name: string; name: string;
@ -91,13 +56,23 @@ interface CustomProperty {
*/ */
function addAdditionalFields(body: IDataObject, additionalFields: IDataObject) { function addAdditionalFields(body: IDataObject, additionalFields: IDataObject) {
for (const key of Object.keys(additionalFields)) { for (const key of Object.keys(additionalFields)) {
if (key === 'customProperties' && (additionalFields.customProperties as IDataObject).property !== undefined) { if (
for (const customProperty of (additionalFields.customProperties as IDataObject)!.property! as CustomProperty[]) { key === 'customProperties' &&
(additionalFields.customProperties as IDataObject).property !== undefined
) {
for (const customProperty of (additionalFields.customProperties as IDataObject)!
.property! as CustomProperty[]) {
body[customProperty.name] = customProperty.value; body[customProperty.name] = customProperty.value;
} }
} else if (key === 'fieldValues' && (additionalFields.fieldValues as IDataObject).property !== undefined) { } else if (
key === 'fieldValues' &&
(additionalFields.fieldValues as IDataObject).property !== undefined
) {
body.fieldValues = (additionalFields.fieldValues as IDataObject).property; body.fieldValues = (additionalFields.fieldValues as IDataObject).property;
} else if (key === 'fields' && (additionalFields.fields as IDataObject).property !== undefined) { } else if (
key === 'fields' &&
(additionalFields.fields as IDataObject).property !== undefined
) {
body.fields = (additionalFields.fields as IDataObject).property; body.fields = (additionalFields.fields as IDataObject).property;
} else { } else {
body[key] = additionalFields[key]; body[key] = additionalFields[key];
@ -263,7 +238,6 @@ export class ActiveCampaign implements INodeType {
// ecommerceOrderProducts // ecommerceOrderProducts
// ---------------------------------- // ----------------------------------
...ecomOrderProductsFields, ...ecomOrderProductsFields,
], ],
}; };
@ -273,7 +247,13 @@ export class ActiveCampaign implements INodeType {
// select them easily // select them easily
async getContactCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getContactCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const { fields } = await activeCampaignApiRequest.call(this, 'GET', '/api/3/fields', {}, { limit: 100 }); const { fields } = await activeCampaignApiRequest.call(
this,
'GET',
'/api/3/fields',
{},
{ limit: 100 },
);
for (const field of fields) { for (const field of fields) {
const fieldName = field.title; const fieldName = field.title;
const fieldId = field.id; const fieldId = field.id;
@ -288,7 +268,13 @@ export class ActiveCampaign implements INodeType {
// select them easily // select them easily
async getAccountCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getAccountCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const { accountCustomFieldMeta: fields } = await activeCampaignApiRequest.call(this, 'GET', '/api/3/accountCustomFieldMeta', {}, { limit: 100 }); const { accountCustomFieldMeta: fields } = await activeCampaignApiRequest.call(
this,
'GET',
'/api/3/accountCustomFieldMeta',
{},
{ limit: 100 },
);
for (const field of fields) { for (const field of fields) {
const fieldName = field.fieldLabel; const fieldName = field.fieldLabel;
const fieldId = field.id; const fieldId = field.id;
@ -303,7 +289,13 @@ export class ActiveCampaign implements INodeType {
// select them easily // select them easily
async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const { tags } = await activeCampaignApiRequest.call(this, 'GET', '/api/3/tags', {}, { limit: 100 }); const { tags } = await activeCampaignApiRequest.call(
this,
'GET',
'/api/3/tags',
{},
{ limit: 100 },
);
for (const tag of tags) { for (const tag of tags) {
returnData.push({ returnData.push({
name: tag.tag, name: tag.tag,
@ -334,7 +326,6 @@ export class ActiveCampaign implements INodeType {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
try { try {
dataKey = undefined; dataKey = undefined;
resource = this.getNodeParameter('resource', 0) as string; resource = this.getNodeParameter('resource', 0) as string;
operation = this.getNodeParameter('operation', 0) as string; operation = this.getNodeParameter('operation', 0) as string;
@ -367,7 +358,6 @@ export class ActiveCampaign implements INodeType {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.contact as IDataObject, additionalFields); addAdditionalFields(body.contact as IDataObject, additionalFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// contact:delete // contact:delete
@ -377,7 +367,6 @@ export class ActiveCampaign implements INodeType {
const contactId = this.getNodeParameter('contactId', i) as number; const contactId = this.getNodeParameter('contactId', i) as number;
endpoint = `/api/3/contacts/${contactId}`; endpoint = `/api/3/contacts/${contactId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// contact:get // contact:get
@ -387,7 +376,6 @@ export class ActiveCampaign implements INodeType {
const contactId = this.getNodeParameter('contactId', i) as number; const contactId = this.getNodeParameter('contactId', i) as number;
endpoint = `/api/3/contacts/${contactId}`; endpoint = `/api/3/contacts/${contactId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// contacts:getAll // contacts:getAll
@ -415,7 +403,6 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/contacts`; endpoint = `/api/3/contacts`;
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// contact:update // contact:update
@ -432,9 +419,12 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.contact as IDataObject, updateFields); addAdditionalFields(body.contact as IDataObject, updateFields);
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'account') { } else if (resource === 'account') {
if (operation === 'create') { if (operation === 'create') {
@ -454,7 +444,6 @@ export class ActiveCampaign implements INodeType {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.account as IDataObject, additionalFields); addAdditionalFields(body.account as IDataObject, additionalFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// account:delete // account:delete
@ -464,7 +453,6 @@ export class ActiveCampaign implements INodeType {
const accountId = this.getNodeParameter('accountId', i) as number; const accountId = this.getNodeParameter('accountId', i) as number;
endpoint = `/api/3/accounts/${accountId}`; endpoint = `/api/3/accounts/${accountId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// account:get // account:get
@ -474,7 +462,6 @@ export class ActiveCampaign implements INodeType {
const accountId = this.getNodeParameter('accountId', i) as number; const accountId = this.getNodeParameter('accountId', i) as number;
endpoint = `/api/3/accounts/${accountId}`; endpoint = `/api/3/accounts/${accountId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// account:getAll // account:getAll
@ -496,7 +483,6 @@ export class ActiveCampaign implements INodeType {
const filters = this.getNodeParameter('filters', i) as IDataObject; const filters = this.getNodeParameter('filters', i) as IDataObject;
Object.assign(qs, filters); Object.assign(qs, filters);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// account:update // account:update
@ -513,9 +499,12 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.account as IDataObject, updateFields); addAdditionalFields(body.account as IDataObject, updateFields);
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'accountContact') { } else if (resource === 'accountContact') {
if (operation === 'create') { if (operation === 'create') {
@ -536,7 +525,6 @@ export class ActiveCampaign implements INodeType {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.account as IDataObject, additionalFields); addAdditionalFields(body.account as IDataObject, additionalFields);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// accountContact:update // accountContact:update
@ -553,7 +541,6 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.accountContact as IDataObject, updateFields); addAdditionalFields(body.accountContact as IDataObject, updateFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// accountContact:delete // accountContact:delete
@ -563,9 +550,12 @@ export class ActiveCampaign implements INodeType {
const accountContactId = this.getNodeParameter('accountContactId', i) as number; const accountContactId = this.getNodeParameter('accountContactId', i) as number;
endpoint = `/api/3/accountContacts/${accountContactId}`; endpoint = `/api/3/accountContacts/${accountContactId}`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'contactTag') { } else if (resource === 'contactTag') {
if (operation === 'add') { if (operation === 'add') {
@ -583,7 +573,6 @@ export class ActiveCampaign implements INodeType {
contact: this.getNodeParameter('contactId', i) as string, contact: this.getNodeParameter('contactId', i) as string,
tag: this.getNodeParameter('tagId', i) as string, tag: this.getNodeParameter('tagId', i) as string,
} as IDataObject; } as IDataObject;
} else if (operation === 'remove') { } else if (operation === 'remove') {
// ---------------------------------- // ----------------------------------
// contactTag:remove // contactTag:remove
@ -593,9 +582,12 @@ export class ActiveCampaign implements INodeType {
const contactTagId = this.getNodeParameter('contactTagId', i) as number; const contactTagId = this.getNodeParameter('contactTagId', i) as number;
endpoint = `/api/3/contactTags/${contactTagId}`; endpoint = `/api/3/contactTags/${contactTagId}`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'contactList') { } else if (resource === 'contactList') {
if (operation === 'add') { if (operation === 'add') {
@ -614,7 +606,6 @@ export class ActiveCampaign implements INodeType {
contact: this.getNodeParameter('contactId', i) as string, contact: this.getNodeParameter('contactId', i) as string,
status: 1, status: 1,
} as IDataObject; } as IDataObject;
} else if (operation === 'remove') { } else if (operation === 'remove') {
// ---------------------------------- // ----------------------------------
// contactList:remove // contactList:remove
@ -631,9 +622,12 @@ export class ActiveCampaign implements INodeType {
} as IDataObject; } as IDataObject;
dataKey = 'contacts'; dataKey = 'contacts';
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'list') { } else if (resource === 'list') {
if (operation === 'getAll') { if (operation === 'getAll') {
@ -646,7 +640,6 @@ export class ActiveCampaign implements INodeType {
returnAll = this.getNodeParameter('returnAll', i) as boolean; returnAll = this.getNodeParameter('returnAll', i) as boolean;
const simple = this.getNodeParameter('simple', i, true) as boolean; const simple = this.getNodeParameter('simple', i, true) as boolean;
if (returnAll === false) { if (returnAll === false) {
qs.limit = this.getNodeParameter('limit', i) as number; qs.limit = this.getNodeParameter('limit', i) as number;
} }
@ -657,7 +650,6 @@ export class ActiveCampaign implements INodeType {
endpoint = `/api/3/lists`; endpoint = `/api/3/lists`;
} }
} else if (resource === 'tag') { } else if (resource === 'tag') {
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------- // ----------------------------------
@ -677,7 +669,6 @@ export class ActiveCampaign implements INodeType {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.tag as IDataObject, additionalFields); addAdditionalFields(body.tag as IDataObject, additionalFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// tag:delete // tag:delete
@ -687,7 +678,6 @@ export class ActiveCampaign implements INodeType {
const tagId = this.getNodeParameter('tagId', i) as number; const tagId = this.getNodeParameter('tagId', i) as number;
endpoint = `/api/3/tags/${tagId}`; endpoint = `/api/3/tags/${tagId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// tag:get // tag:get
@ -697,7 +687,6 @@ export class ActiveCampaign implements INodeType {
const tagId = this.getNodeParameter('tagId', i) as number; const tagId = this.getNodeParameter('tagId', i) as number;
endpoint = `/api/3/tags/${tagId}`; endpoint = `/api/3/tags/${tagId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// tags:getAll // tags:getAll
@ -716,7 +705,6 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/tags`; endpoint = `/api/3/tags`;
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// tags:update // tags:update
@ -733,9 +721,12 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.tag as IDataObject, updateFields); addAdditionalFields(body.tag as IDataObject, updateFields);
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'deal') { } else if (resource === 'deal') {
if (operation === 'create') { if (operation === 'create') {
@ -771,7 +762,6 @@ export class ActiveCampaign implements INodeType {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.deal as IDataObject, additionalFields); addAdditionalFields(body.deal as IDataObject, additionalFields);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// deal:update // deal:update
@ -786,7 +776,6 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.deal as IDataObject, updateFields); addAdditionalFields(body.deal as IDataObject, updateFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// deal:delete // deal:delete
@ -796,7 +785,6 @@ export class ActiveCampaign implements INodeType {
const dealId = this.getNodeParameter('dealId', i) as number; const dealId = this.getNodeParameter('dealId', i) as number;
endpoint = `/api/3/deals/${dealId}`; endpoint = `/api/3/deals/${dealId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// deal:get // deal:get
@ -806,7 +794,6 @@ export class ActiveCampaign implements INodeType {
const dealId = this.getNodeParameter('dealId', i) as number; const dealId = this.getNodeParameter('dealId', i) as number;
endpoint = `/api/3/deals/${dealId}`; endpoint = `/api/3/deals/${dealId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// deals:getAll // deals:getAll
@ -825,7 +812,6 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/deals`; endpoint = `/api/3/deals`;
} else if (operation === 'createNote') { } else if (operation === 'createNote') {
// ---------------------------------- // ----------------------------------
// deal:createNote // deal:createNote
@ -838,7 +824,6 @@ export class ActiveCampaign implements INodeType {
const dealId = this.getNodeParameter('dealId', i) as number; const dealId = this.getNodeParameter('dealId', i) as number;
endpoint = `/api/3/deals/${dealId}/notes`; endpoint = `/api/3/deals/${dealId}/notes`;
} else if (operation === 'updateNote') { } else if (operation === 'updateNote') {
// ---------------------------------- // ----------------------------------
// deal:updateNote // deal:updateNote
@ -852,9 +837,12 @@ export class ActiveCampaign implements INodeType {
const dealId = this.getNodeParameter('dealId', i) as number; const dealId = this.getNodeParameter('dealId', i) as number;
const dealNoteId = this.getNodeParameter('dealNoteId', i) as number; const dealNoteId = this.getNodeParameter('dealNoteId', i) as number;
endpoint = `/api/3/deals/${dealId}/notes/${dealNoteId}`; endpoint = `/api/3/deals/${dealId}/notes/${dealNoteId}`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'connection') { } else if (resource === 'connection') {
if (operation === 'create') { if (operation === 'create') {
@ -873,7 +861,6 @@ export class ActiveCampaign implements INodeType {
logoUrl: this.getNodeParameter('logoUrl', i) as string, logoUrl: this.getNodeParameter('logoUrl', i) as string,
linkUrl: this.getNodeParameter('linkUrl', i) as string, linkUrl: this.getNodeParameter('linkUrl', i) as string,
} as IDataObject; } as IDataObject;
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// connection:update // connection:update
@ -888,7 +875,6 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.connection as IDataObject, updateFields); addAdditionalFields(body.connection as IDataObject, updateFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// connection:delete // connection:delete
@ -898,7 +884,6 @@ export class ActiveCampaign implements INodeType {
const connectionId = this.getNodeParameter('connectionId', i) as number; const connectionId = this.getNodeParameter('connectionId', i) as number;
endpoint = `/api/3/connections/${connectionId}`; endpoint = `/api/3/connections/${connectionId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// connection:get // connection:get
@ -908,7 +893,6 @@ export class ActiveCampaign implements INodeType {
const connectionId = this.getNodeParameter('connectionId', i) as number; const connectionId = this.getNodeParameter('connectionId', i) as number;
endpoint = `/api/3/connections/${connectionId}`; endpoint = `/api/3/connections/${connectionId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// connections:getAll // connections:getAll
@ -927,9 +911,12 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/connections`; endpoint = `/api/3/connections`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'ecommerceOrder') { } else if (resource === 'ecommerceOrder') {
if (operation === 'create') { if (operation === 'create') {
@ -966,12 +953,14 @@ export class ActiveCampaign implements INodeType {
addAdditionalFields(body.ecomOrder as IDataObject, { abandonedDate }); addAdditionalFields(body.ecomOrder as IDataObject, { abandonedDate });
} }
const orderProducts = this.getNodeParameter('orderProducts', i) as unknown as IProduct[]; const orderProducts = this.getNodeParameter(
'orderProducts',
i,
) as unknown as IProduct[];
addAdditionalFields(body.ecomOrder as IDataObject, { orderProducts }); addAdditionalFields(body.ecomOrder as IDataObject, { orderProducts });
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
addAdditionalFields(body.ecomOrder as IDataObject, additionalFields); addAdditionalFields(body.ecomOrder as IDataObject, additionalFields);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// ecommerceOrder:update // ecommerceOrder:update
@ -986,7 +975,6 @@ export class ActiveCampaign implements INodeType {
const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject;
addAdditionalFields(body.ecomOrder as IDataObject, updateFields); addAdditionalFields(body.ecomOrder as IDataObject, updateFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// ecommerceOrder:delete // ecommerceOrder:delete
@ -996,7 +984,6 @@ export class ActiveCampaign implements INodeType {
const orderId = this.getNodeParameter('orderId', i) as number; const orderId = this.getNodeParameter('orderId', i) as number;
endpoint = `/api/3/ecomOrders/${orderId}`; endpoint = `/api/3/ecomOrders/${orderId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// ecommerceOrder:get // ecommerceOrder:get
@ -1006,7 +993,6 @@ export class ActiveCampaign implements INodeType {
const orderId = this.getNodeParameter('orderId', i) as number; const orderId = this.getNodeParameter('orderId', i) as number;
endpoint = `/api/3/ecomOrders/${orderId}`; endpoint = `/api/3/ecomOrders/${orderId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// ecommerceOrders:getAll // ecommerceOrders:getAll
@ -1025,9 +1011,12 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/ecomOrders`; endpoint = `/api/3/ecomOrders`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'ecommerceCustomer') { } else if (resource === 'ecommerceCustomer') {
if (operation === 'create') { if (operation === 'create') {
@ -1054,7 +1043,6 @@ export class ActiveCampaign implements INodeType {
} }
} }
addAdditionalFields(body.ecomCustomer as IDataObject, additionalFields); addAdditionalFields(body.ecomCustomer as IDataObject, additionalFields);
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// ecommerceCustomer:update // ecommerceCustomer:update
@ -1076,7 +1064,6 @@ export class ActiveCampaign implements INodeType {
} }
} }
addAdditionalFields(body.ecomCustomer as IDataObject, updateFields); addAdditionalFields(body.ecomCustomer as IDataObject, updateFields);
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// ecommerceCustomer:delete // ecommerceCustomer:delete
@ -1086,7 +1073,6 @@ export class ActiveCampaign implements INodeType {
const ecommerceCustomerId = this.getNodeParameter('ecommerceCustomerId', i) as number; const ecommerceCustomerId = this.getNodeParameter('ecommerceCustomerId', i) as number;
endpoint = `/api/3/ecomCustomers/${ecommerceCustomerId}`; endpoint = `/api/3/ecomCustomers/${ecommerceCustomerId}`;
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// ecommerceCustomer:get // ecommerceCustomer:get
@ -1096,7 +1082,6 @@ export class ActiveCampaign implements INodeType {
const ecommerceCustomerId = this.getNodeParameter('ecommerceCustomerId', i) as number; const ecommerceCustomerId = this.getNodeParameter('ecommerceCustomerId', i) as number;
endpoint = `/api/3/ecomCustomers/${ecommerceCustomerId}`; endpoint = `/api/3/ecomCustomers/${ecommerceCustomerId}`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// ecommerceCustomers:getAll // ecommerceCustomers:getAll
@ -1115,9 +1100,12 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/ecomCustomers`; endpoint = `/api/3/ecomCustomers`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else if (resource === 'ecommerceOrderProducts') { } else if (resource === 'ecommerceOrderProducts') {
if (operation === 'getByProductId') { if (operation === 'getByProductId') {
@ -1129,8 +1117,6 @@ export class ActiveCampaign implements INodeType {
const procuctId = this.getNodeParameter('procuctId', i) as number; const procuctId = this.getNodeParameter('procuctId', i) as number;
endpoint = `/api/3/ecomOrderProducts/${procuctId}`; endpoint = `/api/3/ecomOrderProducts/${procuctId}`;
} else if (operation === 'getByOrderId') { } else if (operation === 'getByOrderId') {
// ---------------------------------- // ----------------------------------
// ecommerceOrderProducts:getByOrderId // ecommerceOrderProducts:getByOrderId
@ -1142,7 +1128,6 @@ export class ActiveCampaign implements INodeType {
const orderId = this.getNodeParameter('orderId', i) as number; const orderId = this.getNodeParameter('orderId', i) as number;
endpoint = `/api/3/ecomOrders/${orderId}/orderProducts`; endpoint = `/api/3/ecomOrders/${orderId}/orderProducts`;
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// ecommerceOrderProductss:getAll // ecommerceOrderProductss:getAll
@ -1161,20 +1146,38 @@ export class ActiveCampaign implements INodeType {
} }
endpoint = `/api/3/ecomOrderProducts`; endpoint = `/api/3/ecomOrderProducts`;
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The operation "${operation}" is not known`,
{ itemIndex: i },
);
} }
} else { } else {
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, { itemIndex: i }); throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`, {
itemIndex: i,
});
} }
let responseData; let responseData;
if (returnAll === true) { if (returnAll === true) {
responseData = await activeCampaignApiRequestAllItems.call(this, requestMethod, endpoint, body, qs, dataKey); responseData = await activeCampaignApiRequestAllItems.call(
this,
requestMethod,
endpoint,
body,
qs,
dataKey,
);
} else { } else {
responseData = await activeCampaignApiRequest.call(this, requestMethod, endpoint, body, qs, dataKey); responseData = await activeCampaignApiRequest.call(
this,
requestMethod,
endpoint,
body,
qs,
dataKey,
);
} }
if (resource === 'contactList' && operation === 'add' && responseData === undefined) { if (resource === 'contactList' && operation === 'add' && responseData === undefined) {

View file

@ -1,7 +1,4 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -12,10 +9,7 @@ import {
IWebhookResponseData, IWebhookResponseData,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { activeCampaignApiRequest, activeCampaignApiRequestAllItems } from './GenericFunctions';
activeCampaignApiRequest,
activeCampaignApiRequestAllItems,
} from './GenericFunctions';
export class ActiveCampaignTrigger implements INodeType { export class ActiveCampaignTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -50,7 +44,8 @@ export class ActiveCampaignTrigger implements INodeType {
displayName: 'Event Names or IDs', displayName: 'Event Names or IDs',
name: 'events', name: 'events',
type: 'multiOptions', type: 'multiOptions',
description: 'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', description:
'Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getEvents', loadOptionsMethod: 'getEvents',
}, },
@ -93,7 +88,14 @@ export class ActiveCampaignTrigger implements INodeType {
// select them easily // select them easily
async getEvents(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getEvents(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const events = await activeCampaignApiRequestAllItems.call(this, 'GET', '/api/3/webhook/events', {}, {}, 'webhookEvents'); const events = await activeCampaignApiRequestAllItems.call(
this,
'GET',
'/api/3/webhook/events',
{},
{},
'webhookEvents',
);
for (const event of events) { for (const event of events) {
const eventName = event; const eventName = event;
const eventId = event; const eventId = event;
@ -135,14 +137,24 @@ export class ActiveCampaignTrigger implements INodeType {
sources, sources,
}, },
}; };
const { webhook } = await activeCampaignApiRequest.call(this, 'POST', '/api/3/webhooks', body); const { webhook } = await activeCampaignApiRequest.call(
this,
'POST',
'/api/3/webhooks',
body,
);
webhookData.webhookId = webhook.id; webhookData.webhookId = webhook.id;
return true; return true;
}, },
async delete(this: IHookFunctions): Promise<boolean> { async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node'); const webhookData = this.getWorkflowStaticData('node');
try { try {
await activeCampaignApiRequest.call(this, 'DELETE', `/api/3/webhooks/${webhookData.webhookId}`, {}); await activeCampaignApiRequest.call(
this,
'DELETE',
`/api/3/webhooks/${webhookData.webhookId}`,
{},
);
} catch (error) { } catch (error) {
return false; return false;
} }
@ -155,9 +167,7 @@ export class ActiveCampaignTrigger implements INodeType {
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> { async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const req = this.getRequestObject(); const req = this.getRequestObject();
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(req.body)],
this.helpers.returnJsonArray(req.body),
],
}; };
} }
} }

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const connectionOperations: INodeProperties[] = [ export const connectionOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const connectionOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['connection'],
'connection',
],
}, },
}, },
options: [ options: [
@ -53,7 +47,6 @@ export const connectionOperations: INodeProperties[] = [
], ],
default: 'create', default: 'create',
}, },
]; ];
export const connectionFields: INodeProperties[] = [ export const connectionFields: INodeProperties[] = [
@ -68,12 +61,8 @@ export const connectionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
description: 'The name of the service', description: 'The name of the service',
@ -86,12 +75,8 @@ export const connectionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
description: 'The ID of the account in the external service', description: 'The ID of the account in the external service',
@ -104,15 +89,12 @@ export const connectionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
description: 'The name associated with the account in the external service. Often this will be a company name (e.g., "My Toystore, Inc.").', description:
'The name associated with the account in the external service. Often this will be a company name (e.g., "My Toystore, Inc.").',
}, },
{ {
displayName: 'Logo URL', displayName: 'Logo URL',
@ -122,12 +104,8 @@ export const connectionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
description: 'The URL to a logo image for the external service', description: 'The URL to a logo image for the external service',
@ -140,15 +118,12 @@ export const connectionFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
description: 'The URL to a page where the integration with the external service can be managed in the third-party\'s website', description:
"The URL to a page where the integration with the external service can be managed in the third-party's website",
}, },
// ---------------------------------- // ----------------------------------
@ -160,12 +135,8 @@ export const connectionFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
default: 0, default: 0,
@ -180,12 +151,8 @@ export const connectionFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
default: {}, default: {},
@ -209,7 +176,8 @@ export const connectionFields: INodeProperties[] = [
name: 'name', name: 'name',
type: 'string', type: 'string',
default: '', default: '',
description: 'The name associated with the account in the external service. Often this will be a company name (e.g., "My Toystore, Inc.").', description:
'The name associated with the account in the external service. Often this will be a company name (e.g., "My Toystore, Inc.").',
}, },
{ {
displayName: 'Logo URL', displayName: 'Logo URL',
@ -223,7 +191,8 @@ export const connectionFields: INodeProperties[] = [
name: 'linkUrl', name: 'linkUrl',
type: 'string', type: 'string',
default: '', default: '',
description: 'The URL to a page where the integration with the external service can be managed in the third-party\'s website', description:
"The URL to a page where the integration with the external service can be managed in the third-party's website",
}, },
{ {
displayName: 'Status', displayName: 'Status',
@ -237,7 +206,8 @@ export const connectionFields: INodeProperties[] = [
name: 'syncStatus', name: 'syncStatus',
type: 'number', type: 'number',
default: 1, default: 1,
description: 'The status of a sync triggered on the connection (0 = sync stopped; 1 = sync running)', description:
'The status of a sync triggered on the connection (0 = sync stopped; 1 = sync running)',
}, },
], ],
}, },
@ -251,12 +221,8 @@ export const connectionFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
default: 0, default: 0,
@ -273,12 +239,8 @@ export const connectionFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['connection'],
],
resource: [
'connection',
],
}, },
}, },
default: 0, default: 0,
@ -290,5 +252,4 @@ export const connectionFields: INodeProperties[] = [
// connection:getAll // connection:getAll
// ---------------------------------- // ----------------------------------
...activeCampaignDefaultGetAllProperties('connection', 'getAll'), ...activeCampaignDefaultGetAllProperties('connection', 'getAll'),
]; ];

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const contactOperations: INodeProperties[] = [ export const contactOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact',
],
}, },
}, },
options: [ options: [
@ -68,12 +62,8 @@ export const contactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
description: 'The email of the contact to create', description: 'The email of the contact to create',
@ -84,16 +74,13 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: false, default: false,
description: 'Whether to update user if it exists already. If not set and user exists it will error instead.', description:
'Whether to update user if it exists already. If not set and user exists it will error instead.',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -102,12 +89,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -135,7 +118,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getContactCustomFields', loadOptionsMethod: 'getContactCustomFields',
}, },
default: '', default: '',
description: 'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Field Value', displayName: 'Field Value',
@ -181,12 +165,8 @@ export const contactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: 0, default: 0,
@ -201,12 +181,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -234,7 +210,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getContactCustomFields', loadOptionsMethod: 'getContactCustomFields',
}, },
default: '', default: '',
description: 'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the field to set. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Field Value', displayName: 'Field Value',
@ -288,12 +265,8 @@ export const contactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: 0, default: 0,
@ -310,12 +283,8 @@ export const contactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: 0, default: 0,
@ -334,12 +303,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -392,7 +357,8 @@ export const contactFields: INodeProperties[] = [
name: 'search', name: 'search',
type: 'string', type: 'string',
default: '', default: '',
description: 'Filter contacts that match the given value in the contact names, organization, phone or email', description:
'Filter contacts that match the given value in the contact names, organization, phone or email',
}, },
{ {
displayName: 'Segment ID', displayName: 'Segment ID',

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactListOperations: INodeProperties[] = [ export const contactListOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactListOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contactList'],
'contactList',
],
}, },
}, },
options: [ options: [
@ -45,12 +41,8 @@ export const contactListFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactList'],
],
resource: [
'contactList',
],
}, },
}, },
}, },
@ -62,12 +54,8 @@ export const contactListFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactList'],
],
resource: [
'contactList',
],
}, },
}, },
}, },
@ -83,12 +71,8 @@ export const contactListFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['remove'],
'remove', resource: ['contactList'],
],
resource: [
'contactList',
],
}, },
}, },
}, },
@ -100,12 +84,8 @@ export const contactListFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['remove'],
'remove', resource: ['contactList'],
],
resource: [
'contactList',
],
}, },
}, },
}, },

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactTagOperations: INodeProperties[] = [ export const contactTagOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactTagOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contactTag'],
'contactTag',
],
}, },
}, },
options: [ options: [
@ -41,7 +37,8 @@ export const contactTagFields: INodeProperties[] = [
displayName: 'Tag Name or ID', displayName: 'Tag Name or ID',
name: 'tagId', name: 'tagId',
type: 'options', type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
}, },
@ -49,12 +46,8 @@ export const contactTagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactTag'],
],
resource: [
'contactTag',
],
}, },
}, },
}, },
@ -66,12 +59,8 @@ export const contactTagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactTag'],
],
resource: [
'contactTag',
],
}, },
}, },
}, },
@ -84,12 +73,8 @@ export const contactTagFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['remove'],
'remove', resource: ['contactTag'],
],
resource: [
'contactTag',
],
}, },
}, },
default: 0, default: 0,

View file

@ -1,14 +1,8 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { allCurrencies } from './currencies';
allCurrencies,
} from './currencies';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const dealOperations: INodeProperties[] = [ export const dealOperations: INodeProperties[] = [
{ {
@ -18,9 +12,7 @@ export const dealOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal',
],
}, },
}, },
options: [ options: [
@ -69,7 +61,6 @@ export const dealOperations: INodeProperties[] = [
], ],
default: 'create', default: 'create',
}, },
]; ];
export const dealFields: INodeProperties[] = [ export const dealFields: INodeProperties[] = [
@ -84,33 +75,25 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The title of the deal', description: 'The title of the deal',
}, },
{ {
displayName: 'Deal\'s Contact ID', displayName: "Deal's Contact ID",
name: 'contact', name: 'contact',
type: 'number', type: 'number',
default: 0, default: 0,
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal\'s contact', description: "The ID of the deal's contact",
}, },
{ {
displayName: 'Deal Value', displayName: 'Deal Value',
@ -120,12 +103,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The value of the deal in cents', description: 'The value of the deal in cents',
@ -138,12 +117,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
options: allCurrencies, options: allCurrencies,
@ -156,12 +131,8 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The pipeline ID of the deal', description: 'The pipeline ID of the deal',
@ -173,12 +144,8 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The stage ID of the deal', description: 'The stage ID of the deal',
@ -190,12 +157,8 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The owner ID of the deal', description: 'The owner ID of the deal',
@ -207,12 +170,8 @@ export const dealFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
default: {}, default: {},
@ -251,12 +210,8 @@ export const dealFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
default: 0, default: 0,
@ -271,12 +226,8 @@ export const dealFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
default: {}, default: {},
@ -289,11 +240,11 @@ export const dealFields: INodeProperties[] = [
description: 'The title of the deal', description: 'The title of the deal',
}, },
{ {
displayName: 'Deal\'s Contact ID', displayName: "Deal's Contact ID",
name: 'contact', name: 'contact',
type: 'number', type: 'number',
default: 0, default: 0,
description: 'The ID of the deal\'s contact', description: "The ID of the deal's contact",
}, },
{ {
displayName: 'Deal Value', displayName: 'Deal Value',
@ -366,12 +317,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal to delete', description: 'The ID of the deal to delete',
@ -388,12 +335,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal to get', description: 'The ID of the deal to get',
@ -415,12 +358,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['createNote'],
'createNote', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal note', description: 'The ID of the deal note',
@ -433,12 +372,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['createNote'],
'createNote', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The content of the deal note', description: 'The content of the deal note',
@ -455,12 +390,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['updateNote'],
'updateNote', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal note', description: 'The ID of the deal note',
@ -473,12 +404,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['updateNote'],
'updateNote', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The ID of the deal note', description: 'The ID of the deal note',
@ -490,15 +417,10 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['updateNote'],
'updateNote', resource: ['deal'],
],
resource: [
'deal',
],
}, },
}, },
description: 'The content of the deal note', description: 'The content of the deal note',
}, },
]; ];

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const ecomCustomerOperations: INodeProperties[] = [ export const ecomCustomerOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const ecomCustomerOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['ecommerceCustomer'],
'ecommerceCustomer',
],
}, },
}, },
options: [ options: [
@ -67,12 +61,8 @@ export const ecomCustomerFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
description: 'The ID of the connection object for the service where the customer originates', description: 'The ID of the connection object for the service where the customer originates',
@ -85,12 +75,8 @@ export const ecomCustomerFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
description: 'The ID of the customer in the external service', description: 'The ID of the customer in the external service',
@ -104,12 +90,8 @@ export const ecomCustomerFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
description: 'The email address of the customer', description: 'The email address of the customer',
@ -121,12 +103,8 @@ export const ecomCustomerFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
default: {}, default: {},
@ -150,12 +128,8 @@ export const ecomCustomerFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
default: 0, default: 0,
@ -170,12 +144,8 @@ export const ecomCustomerFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
default: {}, default: {},
@ -185,7 +155,8 @@ export const ecomCustomerFields: INodeProperties[] = [
name: 'connectionid', name: 'connectionid',
type: 'string', type: 'string',
default: '', default: '',
description: 'The ID of the connection object for the service where the customer originates', description:
'The ID of the connection object for the service where the customer originates',
}, },
{ {
displayName: 'Customer ID', displayName: 'Customer ID',
@ -221,12 +192,8 @@ export const ecomCustomerFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
default: 0, default: 0,
@ -243,12 +210,8 @@ export const ecomCustomerFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['ecommerceCustomer'],
],
resource: [
'ecommerceCustomer',
],
}, },
}, },
default: 0, default: 0,

View file

@ -1,14 +1,8 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { allCurrencies } from './currencies';
allCurrencies,
} from './currencies';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const ecomOrderOperations: INodeProperties[] = [ export const ecomOrderOperations: INodeProperties[] = [
{ {
@ -18,9 +12,7 @@ export const ecomOrderOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['ecommerceOrder'],
'ecommerceOrder',
],
}, },
}, },
options: [ options: [
@ -70,15 +62,12 @@ export const ecomOrderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the order in the external service. ONLY REQUIRED IF EXTERNALCHECKOUTID NOT INCLUDED.', description:
'The ID of the order in the external service. ONLY REQUIRED IF EXTERNALCHECKOUTID NOT INCLUDED.',
}, },
{ {
displayName: 'External Checkout ID', displayName: 'External Checkout ID',
@ -87,15 +76,12 @@ export const ecomOrderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the cart in the external service. ONLY REQUIRED IF EXTERNALID IS NOT INCLUDED.', description:
'The ID of the cart in the external service. ONLY REQUIRED IF EXTERNALID IS NOT INCLUDED.',
}, },
{ {
displayName: 'Order Source', displayName: 'Order Source',
@ -105,15 +91,12 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The order source code (0 - will not trigger automations, 1 - will trigger automations)', description:
'The order source code (0 - will not trigger automations, 1 - will trigger automations)',
}, },
{ {
displayName: 'Customer Email', displayName: 'Customer Email',
@ -124,12 +107,8 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The email address of the customer who placed the order', description: 'The email address of the customer who placed the order',
@ -142,15 +121,12 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The total price of the order in cents, including tax and shipping charges. (i.e. $456.78 => 45678). Must be greater than or equal to zero.', description:
'The total price of the order in cents, including tax and shipping charges. (i.e. $456.78 => 45678). Must be greater than or equal to zero.',
}, },
{ {
displayName: 'Order Currency', displayName: 'Order Currency',
@ -160,12 +136,8 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
options: allCurrencies, options: allCurrencies,
@ -179,12 +151,8 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the connection from which this order originated', description: 'The ID of the connection from which this order originated',
@ -197,12 +165,8 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the customer associated with this order', description: 'The ID of the customer associated with this order',
@ -215,12 +179,8 @@ export const ecomOrderFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The date the order was placed', description: 'The date the order was placed',
@ -232,12 +192,8 @@ export const ecomOrderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The date the cart was abandoned. REQUIRED ONLY IF INCLUDING EXTERNALCHECKOUTID.', description: 'The date the cart was abandoned. REQUIRED ONLY IF INCLUDING EXTERNALCHECKOUTID.',
@ -252,12 +208,8 @@ export const ecomOrderFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
default: {}, default: {},
@ -276,7 +228,8 @@ export const ecomOrderFields: INodeProperties[] = [
name: 'price', name: 'price',
type: 'number', type: 'number',
default: 0, default: 0,
description: 'The price of the product, in cents. (i.e. $456.78 => 45678). Must be greater than or equal to zero.', description:
'The price of the product, in cents. (i.e. $456.78 => 45678). Must be greater than or equal to zero.',
}, },
{ {
displayName: 'Product Quantity', displayName: 'Product Quantity',
@ -336,12 +289,8 @@ export const ecomOrderFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
default: {}, default: {},
@ -396,7 +345,6 @@ export const ecomOrderFields: INodeProperties[] = [
default: '', default: '',
description: 'The order number. This can be different than the externalid.', description: 'The order number. This can be different than the externalid.',
}, },
], ],
}, },
@ -410,12 +358,8 @@ export const ecomOrderFields: INodeProperties[] = [
default: 0, default: 0,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the e-commerce order', description: 'The ID of the e-commerce order',
@ -428,12 +372,8 @@ export const ecomOrderFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
default: {}, default: {},
@ -443,21 +383,24 @@ export const ecomOrderFields: INodeProperties[] = [
name: 'externalid', name: 'externalid',
type: 'string', type: 'string',
default: '', default: '',
description: 'The ID of the order in the external service. ONLY REQUIRED IF EXTERNALCHECKOUTID NOT INCLUDED.', description:
'The ID of the order in the external service. ONLY REQUIRED IF EXTERNALCHECKOUTID NOT INCLUDED.',
}, },
{ {
displayName: 'External Checkout ID', displayName: 'External Checkout ID',
name: 'externalcheckoutid', name: 'externalcheckoutid',
type: 'string', type: 'string',
default: '', default: '',
description: 'The ID of the cart in the external service. ONLY REQUIRED IF EXTERNALID IS NOT INCLUDED.', description:
'The ID of the cart in the external service. ONLY REQUIRED IF EXTERNALID IS NOT INCLUDED.',
}, },
{ {
displayName: 'Order Source', displayName: 'Order Source',
name: 'source', name: 'source',
type: 'number', type: 'number',
default: 0, default: 0,
description: 'The order source code (0 - will not trigger automations, 1 - will trigger automations)', description:
'The order source code (0 - will not trigger automations, 1 - will trigger automations)',
}, },
{ {
displayName: 'Customer Email', displayName: 'Customer Email',
@ -472,7 +415,8 @@ export const ecomOrderFields: INodeProperties[] = [
name: 'totalPrice', name: 'totalPrice',
type: 'number', type: 'number',
default: 0, default: 0,
description: 'The total price of the order in cents, including tax and shipping charges. (i.e. $456.78 => 45678). Must be greater than or equal to zero.', description:
'The total price of the order in cents, including tax and shipping charges. (i.e. $456.78 => 45678). Must be greater than or equal to zero.',
}, },
{ {
displayName: 'Order Currency', displayName: 'Order Currency',
@ -508,7 +452,8 @@ export const ecomOrderFields: INodeProperties[] = [
name: 'abandonedDate', name: 'abandonedDate',
type: 'dateTime', type: 'dateTime',
default: '', default: '',
description: 'The date the cart was abandoned. REQUIRED ONLY IF INCLUDING EXTERNALCHECKOUTID.', description:
'The date the cart was abandoned. REQUIRED ONLY IF INCLUDING EXTERNALCHECKOUTID.',
}, },
{ {
displayName: 'Shipping Amount', displayName: 'Shipping Amount',
@ -585,7 +530,8 @@ export const ecomOrderFields: INodeProperties[] = [
name: 'price', name: 'price',
type: 'number', type: 'number',
default: 0, default: 0,
description: 'The price of the product, in cents. (i.e. $456.78 => 45678). Must be greater than or equal to zero.', description:
'The price of the product, in cents. (i.e. $456.78 => 45678). Must be greater than or equal to zero.',
}, },
{ {
displayName: 'Product Quantity', displayName: 'Product Quantity',
@ -638,7 +584,6 @@ export const ecomOrderFields: INodeProperties[] = [
}, },
], ],
}, },
], ],
}, },
@ -652,12 +597,8 @@ export const ecomOrderFields: INodeProperties[] = [
default: 0, default: 0,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the e-commerce order', description: 'The ID of the e-commerce order',
@ -673,12 +614,8 @@ export const ecomOrderFields: INodeProperties[] = [
default: 0, default: 0,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['ecommerceOrder'],
],
resource: [
'ecommerceOrder',
],
}, },
}, },
description: 'The ID of the e-commerce order', description: 'The ID of the e-commerce order',
@ -688,5 +625,4 @@ export const ecomOrderFields: INodeProperties[] = [
// ecommerceOrder:getAll // ecommerceOrder:getAll
// ---------------------------------- // ----------------------------------
...activeCampaignDefaultGetAllProperties('ecommerceOrder', 'getAll'), ...activeCampaignDefaultGetAllProperties('ecommerceOrder', 'getAll'),
]; ];

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const ecomOrderProductsOperations: INodeProperties[] = [ export const ecomOrderProductsOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const ecomOrderProductsOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['ecommerceOrderProducts'],
'ecommerceOrderProducts',
],
}, },
}, },
options: [ options: [
@ -35,7 +29,7 @@ export const ecomOrderProductsOperations: INodeProperties[] = [
{ {
name: 'Get by Order ID', name: 'Get by Order ID',
value: 'getByOrderId', value: 'getByOrderId',
description: 'Get data of an order\'s products', description: "Get data of an order's products",
action: 'Get an e-commerce order product by order ID', action: 'Get an e-commerce order product by order ID',
}, },
], ],
@ -54,15 +48,11 @@ export const ecomOrderProductsFields: INodeProperties[] = [
default: 0, default: 0,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getByOrderId'],
'getByOrderId', resource: ['ecommerceOrderProducts'],
],
resource: [
'ecommerceOrderProducts',
],
}, },
}, },
description: 'The ID of the order whose products you\'d like returned', description: "The ID of the order whose products you'd like returned",
}, },
// ---------------------------------- // ----------------------------------
@ -75,15 +65,11 @@ export const ecomOrderProductsFields: INodeProperties[] = [
default: 0, default: 0,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getByProductId'],
'getByProductId', resource: ['ecommerceOrderProducts'],
],
resource: [
'ecommerceOrderProducts',
],
}, },
}, },
description: 'The ID of the product you\'d like returned', description: "The ID of the product you'd like returned",
}, },
// ---------------------------------- // ----------------------------------

View file

@ -1,10 +1,11 @@
import { import { IExecuteFunctions, IHookFunctions } from 'n8n-core';
IExecuteFunctions,
IHookFunctions,
} from 'n8n-core';
import { import {
IDataObject, ILoadOptionsFunctions, INodeProperties, NodeApiError, NodeOperationError, IDataObject,
ILoadOptionsFunctions,
INodeProperties,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { OptionsWithUri } from 'request'; import { OptionsWithUri } from 'request';
@ -15,7 +16,6 @@ export interface IProduct {
}; };
} }
/** /**
* Make an API request to ActiveCampaign * Make an API request to ActiveCampaign
* *
@ -25,7 +25,15 @@ export interface IProduct {
* @param {object} body * @param {object} body
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, dataKey?: string): Promise<any> { // tslint:disable-line:no-any export async function activeCampaignApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: IDataObject,
query?: IDataObject,
dataKey?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('activeCampaignApi'); const credentials = await this.getCredentials('activeCampaignApi');
if (query === undefined) { if (query === undefined) {
@ -33,8 +41,7 @@ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFu
} }
const options: OptionsWithUri = { const options: OptionsWithUri = {
headers: { headers: {},
},
method, method,
qs: query, qs: query,
uri: `${credentials.apiUrl}${endpoint}`, uri: `${credentials.apiUrl}${endpoint}`,
@ -46,7 +53,11 @@ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFu
} }
try { try {
const responseData = await this.helpers.requestWithAuthentication.call(this, 'activeCampaignApi',options); const responseData = await this.helpers.requestWithAuthentication.call(
this,
'activeCampaignApi',
options,
);
if (responseData.success === false) { if (responseData.success === false) {
throw new NodeApiError(this.getNode(), responseData); throw new NodeApiError(this.getNode(), responseData);
@ -57,14 +68,11 @@ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFu
} else { } else {
return responseData[dataKey] as IDataObject; return responseData[dataKey] as IDataObject;
} }
} catch (error) { } catch (error) {
throw new NodeApiError(this.getNode(), error); throw new NodeApiError(this.getNode(), error);
} }
} }
/** /**
* Make an API request to paginated ActiveCampaign endpoint * Make an API request to paginated ActiveCampaign endpoint
* and return all results * and return all results
@ -77,8 +85,15 @@ export async function activeCampaignApiRequest(this: IHookFunctions | IExecuteFu
* @param {IDataObject} [query] * @param {IDataObject} [query]
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function activeCampaignApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject, dataKey?: string): Promise<any> { // tslint:disable-line:no-any export async function activeCampaignApiRequestAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
body: IDataObject,
query?: IDataObject,
dataKey?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
if (query === undefined) { if (query === undefined) {
query = {}; query = {};
} }
@ -115,7 +130,10 @@ export async function activeCampaignApiRequestAllItems(this: IHookFunctions | IE
return returnData; return returnData;
} }
export function activeCampaignDefaultGetAllProperties(resource: string, operation: string): INodeProperties[] { export function activeCampaignDefaultGetAllProperties(
resource: string,
operation: string,
): INodeProperties[] {
return [ return [
{ {
displayName: 'Return All', displayName: 'Return All',
@ -123,12 +141,8 @@ export function activeCampaignDefaultGetAllProperties(resource: string, operatio
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: [operation],
operation, resource: [resource],
],
resource: [
resource,
],
}, },
}, },
default: false, default: false,
@ -140,15 +154,9 @@ export function activeCampaignDefaultGetAllProperties(resource: string, operatio
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: [operation],
operation, resource: [resource],
], returnAll: [false],
resource: [
resource,
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -164,12 +172,8 @@ export function activeCampaignDefaultGetAllProperties(resource: string, operatio
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: [operation],
operation, resource: [resource],
],
resource: [
resource,
],
}, },
}, },
default: true, default: true,

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const listOperations: INodeProperties[] = [ export const listOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const listOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list',
],
}, },
}, },
options: [ options: [

View file

@ -1,10 +1,6 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
import { import { activeCampaignDefaultGetAllProperties } from './GenericFunctions';
activeCampaignDefaultGetAllProperties,
} from './GenericFunctions';
export const tagOperations: INodeProperties[] = [ export const tagOperations: INodeProperties[] = [
{ {
@ -14,9 +10,7 @@ export const tagOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['tag'],
'tag',
],
}, },
}, },
options: [ options: [
@ -67,12 +61,8 @@ export const tagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
options: [ options: [
@ -97,12 +87,8 @@ export const tagFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
description: 'Name of the new tag', description: 'Name of the new tag',
@ -114,12 +100,8 @@ export const tagFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
default: {}, default: {},
@ -142,12 +124,8 @@ export const tagFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
default: 0, default: 0,
@ -162,12 +140,8 @@ export const tagFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
default: {}, default: {},
@ -197,12 +171,8 @@ export const tagFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
default: 0, default: 0,
@ -218,12 +188,8 @@ export const tagFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['tag'],
],
resource: [
'tag',
],
}, },
}, },
default: 0, default: 0,

View file

@ -144,7 +144,7 @@ export const allCurrencies = [
{ name: 'Tajikistani Somoni', value: 'tjs' }, { name: 'Tajikistani Somoni', value: 'tjs' },
{ name: 'Turkmenistani Manat', value: 'tmt' }, { name: 'Turkmenistani Manat', value: 'tmt' },
{ name: 'Tunisian Dinar', value: 'tnd' }, { name: 'Tunisian Dinar', value: 'tnd' },
{ name: 'Tongan Pa\'anga', value: 'top' }, { name: "Tongan Pa'anga", value: 'top' },
{ name: 'Turkish Lira', value: 'try' }, { name: 'Turkish Lira', value: 'try' },
{ name: 'Trinidad and Tobago Dollar', value: 'ttd' }, { name: 'Trinidad and Tobago Dollar', value: 'ttd' },
{ name: 'New Taiwan Dollar', value: 'twd' }, { name: 'New Taiwan Dollar', value: 'twd' },

View file

@ -1,18 +1,8 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
IDataObject,
INodeType,
INodeTypeDescription,
IWebhookResponseData,
} from 'n8n-workflow';
import { import { acuitySchedulingApiRequest } from './GenericFunctions';
acuitySchedulingApiRequest,
} from './GenericFunctions';
export class AcuitySchedulingTrigger implements INodeType { export class AcuitySchedulingTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -34,9 +24,7 @@ export class AcuitySchedulingTrigger implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
authentication: [ authentication: ['apiKey'],
'apiKey',
],
}, },
}, },
}, },
@ -45,9 +33,7 @@ export class AcuitySchedulingTrigger implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
authentication: [ authentication: ['oAuth2'],
'oAuth2',
],
}, },
}, },
}, },
@ -117,7 +103,8 @@ export class AcuitySchedulingTrigger implements INodeType {
type: 'boolean', type: 'boolean',
default: true, default: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default does the webhook-data only contain the ID of the object. If this option gets activated, it will resolve the data automatically.', description:
'By default does the webhook-data only contain the ID of the object. If this option gets activated, it will resolve the data automatically.',
}, },
], ],
}; };
@ -158,7 +145,7 @@ export class AcuitySchedulingTrigger implements INodeType {
const endpoint = `/webhooks/${webhookData.webhookId}`; const endpoint = `/webhooks/${webhookData.webhookId}`;
try { try {
await acuitySchedulingApiRequest.call(this, 'DELETE', endpoint); await acuitySchedulingApiRequest.call(this, 'DELETE', endpoint);
} catch(error) { } catch (error) {
return false; return false;
} }
delete webhookData.webhookId; delete webhookData.webhookId;
@ -175,9 +162,7 @@ export class AcuitySchedulingTrigger implements INodeType {
if (resolveData === false) { if (resolveData === false) {
// Return the data as it got received // Return the data as it got received
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(req.body)],
this.helpers.returnJsonArray(req.body),
],
}; };
} }
@ -188,11 +173,7 @@ export class AcuitySchedulingTrigger implements INodeType {
const responseData = await acuitySchedulingApiRequest.call(this, 'GET', endpoint, {}); const responseData = await acuitySchedulingApiRequest.call(this, 'GET', endpoint, {});
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(responseData)],
this.helpers.returnJsonArray(responseData),
],
}; };
} }
} }

View file

@ -6,9 +6,24 @@ import {
ILoadOptionsFunctions, ILoadOptionsFunctions,
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { IDataObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
export async function acuitySchedulingApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function acuitySchedulingApiRequest(
this:
| IHookFunctions
| IExecuteFunctions
| IExecuteSingleFunctions
| ILoadOptionsFunctions
| IWebhookFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter('authentication', 0); const authenticationMethod = this.getNodeParameter('authentication', 0);
const options: OptionsWithUri = { const options: OptionsWithUri = {
@ -19,7 +34,7 @@ export async function acuitySchedulingApiRequest(this: IHookFunctions | IExecute
method, method,
qs, qs,
body, body,
uri: uri ||`https://acuityscheduling.com/api/v1${resource}`, uri: uri || `https://acuityscheduling.com/api/v1${resource}`,
json: true, json: true,
}; };
@ -35,8 +50,13 @@ export async function acuitySchedulingApiRequest(this: IHookFunctions | IExecute
return await this.helpers.request!(options); return await this.helpers.request!(options);
} else { } else {
delete options.auth; delete options.auth;
//@ts-ignore return await this.helpers.requestOAuth2!.call(
return await this.helpers.requestOAuth2!.call(this, 'acuitySchedulingOAuth2Api', options, true); this,
'acuitySchedulingOAuth2Api',
options,
//@ts-ignore
true,
);
} }
} catch (error) { } catch (error) {
throw new NodeApiError(this.getNode(), error); throw new NodeApiError(this.getNode(), error);

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -11,38 +9,19 @@ import {
INodeTypeDescription, INodeTypeDescription,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { affinityApiRequest, affinityApiRequestAllItems } from './GenericFunctions';
affinityApiRequest,
affinityApiRequestAllItems,
} from './GenericFunctions';
import { import { organizationFields, organizationOperations } from './OrganizationDescription';
organizationFields,
organizationOperations,
} from './OrganizationDescription';
import { import { personFields, personOperations } from './PersonDescription';
personFields,
personOperations,
} from './PersonDescription';
import { import { listFields, listOperations } from './ListDescription';
listFields,
listOperations,
} from './ListDescription';
import { import { listEntryFields, listEntryOperations } from './ListEntryDescription';
listEntryFields,
listEntryOperations,
} from './ListEntryDescription';
import { import { IOrganization } from './OrganizationInterface';
IOrganization,
} from './OrganizationInterface';
import { import { IPerson } from './PersonInterface';
IPerson,
} from './PersonInterface';
export class Affinity implements INodeType { export class Affinity implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -108,7 +87,13 @@ export class Affinity implements INodeType {
// select them easily // select them easily
async getOrganizations(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getOrganizations(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const organizations = await affinityApiRequestAllItems.call(this, 'organizations', 'GET', '/organizations', {}); const organizations = await affinityApiRequestAllItems.call(
this,
'organizations',
'GET',
'/organizations',
{},
);
for (const organization of organizations) { for (const organization of organizations) {
const organizationName = organization.name; const organizationName = organization.name;
const organizationId = organization.id; const organizationId = organization.id;
@ -123,7 +108,13 @@ export class Affinity implements INodeType {
// select them easily // select them easily
async getPersons(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getPersons(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const persons = await affinityApiRequestAllItems.call(this, 'persons', 'GET', '/persons', {}); const persons = await affinityApiRequestAllItems.call(
this,
'persons',
'GET',
'/persons',
{},
);
for (const person of persons) { for (const person of persons) {
let personName = `${person.first_name} ${person.last_name}`; let personName = `${person.first_name} ${person.last_name}`;
if (person.primary_email !== null) { if (person.primary_email !== null) {
@ -189,23 +180,47 @@ export class Affinity implements INodeType {
entity_id: parseInt(entityId, 10), entity_id: parseInt(entityId, 10),
}; };
Object.assign(body, additionalFields); Object.assign(body, additionalFields);
responseData = await affinityApiRequest.call(this, 'POST', `/lists/${listId}/list-entries`, body); responseData = await affinityApiRequest.call(
this,
'POST',
`/lists/${listId}/list-entries`,
body,
);
} }
//https://api-docs.affinity.co/#get-a-specific-list-entry //https://api-docs.affinity.co/#get-a-specific-list-entry
if (operation === 'get') { if (operation === 'get') {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
const listEntryId = this.getNodeParameter('listEntryId', i) as string; const listEntryId = this.getNodeParameter('listEntryId', i) as string;
responseData = await affinityApiRequest.call(this, 'GET', `/lists/${listId}/list-entries/${listEntryId}`, {}, qs); responseData = await affinityApiRequest.call(
this,
'GET',
`/lists/${listId}/list-entries/${listEntryId}`,
{},
qs,
);
} }
//https://api-docs.affinity.co/#get-all-list-entries //https://api-docs.affinity.co/#get-all-list-entries
if (operation === 'getAll') { if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', i) as boolean; const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
if (returnAll === true) { if (returnAll === true) {
responseData = await affinityApiRequestAllItems.call(this, 'list_entries', 'GET', `/lists/${listId}/list-entries`, {}, qs); responseData = await affinityApiRequestAllItems.call(
this,
'list_entries',
'GET',
`/lists/${listId}/list-entries`,
{},
qs,
);
} else { } else {
qs.page_size = this.getNodeParameter('limit', i) as number; qs.page_size = this.getNodeParameter('limit', i) as number;
responseData = await affinityApiRequest.call(this, 'GET', `/lists/${listId}/list-entries`, {}, qs); responseData = await affinityApiRequest.call(
this,
'GET',
`/lists/${listId}/list-entries`,
{},
qs,
);
responseData = responseData.list_entries; responseData = responseData.list_entries;
} }
} }
@ -213,7 +228,13 @@ export class Affinity implements INodeType {
if (operation === 'delete') { if (operation === 'delete') {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
const listEntryId = this.getNodeParameter('listEntryId', i) as string; const listEntryId = this.getNodeParameter('listEntryId', i) as string;
responseData = await affinityApiRequest.call(this, 'DELETE', `/lists/${listId}/list-entries/${listEntryId}`, {}, qs); responseData = await affinityApiRequest.call(
this,
'DELETE',
`/lists/${listId}/list-entries/${listEntryId}`,
{},
qs,
);
} }
} }
if (resource === 'person') { if (resource === 'person') {
@ -259,7 +280,13 @@ export class Affinity implements INodeType {
if (options.withInteractionDates) { if (options.withInteractionDates) {
qs.with_interaction_dates = options.withInteractionDates as boolean; 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 //https://api-docs.affinity.co/#search-for-persons
if (operation === 'getAll') { if (operation === 'getAll') {
@ -272,7 +299,14 @@ export class Affinity implements INodeType {
qs.with_interaction_dates = options.withInteractionDates as boolean; qs.with_interaction_dates = options.withInteractionDates as boolean;
} }
if (returnAll === true) { if (returnAll === true) {
responseData = await affinityApiRequestAllItems.call(this, 'persons', 'GET', '/persons', {}, qs); responseData = await affinityApiRequestAllItems.call(
this,
'persons',
'GET',
'/persons',
{},
qs,
);
} else { } else {
qs.page_size = this.getNodeParameter('limit', i) as number; qs.page_size = this.getNodeParameter('limit', i) as number;
responseData = await affinityApiRequest.call(this, 'GET', '/persons', {}, qs); responseData = await affinityApiRequest.call(this, 'GET', '/persons', {}, qs);
@ -282,7 +316,13 @@ export class Affinity implements INodeType {
//https://api-docs.affinity.co/#delete-a-person //https://api-docs.affinity.co/#delete-a-person
if (operation === 'delete') { if (operation === 'delete') {
const personId = this.getNodeParameter('personId', i) as number; const personId = this.getNodeParameter('personId', i) as number;
responseData = await affinityApiRequest.call(this, 'DELETE', `/persons/${personId}`, {}, qs); responseData = await affinityApiRequest.call(
this,
'DELETE',
`/persons/${personId}`,
{},
qs,
);
} }
} }
if (resource === 'organization') { if (resource === 'organization') {
@ -314,7 +354,12 @@ export class Affinity implements INodeType {
if (updateFields.persons) { if (updateFields.persons) {
body.person_ids = updateFields.persons as number[]; body.person_ids = updateFields.persons as number[];
} }
responseData = await affinityApiRequest.call(this, 'PUT', `/organizations/${organizationId}`, body); responseData = await affinityApiRequest.call(
this,
'PUT',
`/organizations/${organizationId}`,
body,
);
} }
//https://api-docs.affinity.co/#get-a-specific-organization //https://api-docs.affinity.co/#get-a-specific-organization
if (operation === 'get') { if (operation === 'get') {
@ -323,7 +368,13 @@ export class Affinity implements INodeType {
if (options.withInteractionDates) { if (options.withInteractionDates) {
qs.with_interaction_dates = options.withInteractionDates as boolean; 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 //https://api-docs.affinity.co/#search-for-organizations
if (operation === 'getAll') { if (operation === 'getAll') {
@ -336,7 +387,14 @@ export class Affinity implements INodeType {
qs.with_interaction_dates = options.withInteractionDates as boolean; qs.with_interaction_dates = options.withInteractionDates as boolean;
} }
if (returnAll === true) { if (returnAll === true) {
responseData = await affinityApiRequestAllItems.call(this, 'organizations', 'GET', '/organizations', {}, qs); responseData = await affinityApiRequestAllItems.call(
this,
'organizations',
'GET',
'/organizations',
{},
qs,
);
} else { } else {
qs.page_size = this.getNodeParameter('limit', i) as number; qs.page_size = this.getNodeParameter('limit', i) as number;
responseData = await affinityApiRequest.call(this, 'GET', '/organizations', {}, qs); responseData = await affinityApiRequest.call(this, 'GET', '/organizations', {}, qs);
@ -346,7 +404,13 @@ export class Affinity implements INodeType {
//https://api-docs.affinity.co/#delete-an-organization //https://api-docs.affinity.co/#delete-an-organization
if (operation === 'delete') { if (operation === 'delete') {
const organizationId = this.getNodeParameter('organizationId', i) as number; const organizationId = this.getNodeParameter('organizationId', i) as number;
responseData = await affinityApiRequest.call(this, 'DELETE', `/organizations/${organizationId}`, {}, qs); responseData = await affinityApiRequest.call(
this,
'DELETE',
`/organizations/${organizationId}`,
{},
qs,
);
} }
} }
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {

View file

@ -1,7 +1,4 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -11,11 +8,7 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { affinityApiRequest, eventsExist, mapResource } from './GenericFunctions';
affinityApiRequest,
eventsExist,
mapResource,
} from './GenericFunctions';
export class AffinityTrigger implements INodeType { export class AffinityTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -157,7 +150,6 @@ export class AffinityTrigger implements INodeType {
description: 'Webhook events that will be enabled for that endpoint', description: 'Webhook events that will be enabled for that endpoint',
}, },
], ],
}; };
// @ts-ignore (because of request) // @ts-ignore (because of request)
@ -188,7 +180,10 @@ export class AffinityTrigger implements INodeType {
const webhookUrl = this.getNodeWebhookUrl('default') as string; const webhookUrl = this.getNodeWebhookUrl('default') as string;
if (webhookUrl.includes('%20')) { if (webhookUrl.includes('%20')) {
throw new NodeOperationError(this.getNode(), 'The name of the Affinity Trigger Node is not allowed to contain any spaces!'); throw new NodeOperationError(
this.getNode(),
'The name of the Affinity Trigger Node is not allowed to contain any spaces!',
);
} }
const events = this.getNodeParameter('events') as string[]; const events = this.getNodeParameter('events') as string[];
@ -214,7 +209,6 @@ export class AffinityTrigger implements INodeType {
async delete(this: IHookFunctions): Promise<boolean> { async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node'); const webhookData = this.getWorkflowStaticData('node');
if (webhookData.webhookId !== undefined) { if (webhookData.webhookId !== undefined) {
const endpoint = `/webhook/${webhookData.webhookId}`; const endpoint = `/webhook/${webhookData.webhookId}`;
const responseData = await affinityApiRequest.call(this, 'DELETE', endpoint); const responseData = await affinityApiRequest.call(this, 'DELETE', endpoint);
@ -249,9 +243,7 @@ export class AffinityTrigger implements INodeType {
} }
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(responseData)],
this.helpers.returnJsonArray(responseData),
],
}; };
} }
} }

View file

@ -1,12 +1,6 @@
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { BINARY_ENCODING, IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
BINARY_ENCODING,
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -16,8 +10,17 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } 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 export async function affinityApiRequest(
this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('affinityApi'); const credentials = await this.getCredentials('affinityApi');
const apiKey = `:${credentials.apiKey}`; const apiKey = `:${credentials.apiKey}`;
@ -49,8 +52,16 @@ export async function affinityApiRequest(this: IExecuteFunctions | IWebhookFunct
} }
} }
export async function affinityApiRequestAllItems(this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions, propertyName: string, method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function affinityApiRequestAllItems(
this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions,
propertyName: string,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -62,10 +73,7 @@ export async function affinityApiRequestAllItems(this: IHookFunctions | ILoadOpt
// @ts-ignore // @ts-ignore
query.page_token = responseData.page_token; query.page_token = responseData.page_token;
returnData.push.apply(returnData, responseData[propertyName]); returnData.push.apply(returnData, responseData[propertyName]);
} while ( } while (responseData.page_token !== undefined && responseData.page_token !== null);
responseData.page_token !== undefined &&
responseData.page_token !== null
);
return returnData; return returnData;
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const listOperations: INodeProperties[] = [ export const listOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const listOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list',
],
}, },
}, },
options: [ options: [
@ -45,12 +41,8 @@ export const listFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
description: 'The unique ID of the list object to be retrieved', description: 'The unique ID of the list object to be retrieved',
@ -64,12 +56,8 @@ export const listFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -81,15 +69,9 @@ export const listFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const listEntryOperations: INodeProperties[] = [ export const listEntryOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const listEntryOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry',
],
}, },
}, },
options: [ options: [
@ -46,7 +42,6 @@ export const listEntryOperations: INodeProperties[] = [
]; ];
export const listEntryFields: INodeProperties[] = [ export const listEntryFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* listEntry:create */ /* listEntry:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -61,15 +56,12 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The unique ID of the list whose list entries are to be retrieved. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The unique ID of the list whose list entries are to be retrieved. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Entity ID', displayName: 'Entity ID',
@ -79,15 +71,12 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The unique ID of the entity (person, organization, or opportunity) to add to this list', description:
'The unique ID of the entity (person, organization, or opportunity) to add to this list',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -97,12 +86,8 @@ export const listEntryFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: [ options: [
@ -111,7 +96,8 @@ export const listEntryFields: INodeProperties[] = [
name: 'creator_id', name: 'creator_id',
type: 'string', type: 'string',
default: '', default: '',
description: 'The ID of a Person resource who should be recorded as adding the entry to the list. Must be a person who can access Affinity. If not provided the creator defaults to the owner of the API key.', description:
'The ID of a Person resource who should be recorded as adding the entry to the list. Must be a person who can access Affinity. If not provided the creator defaults to the owner of the API key.',
}, },
], ],
}, },
@ -129,15 +115,12 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
description: 'The unique ID of the list that contains the specified list_entry_id. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The unique ID of the list that contains the specified list_entry_id. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'List Entry ID', displayName: 'List Entry ID',
@ -147,12 +130,8 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
description: 'The unique ID of the list entry object to be retrieved', description: 'The unique ID of the list entry object to be retrieved',
@ -169,16 +148,13 @@ export const listEntryFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: '', default: '',
description: 'The unique ID of the list whose list entries are to be retrieved. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The unique ID of the list whose list entries are to be retrieved. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Return All', displayName: 'Return All',
@ -186,12 +162,8 @@ export const listEntryFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -203,15 +175,9 @@ export const listEntryFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -235,15 +201,12 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
description: 'The unique ID of the list that contains the specified list_entry_id. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The unique ID of the list that contains the specified list_entry_id. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'List Entry ID', displayName: 'List Entry ID',
@ -253,12 +216,8 @@ export const listEntryFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['listEntry'],
'listEntry', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
description: 'The unique ID of the list entry object to be deleted', description: 'The unique ID of the list entry object to be deleted',

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const organizationOperations: INodeProperties[] = [ export const organizationOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const organizationOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization',
],
}, },
}, },
options: [ options: [
@ -52,7 +48,6 @@ export const organizationOperations: INodeProperties[] = [
]; ];
export const organizationFields: INodeProperties[] = [ export const organizationFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* organization:create */ /* organization:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -64,12 +59,8 @@ export const organizationFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The name of the organization', description: 'The name of the organization',
@ -82,12 +73,8 @@ export const organizationFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The domain name of the organization', description: 'The domain name of the organization',
@ -100,12 +87,8 @@ export const organizationFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: [ options: [
@ -117,7 +100,8 @@ export const organizationFields: INodeProperties[] = [
loadOptionsMethod: 'getPersons', loadOptionsMethod: 'getPersons',
}, },
default: [], default: [],
description: 'Persons that the new organization will be associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Persons that the new organization will be associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },
@ -132,12 +116,8 @@ export const organizationFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
description: 'Unique identifier for the organization', description: 'Unique identifier for the organization',
@ -150,12 +130,8 @@ export const organizationFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
options: [ options: [
@ -181,7 +157,8 @@ export const organizationFields: INodeProperties[] = [
loadOptionsMethod: 'getPersons', loadOptionsMethod: 'getPersons',
}, },
default: [], default: [],
description: 'Persons that the new organization will be associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Persons that the new organization will be associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },
@ -196,12 +173,8 @@ export const organizationFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
description: 'Unique identifier for the organization', description: 'Unique identifier for the organization',
@ -214,12 +187,8 @@ export const organizationFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
options: [ options: [
@ -241,12 +210,8 @@ export const organizationFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -258,15 +223,9 @@ export const organizationFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -284,12 +243,8 @@ export const organizationFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -298,7 +253,8 @@ export const organizationFields: INodeProperties[] = [
name: 'term', name: 'term',
type: 'string', type: 'string',
default: '', default: '',
description: 'A string used to search all the organizations in your teams address book. This could be an email address, a first name or a last name.', description:
'A string used to search all the organizations in your teams address book. This could be an email address, a first name or a last name.',
}, },
{ {
displayName: 'With Interaction Dates', displayName: 'With Interaction Dates',
@ -320,12 +276,8 @@ export const organizationFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['organization'],
'organization', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
description: 'Unique identifier for the organization', description: 'Unique identifier for the organization',

View file

@ -1,4 +1,3 @@
export interface IOrganization { export interface IOrganization {
name?: string; name?: string;
domain?: string; domain?: string;

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const personOperations: INodeProperties[] = [ export const personOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const personOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person',
],
}, },
}, },
options: [ options: [
@ -52,7 +48,6 @@ export const personOperations: INodeProperties[] = [
]; ];
export const personFields: INodeProperties[] = [ export const personFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* person:create */ /* person:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -64,12 +59,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The first name of the person', description: 'The first name of the person',
@ -82,12 +73,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The last name of the person', description: 'The last name of the person',
@ -100,12 +87,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
options: [ options: [
@ -117,7 +100,8 @@ export const personFields: INodeProperties[] = [
loadOptionsMethod: 'getOrganizations', loadOptionsMethod: 'getOrganizations',
}, },
default: [], default: [],
description: 'Organizations that the person is associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Organizations that the person is associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },
@ -132,12 +116,8 @@ export const personFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
placeholder: 'info@example.com', placeholder: 'info@example.com',
@ -154,12 +134,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
description: 'Unique identifier for the person', description: 'Unique identifier for the person',
@ -172,12 +148,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
options: [ options: [
@ -203,7 +175,8 @@ export const personFields: INodeProperties[] = [
loadOptionsMethod: 'getOrganizations', loadOptionsMethod: 'getOrganizations',
}, },
default: [], default: [],
description: 'Organizations that the person is associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Organizations that the person is associated with. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },
@ -218,12 +191,8 @@ export const personFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
placeholder: 'info@example.com', placeholder: 'info@example.com',
@ -240,12 +209,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
description: 'Unique identifier for the person', description: 'Unique identifier for the person',
@ -258,12 +223,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
options: [ options: [
@ -285,12 +246,8 @@ export const personFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -302,15 +259,9 @@ export const personFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -328,12 +279,8 @@ export const personFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -342,7 +289,8 @@ export const personFields: INodeProperties[] = [
name: 'term', name: 'term',
type: 'string', type: 'string',
default: '', default: '',
description: 'A string used to search all the persons in your teams address book. This could be an email address, a first name or a last name.', description:
'A string used to search all the persons in your teams address book. This could be an email address, a first name or a last name.',
}, },
{ {
displayName: 'With Interaction Dates', displayName: 'With Interaction Dates',
@ -364,12 +312,8 @@ export const personFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['person'],
'person', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
description: 'Unique identifier for the person', description: 'Unique identifier for the person',

View file

@ -1,4 +1,3 @@
export interface IPerson { export interface IPerson {
first_name?: string; first_name?: string;
last_name?: string; last_name?: string;

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -10,42 +8,26 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { contactFields, contactOperations } from './ContactDescription';
contactFields,
contactOperations import { companyFields, companyOperations } from './CompanyDescription';
} from './ContactDescription';
import { dealFields, dealOperations } from './DealDescription';
import { IContact, IContactUpdate } from './ContactInterface';
import { import {
companyFields, agileCrmApiRequest,
companyOperations agileCrmApiRequestAllItems,
} from './CompanyDescription';
import {
dealFields,
dealOperations
} from './DealDescription';
import {
IContact,
IContactUpdate,
} from './ContactInterface';
import {
agileCrmApiRequest, agileCrmApiRequestAllItems,
agileCrmApiRequestUpdate, agileCrmApiRequestUpdate,
getFilterRules, getFilterRules,
simplifyResponse, simplifyResponse,
validateJSON, validateJSON,
} from './GenericFunctions'; } from './GenericFunctions';
import { import { IDeal } from './DealInterface';
IDeal,
} from './DealInterface';
import { import { IFilter, ISearchConditions } from './FilterInterface';
IFilter,
ISearchConditions,
} from './FilterInterface';
export class AgileCrm implements INodeType { export class AgileCrm implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -104,11 +86,9 @@ export class AgileCrm implements INodeType {
...dealOperations, ...dealOperations,
...dealFields, ...dealFields,
], ],
}; };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData(); const items = this.getInputData();
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -116,7 +96,6 @@ export class AgileCrm implements INodeType {
const operation = this.getNodeParameter('operation', 0) as string; const operation = this.getNodeParameter('operation', 0) as string;
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
if (resource === 'contact' || resource === 'company') { if (resource === 'contact' || resource === 'company') {
const idGetter = resource === 'contact' ? 'contactId' : 'companyId'; const idGetter = resource === 'contact' ? 'contactId' : 'companyId';
@ -125,18 +104,19 @@ export class AgileCrm implements INodeType {
const endpoint = `api/contacts/${contactId}`; const endpoint = `api/contacts/${contactId}`;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {});
} else if (operation === 'delete') { } else if (operation === 'delete') {
const contactId = this.getNodeParameter(idGetter, i) as string; const contactId = this.getNodeParameter(idGetter, i) as string;
const endpoint = `api/contacts/${contactId}`; const endpoint = `api/contacts/${contactId}`;
responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {}); responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {});
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
const simple = this.getNodeParameter('simple', 0) as boolean; const simple = this.getNodeParameter('simple', 0) as boolean;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean; const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const filterType = this.getNodeParameter('filterType', i) as string; const filterType = this.getNodeParameter('filterType', i) as string;
const sort = this.getNodeParameter('options.sort.sort', i, {}) as { direction: string, field: string }; const sort = this.getNodeParameter('options.sort.sort', i, {}) as {
direction: string;
field: string;
};
const body: IDataObject = {}; const body: IDataObject = {};
const filterJson: IFilter = {}; const filterJson: IFilter = {};
@ -149,21 +129,31 @@ export class AgileCrm implements INodeType {
filterJson.contact_type = contactType; filterJson.contact_type = contactType;
if (filterType === 'manual') { if (filterType === 'manual') {
const conditions = this.getNodeParameter('filters.conditions', i, []) as ISearchConditions[]; const conditions = this.getNodeParameter(
'filters.conditions',
i,
[],
) as ISearchConditions[];
const matchType = this.getNodeParameter('matchType', i) as string; const matchType = this.getNodeParameter('matchType', i) as string;
let rules; let rules;
if (conditions.length !== 0) { if (conditions.length !== 0) {
rules = getFilterRules(conditions, matchType); rules = getFilterRules(conditions, matchType);
Object.assign(filterJson, rules); Object.assign(filterJson, rules);
} else { } else {
throw new NodeOperationError(this.getNode(), 'At least one condition must be added.', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'At least one condition must be added.',
{ itemIndex: i },
);
} }
} else if (filterType === 'json') { } else if (filterType === 'json') {
const filterJsonRules = this.getNodeParameter('filterJson', i) as string; const filterJsonRules = this.getNodeParameter('filterJson', i) as string;
if (validateJSON(filterJsonRules) !== undefined) { if (validateJSON(filterJsonRules) !== undefined) {
Object.assign(filterJson, JSON.parse(filterJsonRules) as IFilter); Object.assign(filterJson, JSON.parse(filterJsonRules) as IFilter);
} else { } else {
throw new NodeOperationError(this.getNode(), 'Filter (JSON) must be a valid json', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'Filter (JSON) must be a valid json', {
itemIndex: i,
});
} }
} }
body.filterJson = JSON.stringify(filterJson); body.filterJson = JSON.stringify(filterJson);
@ -178,16 +168,31 @@ export class AgileCrm implements INodeType {
if (returnAll) { if (returnAll) {
body.page_size = 100; body.page_size = 100;
responseData = await agileCrmApiRequestAllItems.call(this, 'POST', `api/filters/filter/dynamic-filter`, body, undefined, undefined, true); responseData = await agileCrmApiRequestAllItems.call(
this,
'POST',
`api/filters/filter/dynamic-filter`,
body,
undefined,
undefined,
true,
);
} else { } else {
body.page_size = this.getNodeParameter('limit', 0) as number; body.page_size = this.getNodeParameter('limit', 0) as number;
responseData = await agileCrmApiRequest.call(this, 'POST', `api/filters/filter/dynamic-filter`, body, undefined, undefined, true); responseData = await agileCrmApiRequest.call(
this,
'POST',
`api/filters/filter/dynamic-filter`,
body,
undefined,
undefined,
true,
);
} }
if (simple) { if (simple) {
responseData = simplifyResponse(responseData); responseData = simplifyResponse(responseData);
} }
} else if (operation === 'create') { } else if (operation === 'create') {
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
const body: IContact = {}; const body: IContact = {};
@ -197,18 +202,17 @@ export class AgileCrm implements INodeType {
const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string;
if (additionalFieldsJson !== '') { if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) { if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson)); Object.assign(body, JSON.parse(additionalFieldsJson));
} else { } else {
throw new NodeOperationError(this.getNode(), 'Additional fields must be a valid JSON', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'Additional fields must be a valid JSON',
{ itemIndex: i },
);
} }
} }
} else { } else {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
// if company, add 'company' as type. default is person // if company, add 'company' as type. default is person
@ -254,7 +258,7 @@ export class AgileCrm implements INodeType {
} }
if (additionalFields.emailOptions) { if (additionalFields.emailOptions) {
//@ts-ignore //@ts-ignore
additionalFields.emailOptions.emailProperties.map(property => { additionalFields.emailOptions.emailProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -265,7 +269,7 @@ export class AgileCrm implements INodeType {
} }
if (additionalFields.addressOptions) { if (additionalFields.addressOptions) {
//@ts-ignore //@ts-ignore
additionalFields.addressOptions.addressProperties.map(property => { additionalFields.addressOptions.addressProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -277,7 +281,7 @@ export class AgileCrm implements INodeType {
if (additionalFields.phoneOptions) { if (additionalFields.phoneOptions) {
//@ts-ignore //@ts-ignore
additionalFields.phoneOptions.phoneProperties.map(property => { additionalFields.phoneOptions.phoneProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -310,12 +314,11 @@ export class AgileCrm implements INodeType {
value: additionalFields.phone as string, value: additionalFields.phone as string,
} as IDataObject); } as IDataObject);
} }
} }
if (additionalFields.websiteOptions) { if (additionalFields.websiteOptions) {
//@ts-ignore //@ts-ignore
additionalFields.websiteOptions.websiteProperties.map(property => { additionalFields.websiteOptions.websiteProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -327,7 +330,7 @@ export class AgileCrm implements INodeType {
if (additionalFields.customProperties) { if (additionalFields.customProperties) {
//@ts-ignore //@ts-ignore
additionalFields.customProperties.customProperty.map(property => { additionalFields.customProperties.customProperty.map((property) => {
properties.push({ properties.push({
type: 'CUSTOM', type: 'CUSTOM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -337,11 +340,9 @@ export class AgileCrm implements INodeType {
}); });
} }
body.properties = properties; body.properties = properties;
} }
const endpoint = 'api/contacts'; const endpoint = 'api/contacts';
responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body); responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body);
} else if (operation === 'update') { } else if (operation === 'update') {
const contactId = this.getNodeParameter(idGetter, i) as string; const contactId = this.getNodeParameter(idGetter, i) as string;
const contactUpdatePayload: IContactUpdate = { id: contactId }; const contactUpdatePayload: IContactUpdate = { id: contactId };
@ -353,13 +354,14 @@ export class AgileCrm implements INodeType {
const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string;
if (additionalFieldsJson !== '') { if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) { if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson)); Object.assign(body, JSON.parse(additionalFieldsJson));
} else { } else {
throw new NodeOperationError(this.getNode(), 'Additional fields must be a valid JSON', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'Additional fields must be a valid JSON',
{ itemIndex: i },
);
} }
} }
} else { } else {
@ -374,7 +376,6 @@ export class AgileCrm implements INodeType {
// Contact specific properties // Contact specific properties
if (resource === 'contact') { if (resource === 'contact') {
if (additionalFields.leadScore) { if (additionalFields.leadScore) {
body.lead_score = additionalFields.leadScore as string; body.lead_score = additionalFields.leadScore as string;
} }
@ -409,7 +410,7 @@ export class AgileCrm implements INodeType {
} }
if (additionalFields.emailOptions) { if (additionalFields.emailOptions) {
//@ts-ignore //@ts-ignore
additionalFields.emailOptions.emailProperties.map(property => { additionalFields.emailOptions.emailProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -420,7 +421,7 @@ export class AgileCrm implements INodeType {
} }
if (additionalFields.addressOptions) { if (additionalFields.addressOptions) {
//@ts-ignore //@ts-ignore
additionalFields.addressOptions.addressProperties.map(property => { additionalFields.addressOptions.addressProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -432,7 +433,7 @@ export class AgileCrm implements INodeType {
if (additionalFields.phoneOptions) { if (additionalFields.phoneOptions) {
//@ts-ignore //@ts-ignore
additionalFields.phoneOptions.phoneProperties.map(property => { additionalFields.phoneOptions.phoneProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -465,12 +466,11 @@ export class AgileCrm implements INodeType {
value: additionalFields.phone as string, value: additionalFields.phone as string,
} as IDataObject); } as IDataObject);
} }
} }
if (additionalFields.websiteOptions) { if (additionalFields.websiteOptions) {
//@ts-ignore //@ts-ignore
additionalFields.websiteOptions.websiteProperties.map(property => { additionalFields.websiteOptions.websiteProperties.map((property) => {
properties.push({ properties.push({
type: 'SYSTEM', type: 'SYSTEM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -481,7 +481,7 @@ export class AgileCrm implements INodeType {
} }
if (additionalFields.customProperties) { if (additionalFields.customProperties) {
//@ts-ignore //@ts-ignore
additionalFields.customProperties.customProperty.map(property => { additionalFields.customProperties.customProperty.map((property) => {
properties.push({ properties.push({
type: 'CUSTOM', type: 'CUSTOM',
subtype: property.subtype as string, subtype: property.subtype as string,
@ -496,35 +496,33 @@ export class AgileCrm implements INodeType {
Object.assign(contactUpdatePayload, body); Object.assign(contactUpdatePayload, body);
responseData = await agileCrmApiRequestUpdate.call(this, 'PUT', '', contactUpdatePayload); responseData = await agileCrmApiRequestUpdate.call(this, 'PUT', '', contactUpdatePayload);
} }
} else if (resource === 'deal') { } else if (resource === 'deal') {
if (operation === 'get') { if (operation === 'get') {
const dealId = this.getNodeParameter('dealId', i) as string; const dealId = this.getNodeParameter('dealId', i) as string;
const endpoint = `api/opportunity/${dealId}`; const endpoint = `api/opportunity/${dealId}`;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {}); responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, {});
} else if (operation === 'delete') { } else if (operation === 'delete') {
const contactId = this.getNodeParameter('dealId', i) as string; const contactId = this.getNodeParameter('dealId', i) as string;
const endpoint = `api/opportunity/${contactId}`; const endpoint = `api/opportunity/${contactId}`;
responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {}); responseData = await agileCrmApiRequest.call(this, 'DELETE', endpoint, {});
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean; const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const endpoint = 'api/opportunity'; const endpoint = 'api/opportunity';
if (returnAll) { if (returnAll) {
const limit = 100; const limit = 100;
responseData = await agileCrmApiRequestAllItems.call(this, 'GET', endpoint, undefined, { page_size: limit }); responseData = await agileCrmApiRequestAllItems.call(this, 'GET', endpoint, undefined, {
page_size: limit,
});
} else { } else {
const limit = this.getNodeParameter('limit', 0) as number; const limit = this.getNodeParameter('limit', 0) as number;
responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, undefined, { page_size: limit }); responseData = await agileCrmApiRequest.call(this, 'GET', endpoint, undefined, {
page_size: limit,
});
} }
} else if (operation === 'create') { } else if (operation === 'create') {
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
@ -537,10 +535,13 @@ export class AgileCrm implements INodeType {
if (validateJSON(additionalFieldsJson) !== undefined) { if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson)); Object.assign(body, JSON.parse(additionalFieldsJson));
} else { } else {
throw new NodeOperationError(this.getNode(), 'Additional fields must be a valid JSON', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'Additional fields must be a valid JSON',
{ itemIndex: i },
);
} }
} }
} else { } else {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
@ -558,12 +559,10 @@ export class AgileCrm implements INodeType {
// @ts-ignore // @ts-ignore
body.customData = additionalFields.customData.customProperty as IDealCustomProperty[]; body.customData = additionalFields.customData.customProperty as IDealCustomProperty[];
} }
} }
const endpoint = 'api/opportunity'; const endpoint = 'api/opportunity';
responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body); responseData = await agileCrmApiRequest.call(this, 'POST', endpoint, body);
} else if (operation === 'update') { } else if (operation === 'update') {
const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean; const jsonParameters = this.getNodeParameter('jsonParameters', i) as boolean;
@ -573,16 +572,16 @@ export class AgileCrm implements INodeType {
const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string; const additionalFieldsJson = this.getNodeParameter('additionalFieldsJson', i) as string;
if (additionalFieldsJson !== '') { if (additionalFieldsJson !== '') {
if (validateJSON(additionalFieldsJson) !== undefined) { if (validateJSON(additionalFieldsJson) !== undefined) {
Object.assign(body, JSON.parse(additionalFieldsJson)); Object.assign(body, JSON.parse(additionalFieldsJson));
} else { } else {
throw new NodeOperationError(this.getNode(), 'Additional fields must be valid JSON', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'Additional fields must be valid JSON',
{ itemIndex: i },
);
} }
} }
} else { } else {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
body.id = this.getNodeParameter('dealId', i) as number; body.id = this.getNodeParameter('dealId', i) as number;
@ -607,7 +606,6 @@ export class AgileCrm implements INodeType {
// @ts-ignore // @ts-ignore
body.customData = additionalFields.customData.customProperty as IDealCustomProperty[]; body.customData = additionalFields.customData.customProperty as IDealCustomProperty[];
} }
} }
const endpoint = 'api/opportunity/partial-update'; const endpoint = 'api/opportunity/partial-update';
@ -620,10 +618,8 @@ export class AgileCrm implements INodeType {
} else { } else {
returnData.push(responseData as IDataObject); returnData.push(responseData as IDataObject);
} }
} }
return [this.helpers.returnJsonArray(returnData)]; return [this.helpers.returnJsonArray(returnData)];
} }
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const companyOperations: INodeProperties[] = [ export const companyOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const companyOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company',
],
}, },
}, },
options: [ options: [
@ -62,12 +58,8 @@ export const companyFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
default: '', default: '',
@ -83,12 +75,8 @@ export const companyFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -103,15 +91,9 @@ export const companyFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
default: 20, default: 20,
@ -138,12 +120,8 @@ export const companyFields: INodeProperties[] = [
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: 'none', default: 'none',
@ -164,15 +142,9 @@ export const companyFields: INodeProperties[] = [
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
], filterType: ['manual'],
operation: [
'getAll',
],
filterType: [
'manual',
],
}, },
}, },
default: 'anyFilter', default: 'anyFilter',
@ -183,12 +155,8 @@ export const companyFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
// eslint-disable-next-line n8n-nodes-base/node-param-default-wrong-for-simplify // eslint-disable-next-line n8n-nodes-base/node-param-default-wrong-for-simplify
@ -204,15 +172,9 @@ export const companyFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
], filterType: ['manual'],
operation: [
'getAll',
],
filterType: [
'manual',
],
}, },
}, },
default: {}, default: {},
@ -277,9 +239,7 @@ export const companyFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
condition_type: [ condition_type: ['BETWEEN'],
'BETWEEN',
],
}, },
}, },
default: '', default: '',
@ -289,20 +249,15 @@ export const companyFields: INodeProperties[] = [
], ],
}, },
{ {
displayName: 'See <a href="https://github.com/agilecrm/rest-api#121-get-contacts-by-dynamic-filter" target="_blank">Agile CRM guide</a> to creating filters', displayName:
'See <a href="https://github.com/agilecrm/rest-api#121-get-contacts-by-dynamic-filter" target="_blank">Agile CRM guide</a> to creating filters',
name: 'jsonNotice', name: 'jsonNotice',
type: 'notice', type: 'notice',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
], filterType: ['json'],
operation: [
'getAll',
],
filterType: [
'json',
],
}, },
}, },
default: '', default: '',
@ -316,15 +271,9 @@ export const companyFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
], filterType: ['json'],
operation: [
'getAll',
],
filterType: [
'json',
],
}, },
}, },
default: '', default: '',
@ -337,12 +286,8 @@ export const companyFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -398,12 +343,8 @@ export const companyFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -417,18 +358,13 @@ export const companyFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['create'],
], jsonParameters: [true],
operation: [
'create',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-companys---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-companys---companies-api">here</a>',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -438,15 +374,9 @@ export const companyFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -522,7 +452,8 @@ export const companyFields: INodeProperties[] = [
multipleValueButtonText: 'Add Tag', multipleValueButtonText: 'Add Tag',
}, },
default: [], default: [],
description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', description:
'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.',
}, },
{ {
displayName: 'Website', displayName: 'Website',
@ -656,12 +587,8 @@ export const companyFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
default: '', default: '',
@ -678,12 +605,8 @@ export const companyFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
default: '', default: '',
@ -696,12 +619,8 @@ export const companyFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -715,18 +634,13 @@ export const companyFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['update'],
], jsonParameters: [true],
operation: [
'update',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-companys---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-companys---companies-api">here</a>',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -736,15 +650,9 @@ export const companyFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['company'],
'company', operation: ['update'],
], jsonParameters: [false],
operation: [
'update',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -806,7 +714,8 @@ export const companyFields: INodeProperties[] = [
multipleValueButtonText: 'Add Tag', multipleValueButtonText: 'Add Tag',
}, },
default: [], default: [],
description: 'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.', description:
'Unique identifiers added to company, for easy management of companys. This is not applicable for companies.',
}, },
{ {
displayName: 'Name', displayName: 'Name',
@ -943,5 +852,4 @@ export const companyFields: INodeProperties[] = [
}, },
], ],
}, },
]; ];

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactOperations: INodeProperties[] = [ export const contactOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact',
],
}, },
}, },
options: [ options: [
@ -62,12 +58,8 @@ export const contactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
default: '', default: '',
@ -83,12 +75,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -103,15 +91,9 @@ export const contactFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
default: 20, default: 20,
@ -138,12 +120,8 @@ export const contactFields: INodeProperties[] = [
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: 'none', default: 'none',
@ -164,15 +142,9 @@ export const contactFields: INodeProperties[] = [
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
], filterType: ['manual'],
operation: [
'getAll',
],
filterType: [
'manual',
],
}, },
}, },
default: 'anyFilter', default: 'anyFilter',
@ -183,12 +155,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
// eslint-disable-next-line n8n-nodes-base/node-param-default-wrong-for-simplify // eslint-disable-next-line n8n-nodes-base/node-param-default-wrong-for-simplify
@ -204,15 +172,9 @@ export const contactFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
], filterType: ['manual'],
operation: [
'getAll',
],
filterType: [
'manual',
],
}, },
}, },
default: {}, default: {},
@ -277,9 +239,7 @@ export const contactFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
condition_type: [ condition_type: ['BETWEEN'],
'BETWEEN',
],
}, },
}, },
default: '', default: '',
@ -289,20 +249,15 @@ export const contactFields: INodeProperties[] = [
], ],
}, },
{ {
displayName: 'See <a href="https://github.com/agilecrm/rest-api#121-get-contacts-by-dynamic-filter" target="_blank">Agile CRM guide</a> to creating filters', displayName:
'See <a href="https://github.com/agilecrm/rest-api#121-get-contacts-by-dynamic-filter" target="_blank">Agile CRM guide</a> to creating filters',
name: 'jsonNotice', name: 'jsonNotice',
type: 'notice', type: 'notice',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
], filterType: ['json'],
operation: [
'getAll',
],
filterType: [
'json',
],
}, },
}, },
default: '', default: '',
@ -316,15 +271,9 @@ export const contactFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
], filterType: ['json'],
operation: [
'getAll',
],
filterType: [
'json',
],
}, },
}, },
default: '', default: '',
@ -337,12 +286,8 @@ export const contactFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -399,12 +344,8 @@ export const contactFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -418,19 +359,14 @@ export const contactFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['create'],
], jsonParameters: [true],
operation: [
'create',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-contacts---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-contacts---companies-api">here</a>',
}, },
{ {
@ -441,15 +377,9 @@ export const contactFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -682,7 +612,8 @@ export const contactFields: INodeProperties[] = [
multipleValueButtonText: 'Add Tag', multipleValueButtonText: 'Add Tag',
}, },
default: [], default: [],
description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.', description:
'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.',
}, },
{ {
displayName: 'Title', displayName: 'Title',
@ -823,12 +754,8 @@ export const contactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
default: '', default: '',
@ -845,12 +772,8 @@ export const contactFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
default: '', default: '',
@ -863,12 +786,8 @@ export const contactFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -882,18 +801,13 @@ export const contactFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['update'],
], jsonParameters: [true],
operation: [
'update',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-contacts---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-contacts---companies-api">here</a>',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -903,15 +817,9 @@ export const contactFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact', operation: ['update'],
], jsonParameters: [false],
operation: [
'update',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -1144,7 +1052,8 @@ export const contactFields: INodeProperties[] = [
multipleValueButtonText: 'Add Tag', multipleValueButtonText: 'Add Tag',
}, },
default: [], default: [],
description: 'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.', description:
'Unique identifiers added to contact, for easy management of contacts. This is not applicable for companies.',
}, },
{ {
displayName: 'Title', displayName: 'Title',
@ -1274,5 +1183,4 @@ export const contactFields: INodeProperties[] = [
}, },
], ],
}, },
]; ];

View file

@ -1,6 +1,4 @@
import { import { IDataObject } from 'n8n-workflow';
IDataObject,
} from 'n8n-workflow';
export interface IProperty { export interface IProperty {
type: string; type: string;

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const dealOperations: INodeProperties[] = [ export const dealOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const dealOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal',
],
}, },
}, },
options: [ options: [
@ -46,7 +42,6 @@ export const dealOperations: INodeProperties[] = [
description: 'Update deal properties', description: 'Update deal properties',
action: 'Update a deal', action: 'Update a deal',
}, },
], ],
default: 'get', default: 'get',
}, },
@ -63,19 +58,14 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
default: '', default: '',
description: 'Unique identifier for a particular deal', description: 'Unique identifier for a particular deal',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* deal:get all */ /* deal:get all */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -90,15 +80,9 @@ export const dealFields: INodeProperties[] = [
default: 20, default: 20,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
}, },
@ -108,12 +92,8 @@ export const dealFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -129,15 +109,9 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: '', default: '',
@ -154,15 +128,9 @@ export const dealFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: 1, default: 1,
@ -175,15 +143,9 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: '', default: '',
@ -196,15 +158,9 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: '', default: '',
@ -221,15 +177,9 @@ export const dealFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: 50, default: 50,
@ -242,12 +192,8 @@ export const dealFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -261,18 +207,13 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [true],
operation: [
'create',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-deals---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-deals---companies-api">here</a>',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -282,15 +223,9 @@ export const dealFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -350,12 +285,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
default: '', default: '',
@ -372,12 +303,8 @@ export const dealFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
default: '', default: '',
@ -390,12 +317,8 @@ export const dealFields: INodeProperties[] = [
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
}, },
@ -409,19 +332,14 @@ export const dealFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['update'],
], jsonParameters: [true],
operation: [
'update',
],
jsonParameters: [
true,
],
}, },
}, },
description: 'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-deals---companies-api">here</a>', description:
'Object of values to set as described <a href="https://github.com/agilecrm/rest-api#1-deals---companies-api">here</a>',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -431,15 +349,9 @@ export const dealFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['deal'],
'deal', operation: ['update'],
], jsonParameters: [false],
operation: [
'update',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [

View file

@ -7,28 +7,28 @@ import {
ILoadOptionsFunctions, ILoadOptionsFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { IDataObject, NodeApiError } from 'n8n-workflow';
IDataObject,
NodeApiError,
} from 'n8n-workflow';
import { import { IContactUpdate } from './ContactInterface';
IContactUpdate,
} from './ContactInterface';
import { import { IFilterRules, ISearchConditions } from './FilterInterface';
IFilterRules,
ISearchConditions,
} from './FilterInterface';
export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string, endpoint: string, body: any = {}, query: IDataObject = {}, uri?: string, sendAsForm?: boolean): Promise<any> { // tslint:disable-line:no-any
export async function agileCrmApiRequest(
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
sendAsForm?: boolean,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('agileCrmApi'); const credentials = await this.getCredentials('agileCrmApi');
const options: OptionsWithUri = { const options: OptionsWithUri = {
method, method,
headers: { headers: {
'Accept': 'application/json', Accept: 'application/json',
}, },
auth: { auth: {
username: credentials.email as string, username: credentials.email as string,
@ -40,7 +40,7 @@ export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunction
}; };
// To send the request as 'content-type': 'application/x-www-form-urlencoded' add form to options instead of body // To send the request as 'content-type': 'application/x-www-form-urlencoded' add form to options instead of body
if(sendAsForm) { if (sendAsForm) {
options.form = body; options.form = body;
} }
// Only add Body property if method not GET or DELETE to avoid 400 response // Only add Body property if method not GET or DELETE to avoid 400 response
@ -56,38 +56,63 @@ export async function agileCrmApiRequest(this: IHookFunctions | IExecuteFunction
} }
} }
export async function agileCrmApiRequestAllItems(this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions, export async function agileCrmApiRequestAllItems(
method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, sendAsForm?: boolean): Promise<any> { // tslint:disable-line:no-any this: IHookFunctions | ILoadOptionsFunctions | IExecuteFunctions,
method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
sendAsForm?: boolean,
// tslint:disable-next-line:no-any
): Promise<any> {
// https://github.com/agilecrm/rest-api#11-listing-contacts- // https://github.com/agilecrm/rest-api#11-listing-contacts-
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
do { do {
responseData = await agileCrmApiRequest.call(this, method, resource, body, query, uri, sendAsForm); responseData = await agileCrmApiRequest.call(
this,
method,
resource,
body,
query,
uri,
sendAsForm,
);
if (responseData.length !== 0) { if (responseData.length !== 0) {
returnData.push.apply(returnData, responseData); returnData.push.apply(returnData, responseData);
if (sendAsForm) { if (sendAsForm) {
body.cursor = responseData[responseData.length-1].cursor; body.cursor = responseData[responseData.length - 1].cursor;
} else { } else {
query.cursor = responseData[responseData.length-1].cursor; query.cursor = responseData[responseData.length - 1].cursor;
} }
} }
} while ( } while (
responseData.length !== 0 && responseData.length !== 0 &&
responseData[responseData.length-1].hasOwnProperty('cursor') responseData[responseData.length - 1].hasOwnProperty('cursor')
); );
return returnData; return returnData;
} }
export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method = 'PUT', endpoint?: string, body: any = {}, query: IDataObject = {}, uri?: string): Promise<any> { // tslint:disable-line:no-any export async function agileCrmApiRequestUpdate(
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
method = 'PUT',
endpoint?: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('agileCrmApi'); const credentials = await this.getCredentials('agileCrmApi');
const baseUri = `https://${credentials.subdomain}.agilecrm.com/dev/`; const baseUri = `https://${credentials.subdomain}.agilecrm.com/dev/`;
const options: OptionsWithUri = { const options: OptionsWithUri = {
method, method,
headers: { headers: {
'Accept': 'application/json', Accept: 'application/json',
}, },
body: { id: body.id }, body: { id: body.id },
auth: { auth: {
@ -110,7 +135,8 @@ export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFu
lastSuccesfulUpdateReturn = await this.helpers.request!(options); lastSuccesfulUpdateReturn = await this.helpers.request!(options);
// Iterate trough properties and show them as individial updates instead of only vague "properties" // Iterate trough properties and show them as individial updates instead of only vague "properties"
payload.properties?.map((property: any) => { // tslint:disable-line:no-any // tslint:disable-next-line:no-any
payload.properties?.map((property: any) => {
successfulUpdates.push(`${property.name}`); successfulUpdates.push(`${property.name}`);
}); });
@ -147,18 +173,21 @@ export async function agileCrmApiRequestUpdate(this: IHookFunctions | IExecuteFu
} }
return lastSuccesfulUpdateReturn; return lastSuccesfulUpdateReturn;
} catch (error) { } catch (error) {
if (successfulUpdates.length === 0) { if (successfulUpdates.length === 0) {
throw new NodeApiError(this.getNode(), error); throw new NodeApiError(this.getNode(), error);
} else { } else {
throw new NodeApiError(this.getNode(), error, { message: `Not all properties updated. Updated properties: ${successfulUpdates.join(', ')}`, description: error.message, httpCode: error.statusCode }); throw new NodeApiError(this.getNode(), error, {
message: `Not all properties updated. Updated properties: ${successfulUpdates.join(', ')}`,
description: error.message,
httpCode: error.statusCode,
});
} }
} }
} }
export function validateJSON(json: string | undefined): any { // tslint:disable-line:no-any // tslint:disable-next-line:no-any
export function validateJSON(json: string | undefined): any {
let result; let result;
try { try {
result = JSON.parse(json!); result = JSON.parse(json!);
@ -168,7 +197,7 @@ export function validateJSON(json: string | undefined): any { // tslint:disable-
return result; return result;
} }
export function getFilterRules(conditions: ISearchConditions[], matchType: string): IDataObject { // tslint:disable-line:no-any export function getFilterRules(conditions: ISearchConditions[], matchType: string): IDataObject {
const rules = []; const rules = [];
for (const key in conditions) { for (const key in conditions) {
@ -180,7 +209,7 @@ export function getFilterRules(conditions: ISearchConditions[], matchType: strin
RHS: searchConditions.value as string, RHS: searchConditions.value as string,
RHS_NEW: searchConditions.value2 as string, RHS_NEW: searchConditions.value2 as string,
}; };
rules.push(rule); rules.push(rule);
} }
} }
@ -188,18 +217,24 @@ export function getFilterRules(conditions: ISearchConditions[], matchType: strin
return { return {
or_rules: rules, or_rules: rules,
}; };
} } else {
else {
return { return {
rules, rules,
}; };
} }
} }
export function simplifyResponse(records: [{ id: string, properties: [{ name: string, value: string }] } ]) { export function simplifyResponse(
records: [{ id: string; properties: [{ name: string; value: string }] }],
) {
const results = []; const results = [];
for (const record of records) { for (const record of records) {
results.push(record.properties.reduce((obj, value) => Object.assign(obj, { [`${value.name}`]: value.value }), { id: record.id })); results.push(
record.properties.reduce(
(obj, value) => Object.assign(obj, { [`${value.name}`]: value.value }),
{ id: record.id },
),
);
} }
return results; return results;
} }

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -10,11 +8,7 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { apiRequest, apiRequestAllItems, downloadRecordAttachments } from './GenericFunctions';
apiRequest,
apiRequestAllItems,
downloadRecordAttachments,
} from './GenericFunctions';
export class Airtable implements INodeType { export class Airtable implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -106,9 +100,7 @@ export class Airtable implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['append'],
'append',
],
}, },
}, },
default: true, default: true,
@ -124,12 +116,8 @@ export class Airtable implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
addAllFields: [ addAllFields: [false],
false, operation: ['append'],
],
operation: [
'append',
],
}, },
}, },
default: [], default: [],
@ -147,9 +135,7 @@ export class Airtable implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete',
],
}, },
}, },
default: '', default: '',
@ -166,9 +152,7 @@ export class Airtable implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['list'],
'list',
],
}, },
}, },
default: true, default: true,
@ -180,12 +164,8 @@ export class Airtable implements INodeType {
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['list'],
'list', returnAll: [false],
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -201,13 +181,11 @@ export class Airtable implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['list'],
'list',
],
}, },
}, },
default: false, default: false,
description: 'Whether the attachment fields define in \'Download Fields\' will be downloaded', description: "Whether the attachment fields define in 'Download Fields' will be downloaded",
}, },
{ {
displayName: 'Download Fields', displayName: 'Download Fields',
@ -216,16 +194,13 @@ export class Airtable implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['list'],
'list', downloadAttachments: [true],
],
downloadAttachments: [
true,
],
}, },
}, },
default: '', default: '',
description: 'Name of the fields of type \'attachment\' that should be downloaded. Multiple ones can be defined separated by comma. Case sensitive and cannot include spaces after a comma.', description:
"Name of the fields of type 'attachment' that should be downloaded. Multiple ones can be defined separated by comma. Case sensitive and cannot include spaces after a comma.",
}, },
{ {
displayName: 'Additional Options', displayName: 'Additional Options',
@ -233,9 +208,7 @@ export class Airtable implements INodeType {
type: 'collection', type: 'collection',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['list'],
'list',
],
}, },
}, },
default: {}, default: {},
@ -252,15 +225,17 @@ export class Airtable implements INodeType {
}, },
default: [], default: [],
placeholder: 'Name', placeholder: 'Name',
description: 'Only data for fields whose names are in this list will be included in the records', description:
'Only data for fields whose names are in this list will be included in the records',
}, },
{ {
displayName: 'Filter By Formula', displayName: 'Filter By Formula',
name: 'filterByFormula', name: 'filterByFormula',
type: 'string', type: 'string',
default: '', default: '',
placeholder: 'NOT({Name} = \'\')', placeholder: "NOT({Name} = '')",
description: 'A formula used to filter records. The formula will be evaluated for each record, and if the result is not 0, false, "", NaN, [], or #Error! the record will be included in the response.', description:
'A formula used to filter records. The formula will be evaluated for each record, and if the result is not 0, false, "", NaN, [], or #Error! the record will be included in the response.',
}, },
{ {
displayName: 'Sort', displayName: 'Sort',
@ -313,7 +288,8 @@ export class Airtable implements INodeType {
type: 'string', type: 'string',
default: '', default: '',
placeholder: 'All Stories', placeholder: 'All Stories',
description: 'The name or ID of a view in the Stories table. If set, only the records in that view will be returned. The records will be sorted according to the order of the view.', description:
'The name or ID of a view in the Stories table. If set, only the records in that view will be returned. The records will be sorted according to the order of the view.',
}, },
], ],
}, },
@ -327,9 +303,7 @@ export class Airtable implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['read'],
'read',
],
}, },
}, },
default: '', default: '',
@ -346,9 +320,7 @@ export class Airtable implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update',
],
}, },
}, },
default: '', default: '',
@ -361,9 +333,7 @@ export class Airtable implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update',
],
}, },
}, },
default: true, default: true,
@ -379,12 +349,8 @@ export class Airtable implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
updateAllFields: [ updateAllFields: [false],
false, operation: ['update'],
],
operation: [
'update',
],
}, },
}, },
default: [], default: [],
@ -403,11 +369,7 @@ export class Airtable implements INodeType {
placeholder: 'Add Option', placeholder: 'Add Option',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['append', 'delete', 'update'],
'append',
'delete',
'update',
],
}, },
}, },
default: {}, default: {},
@ -429,12 +391,8 @@ export class Airtable implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
'/operation': [ '/operation': ['update'],
'update', '/updateAllFields': [true],
],
'/updateAllFields': [
true,
],
}, },
}, },
default: '', default: '',
@ -446,14 +404,12 @@ export class Airtable implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
'/operation': [ '/operation': ['append', 'update'],
'append',
'update',
],
}, },
}, },
default: false, default: false,
description: 'Whether the Airtable API should attempt mapping of string values for linked records & select options', description:
'Whether the Airtable API should attempt mapping of string values for linked records & select options',
}, },
], ],
}, },
@ -496,7 +452,7 @@ export class Airtable implements INodeType {
try { try {
addAllFields = this.getNodeParameter('addAllFields', i) as boolean; addAllFields = this.getNodeParameter('addAllFields', i) as boolean;
options = this.getNodeParameter('options', i, {}) as IDataObject; options = this.getNodeParameter('options', i, {}) as IDataObject;
bulkSize = options.bulkSize as number || bulkSize; bulkSize = (options.bulkSize as number) || bulkSize;
const row: IDataObject = {}; const row: IDataObject = {};
@ -540,13 +496,12 @@ export class Airtable implements INodeType {
throw error; throw error;
} }
} }
} else if (operation === 'delete') { } else if (operation === 'delete') {
requestMethod = 'DELETE'; requestMethod = 'DELETE';
const rows: string[] = []; const rows: string[] = [];
const options = this.getNodeParameter('options', 0, {}) as IDataObject; const options = this.getNodeParameter('options', 0, {}) as IDataObject;
const bulkSize = options.bulkSize as number || 10; const bulkSize = (options.bulkSize as number) || 10;
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
try { try {
@ -581,7 +536,6 @@ export class Airtable implements INodeType {
throw error; throw error;
} }
} }
} else if (operation === 'list') { } else if (operation === 'list') {
// ---------------------------------- // ----------------------------------
// list // list
@ -614,8 +568,14 @@ export class Airtable implements INodeType {
returnData.push.apply(returnData, responseData.records); returnData.push.apply(returnData, responseData.records);
if (downloadAttachments === true) { if (downloadAttachments === true) {
const downloadFieldNames = (this.getNodeParameter('downloadFieldNames', 0) as string).split(','); const downloadFieldNames = (
const data = await downloadRecordAttachments.call(this, responseData.records, downloadFieldNames); this.getNodeParameter('downloadFieldNames', 0) as string
).split(',');
const data = await downloadRecordAttachments.call(
this,
responseData.records,
downloadFieldNames,
);
return [data]; return [data];
} }
} catch (error) { } catch (error) {
@ -625,7 +585,6 @@ export class Airtable implements INodeType {
throw error; throw error;
} }
} }
} else if (operation === 'read') { } else if (operation === 'read') {
// ---------------------------------- // ----------------------------------
// read // read
@ -635,7 +594,6 @@ export class Airtable implements INodeType {
let id: string; let id: string;
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
id = this.getNodeParameter('id', i) as string; id = this.getNodeParameter('id', i) as string;
endpoint = `${application}/${table}/${id}`; endpoint = `${application}/${table}/${id}`;
@ -658,7 +616,6 @@ export class Airtable implements INodeType {
throw error; throw error;
} }
} }
} else if (operation === 'update') { } else if (operation === 'update') {
// ---------------------------------- // ----------------------------------
// update // update
@ -677,7 +634,7 @@ export class Airtable implements INodeType {
try { try {
updateAllFields = this.getNodeParameter('updateAllFields', i) as boolean; updateAllFields = this.getNodeParameter('updateAllFields', i) as boolean;
options = this.getNodeParameter('options', i, {}) as IDataObject; options = this.getNodeParameter('options', i, {}) as IDataObject;
bulkSize = options.bulkSize as number || bulkSize; bulkSize = (options.bulkSize as number) || bulkSize;
const row: IDataObject = {}; const row: IDataObject = {};
row.fields = {} as IDataObject; row.fields = {} as IDataObject;
@ -690,7 +647,10 @@ export class Airtable implements INodeType {
delete (row.fields! as any).id; delete (row.fields! as any).id;
if (options.ignoreFields && options.ignoreFields !== '') { if (options.ignoreFields && options.ignoreFields !== '') {
const ignoreFields = (options.ignoreFields as string).split(',').map(field => field.trim()).filter(field => !!field); const ignoreFields = (options.ignoreFields as string)
.split(',')
.map((field) => field.trim())
.filter((field) => !!field);
if (ignoreFields.length) { if (ignoreFields.length) {
// From: https://stackoverflow.com/questions/17781472/how-to-get-a-subset-of-a-javascript-objects-properties // From: https://stackoverflow.com/questions/17781472/how-to-get-a-subset-of-a-javascript-objects-properties
row.fields = Object.entries(items[i].json) row.fields = Object.entries(items[i].json)
@ -721,7 +681,7 @@ export class Airtable implements INodeType {
// according to specific rules like not more than 5 requests // according to specific rules like not more than 5 requests
// per seconds. // per seconds.
const data = { records: rows, typecast: (options.typecast) ? true : false }; const data = { records: rows, typecast: options.typecast ? true : false };
responseData = await apiRequest.call(this, requestMethod, endpoint, data, qs); responseData = await apiRequest.call(this, requestMethod, endpoint, data, qs);
@ -738,7 +698,6 @@ export class Airtable implements INodeType {
throw error; throw error;
} }
} }
} else { } else {
throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`); throw new NodeOperationError(this.getNode(), `The operation "${operation}" is not known!`);
} }

View file

@ -1,6 +1,4 @@
import { import { IPollFunctions } from 'n8n-core';
IPollFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -10,10 +8,7 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { apiRequestAllItems, downloadRecordAttachments } from './GenericFunctions';
apiRequestAllItems,
downloadRecordAttachments,
} from './GenericFunctions';
import moment from 'moment'; import moment from 'moment';
@ -60,7 +55,8 @@ export class AirtableTrigger implements INodeType {
name: 'triggerField', name: 'triggerField',
type: 'string', type: 'string',
default: '', default: '',
description: 'A Created Time or Last Modified Time field that will be used to sort records. If you do not have a Created Time or Last Modified Time field in your schema, please create one, because without this field trigger will not work correctly.', description:
'A Created Time or Last Modified Time field that will be used to sort records. If you do not have a Created Time or Last Modified Time field in your schema, please create one, because without this field trigger will not work correctly.',
required: true, required: true,
}, },
{ {
@ -68,7 +64,7 @@ export class AirtableTrigger implements INodeType {
name: 'downloadAttachments', name: 'downloadAttachments',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether the attachment fields define in \'Download Fields\' will be downloaded', description: "Whether the attachment fields define in 'Download Fields' will be downloaded",
}, },
{ {
displayName: 'Download Fields', displayName: 'Download Fields',
@ -77,13 +73,12 @@ export class AirtableTrigger implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
downloadAttachments: [ downloadAttachments: [true],
true,
],
}, },
}, },
default: '', default: '',
description: 'Name of the fields of type \'attachment\' that should be downloaded. Multiple ones can be defined separated by comma. Case sensitive.', description:
"Name of the fields of type 'attachment' that should be downloaded. Multiple ones can be defined separated by comma. Case sensitive.",
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -98,21 +93,24 @@ export class AirtableTrigger implements INodeType {
type: 'string', type: 'string',
default: '', default: '',
// eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-id // eslint-disable-next-line n8n-nodes-base/node-param-description-miscased-id
description: 'Fields to be included in the response. Multiple ones can be set separated by comma. Example: <code>name, id</code>. By default just the trigger field will be included.', description:
'Fields to be included in the response. Multiple ones can be set separated by comma. Example: <code>name, id</code>. By default just the trigger field will be included.',
}, },
{ {
displayName: 'Formula', displayName: 'Formula',
name: 'formula', name: 'formula',
type: 'string', type: 'string',
default: '', default: '',
description: 'Formulas may involve functions, numeric operations, logical operations, and text operations that operate on fields. More info <a href="https://support.airtable.com/hc/en-us/articles/203255215-Formula-Field-Reference">here</a>.', description:
'Formulas may involve functions, numeric operations, logical operations, and text operations that operate on fields. More info <a href="https://support.airtable.com/hc/en-us/articles/203255215-Formula-Field-Reference">here</a>.',
}, },
{ {
displayName: 'View ID', displayName: 'View ID',
name: 'viewId', name: 'viewId',
type: 'string', type: 'string',
default: '', default: '',
description: 'The name or ID of a view in the table. If set, only the records in that view will be returned.', description:
'The name or ID of a view in the table. If set, only the records in that view will be returned.',
}, },
], ],
}, },
@ -138,7 +136,7 @@ export class AirtableTrigger implements INodeType {
const now = moment().utc().format(); const now = moment().utc().format();
const startDate = webhookData.lastTimeChecked as string || now; const startDate = (webhookData.lastTimeChecked as string) || now;
const endDate = now; const endDate = now;
@ -171,7 +169,9 @@ export class AirtableTrigger implements INodeType {
} }
if (downloadAttachments === true) { if (downloadAttachments === true) {
const downloadFieldNames = (this.getNodeParameter('downloadFieldNames', 0) as string).split(','); const downloadFieldNames = (this.getNodeParameter('downloadFieldNames', 0) as string).split(
',',
);
const data = await downloadRecordAttachments.call(this, records, downloadFieldNames); const data = await downloadRecordAttachments.call(this, records, downloadFieldNames);
return [data]; return [data];
} }

View file

@ -1,11 +1,6 @@
import { import { IExecuteFunctions, IPollFunctions } from 'n8n-core';
IExecuteFunctions,
IPollFunctions,
} from 'n8n-core';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import {
IBinaryKeyData, IBinaryKeyData,
@ -15,7 +10,6 @@ import {
NodeApiError, NodeApiError,
} from 'n8n-workflow'; } from 'n8n-workflow';
interface IAttachment { interface IAttachment {
url: string; url: string;
filename: string; filename: string;
@ -24,7 +18,7 @@ interface IAttachment {
export interface IRecord { export interface IRecord {
fields: { fields: {
[key: string]: string | IAttachment[], [key: string]: string | IAttachment[];
}; };
} }
@ -37,7 +31,16 @@ export interface IRecord {
* @param {object} body * @param {object} body
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function apiRequest(this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: object, query?: IDataObject, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function apiRequest(
this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
method: string,
endpoint: string,
body: object,
query?: IDataObject,
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('airtableApi'); const credentials = await this.getCredentials('airtableApi');
query = query || {}; query = query || {};
@ -48,8 +51,7 @@ export async function apiRequest(this: IExecuteFunctions | ILoadOptionsFunctions
// query.api_key = credentials.apiKey; // query.api_key = credentials.apiKey;
const options: OptionsWithUri = { const options: OptionsWithUri = {
headers: { headers: {},
},
method, method,
body, body,
qs: query, qs: query,
@ -73,7 +75,6 @@ export async function apiRequest(this: IExecuteFunctions | ILoadOptionsFunctions
} }
} }
/** /**
* Make an API request to paginated Airtable endpoint * Make an API request to paginated Airtable endpoint
* and return all results * and return all results
@ -86,8 +87,14 @@ export async function apiRequest(this: IExecuteFunctions | ILoadOptionsFunctions
* @param {IDataObject} [query] * @param {IDataObject} [query]
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function apiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions, method: string, endpoint: string, body: IDataObject, query?: IDataObject): Promise<any> { // tslint:disable-line:no-any export async function apiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IPollFunctions,
method: string,
endpoint: string,
body: IDataObject,
query?: IDataObject,
// tslint:disable-next-line:no-any
): Promise<any> {
if (query === undefined) { if (query === undefined) {
query = {}; query = {};
} }
@ -102,16 +109,18 @@ export async function apiRequestAllItems(this: IExecuteFunctions | ILoadOptionsF
returnData.push.apply(returnData, responseData.records); returnData.push.apply(returnData, responseData.records);
query.offset = responseData.offset; query.offset = responseData.offset;
} while ( } while (responseData.offset !== undefined);
responseData.offset !== undefined
);
return { return {
records: returnData, records: returnData,
}; };
} }
export async function downloadRecordAttachments(this: IExecuteFunctions | IPollFunctions, records: IRecord[], fieldNames: string[]): Promise<INodeExecutionData[]> { export async function downloadRecordAttachments(
this: IExecuteFunctions | IPollFunctions,
records: IRecord[],
fieldNames: string[],
): Promise<INodeExecutionData[]> {
const elements: INodeExecutionData[] = []; const elements: INodeExecutionData[] = [];
for (const record of records) { for (const record of records) {
const element: INodeExecutionData = { json: {}, binary: {} }; const element: INodeExecutionData = { json: {}, binary: {} };
@ -119,8 +128,15 @@ export async function downloadRecordAttachments(this: IExecuteFunctions | IPollF
for (const fieldName of fieldNames) { for (const fieldName of fieldNames) {
if (record.fields[fieldName] !== undefined) { if (record.fields[fieldName] !== undefined) {
for (const [index, attachment] of (record.fields[fieldName] as IAttachment[]).entries()) { for (const [index, attachment] of (record.fields[fieldName] as IAttachment[]).entries()) {
const file = await apiRequest.call(this, 'GET', '', {}, {}, attachment.url, { json: false, encoding: null }); const file = await apiRequest.call(this, 'GET', '', {}, {}, attachment.url, {
element.binary![`${fieldName}_${index}`] = await this.helpers.prepareBinaryData(Buffer.from(file), attachment.filename, attachment.type); json: false,
encoding: null,
});
element.binary![`${fieldName}_${index}`] = await this.helpers.prepareBinaryData(
Buffer.from(file),
attachment.filename,
attachment.type,
);
} }
} }
} }

View file

@ -1,9 +1,4 @@
import { import { ContainerOptions, create_container, Dictionary, EventContext } from 'rhea';
ContainerOptions,
create_container,
Dictionary,
EventContext,
} from 'rhea';
import { IExecuteFunctions } from 'n8n-core'; import { IExecuteFunctions } from 'n8n-core';
import { import {
@ -28,10 +23,12 @@ export class Amqp implements INodeType {
}, },
inputs: ['main'], inputs: ['main'],
outputs: ['main'], outputs: ['main'],
credentials: [{ credentials: [
name: 'amqp', {
required: true, name: 'amqp',
}], required: true,
},
],
properties: [ properties: [
{ {
displayName: 'Queue / Topic', displayName: 'Queue / Topic',
@ -47,7 +44,8 @@ export class Amqp implements INodeType {
name: 'headerParametersJson', name: 'headerParametersJson',
type: 'json', type: 'json',
default: '', default: '',
description: 'Header parameters as JSON (flat object). Sent as application_properties in amqp-message meta info.', description:
'Header parameters as JSON (flat object). Sent as application_properties in amqp-message meta info.',
}, },
{ {
displayName: 'Options', displayName: 'Options',
@ -101,11 +99,13 @@ export class Amqp implements INodeType {
const credentials = await this.getCredentials('amqp'); const credentials = await this.getCredentials('amqp');
const sink = this.getNodeParameter('sink', 0, '') as string; const sink = this.getNodeParameter('sink', 0, '') as string;
const applicationProperties = this.getNodeParameter('headerParametersJson', 0, {}) as string | object; const applicationProperties = this.getNodeParameter('headerParametersJson', 0, {}) as
| string
| object;
const options = this.getNodeParameter('options', 0, {}) as IDataObject; const options = this.getNodeParameter('options', 0, {}) as IDataObject;
const containerId = options.containerId as string; const containerId = options.containerId as string;
const containerReconnect = options.reconnect as boolean || true; const containerReconnect = (options.reconnect as boolean) || true;
const containerReconnectLimit = options.reconnectLimit as number || 50; const containerReconnectLimit = (options.reconnectLimit as number) || 50;
let headerProperties: Dictionary<any>; // tslint:disable-line:no-any let headerProperties: Dictionary<any>; // tslint:disable-line:no-any
if (typeof applicationProperties === 'string' && applicationProperties !== '') { if (typeof applicationProperties === 'string' && applicationProperties !== '') {
@ -177,7 +177,7 @@ export class Amqp implements INodeType {
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
return [this.helpers.returnJsonArray({ error: error.message })]; return [this.helpers.returnJsonArray({ error: error.message })];
}else{ } else {
throw error; throw error;
} }
} }

View file

@ -1,10 +1,4 @@
import { import { ContainerOptions, create_container, EventContext, Message, ReceiverOptions } from 'rhea';
ContainerOptions,
create_container,
EventContext,
Message,
ReceiverOptions,
} from 'rhea';
import { ITriggerFunctions } from 'n8n-core'; import { ITriggerFunctions } from 'n8n-core';
import { import {
@ -15,7 +9,6 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
export class AmqpTrigger implements INodeType { export class AmqpTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
displayName: 'AMQP Trigger', displayName: 'AMQP Trigger',
@ -30,10 +23,12 @@ export class AmqpTrigger implements INodeType {
}, },
inputs: [], inputs: [],
outputs: ['main'], outputs: ['main'],
credentials: [{ credentials: [
name: 'amqp', {
required: true, name: 'amqp',
}], required: true,
},
],
properties: [ properties: [
// Node properties which the user gets displayed and // Node properties which the user gets displayed and
// can change on the node. // can change on the node.
@ -80,7 +75,8 @@ export class AmqpTrigger implements INodeType {
name: 'jsonConvertByteArrayToString', name: 'jsonConvertByteArrayToString',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether to convert JSON Body content (["body"]["content"]) from Byte Array to string. Needed for Azure Service Bus.', description:
'Whether to convert JSON Body content (["body"]["content"]) from Byte Array to string. Needed for Azure Service Bus.',
}, },
{ {
displayName: 'JSON Parse Body', displayName: 'JSON Parse Body',
@ -129,19 +125,17 @@ export class AmqpTrigger implements INodeType {
], ],
}; };
async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> { async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
const credentials = await this.getCredentials('amqp'); const credentials = await this.getCredentials('amqp');
const sink = this.getNodeParameter('sink', '') as string; const sink = this.getNodeParameter('sink', '') as string;
const clientname = this.getNodeParameter('clientname', '') as string; const clientname = this.getNodeParameter('clientname', '') as string;
const subscription = this.getNodeParameter('subscription', '') as string; const subscription = this.getNodeParameter('subscription', '') as string;
const options = this.getNodeParameter('options', {}) as IDataObject; const options = this.getNodeParameter('options', {}) as IDataObject;
const pullMessagesNumber = options.pullMessagesNumber as number || 100; const pullMessagesNumber = (options.pullMessagesNumber as number) || 100;
const containerId = options.containerId as string; const containerId = options.containerId as string;
const containerReconnect = options.reconnect as boolean || true; const containerReconnect = (options.reconnect as boolean) || true;
const containerReconnectLimit = options.reconnectLimit as number || 50; const containerReconnectLimit = (options.reconnectLimit as number) || 50;
if (sink === '') { if (sink === '') {
throw new NodeOperationError(this.getNode(), 'Queue or Topic required!'); throw new NodeOperationError(this.getNode(), 'Queue or Topic required!');
@ -163,7 +157,6 @@ export class AmqpTrigger implements INodeType {
}); });
container.on('message', (context: EventContext) => { container.on('message', (context: EventContext) => {
// No message in the context // No message in the context
if (!context.message) { if (!context.message) {
return; return;
@ -202,13 +195,12 @@ export class AmqpTrigger implements INodeType {
data = data.body; data = data.body;
} }
self.emit([self.helpers.returnJsonArray([data as any])]); // tslint:disable-line:no-any self.emit([self.helpers.returnJsonArray([data as any])]); // tslint:disable-line:no-any
if (!context.receiver?.has_credit()) { if (!context.receiver?.has_credit()) {
setTimeout(() => { setTimeout(() => {
context.receiver?.add_credit(pullMessagesNumber); context.receiver?.add_credit(pullMessagesNumber);
}, options.sleepTime as number || 10); }, (options.sleepTime as number) || 10);
} }
}); });
@ -233,14 +225,13 @@ export class AmqpTrigger implements INodeType {
name: subscription ? subscription : undefined, name: subscription ? subscription : undefined,
source: { source: {
address: sink, address: sink,
durable: (durable ? 2 : undefined), durable: durable ? 2 : undefined,
expiry_policy: (durable ? 'never' : undefined), expiry_policy: durable ? 'never' : undefined,
}, },
credit_window: 0, // prefetch 1 credit_window: 0, // prefetch 1
}; };
connection.open_receiver(clientOptions); connection.open_receiver(clientOptions);
// The "closeFunction" function gets called by n8n whenever // The "closeFunction" function gets called by n8n whenever
// the workflow gets deactivated and can so clean up. // the workflow gets deactivated and can so clean up.
async function closeFunction() { async function closeFunction() {
@ -257,7 +248,11 @@ export class AmqpTrigger implements INodeType {
async function manualTriggerFunction() { async function manualTriggerFunction() {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
const timeoutHandler = setTimeout(() => { const timeoutHandler = setTimeout(() => {
reject(new Error('Aborted, no message received within 30secs. This 30sec timeout is only set for "manually triggered execution". Active Workflows will listen indefinitely.')); reject(
new Error(
'Aborted, no message received within 30secs. This 30sec timeout is only set for "manually triggered execution". Active Workflows will listen indefinitely.',
),
);
}, 30000); }, 30000);
container.on('message', (context: EventContext) => { container.on('message', (context: EventContext) => {
// Check if the only property present in the message is body // Check if the only property present in the message is body
@ -279,6 +274,5 @@ export class AmqpTrigger implements INodeType {
closeFunction, closeFunction,
manualTriggerFunction, manualTriggerFunction,
}; };
} }
} }

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -77,10 +75,7 @@ export class ApiTemplateIo implements INodeType {
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['image', 'pdf'],
'image',
'pdf',
],
}, },
}, },
}, },
@ -100,9 +95,7 @@ export class ApiTemplateIo implements INodeType {
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['account'],
'account',
],
}, },
}, },
}, },
@ -112,18 +105,15 @@ export class ApiTemplateIo implements INodeType {
type: 'options', type: 'options',
required: true, required: true,
default: '', default: '',
description: 'ID of the image template to use. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the image template to use. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getImageTemplates', loadOptionsMethod: 'getImageTemplates',
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['image'],
'image', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -133,18 +123,15 @@ export class ApiTemplateIo implements INodeType {
type: 'options', type: 'options',
required: true, required: true,
default: '', default: '',
description: 'ID of the PDF template to use. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the PDF template to use. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getPdfTemplates', loadOptionsMethod: 'getPdfTemplates',
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf'],
'pdf', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -155,13 +142,8 @@ export class ApiTemplateIo implements INodeType {
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf', 'image'],
'pdf', operation: ['create'],
'image',
],
operation: [
'create',
],
}, },
}, },
}, },
@ -172,13 +154,8 @@ export class ApiTemplateIo implements INodeType {
default: false, default: false,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf', 'image'],
'pdf', operation: ['create'],
'image',
],
operation: [
'create',
],
}, },
}, },
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
@ -193,16 +170,9 @@ export class ApiTemplateIo implements INodeType {
description: 'Name of the binary property to which to write to', description: 'Name of the binary property to which to write to',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf', 'image'],
'pdf', operation: ['create'],
'image', download: [true],
],
operation: [
'create',
],
download: [
true,
],
}, },
}, },
}, },
@ -213,15 +183,9 @@ export class ApiTemplateIo implements INodeType {
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['image'],
'image', operation: ['create'],
], jsonParameters: [true],
operation: [
'create',
],
jsonParameters: [
true,
],
}, },
}, },
placeholder: `[ {"name": "text_1", "text": "hello world", "textBackgroundColor": "rgba(246, 243, 243, 0)" } ]`, placeholder: `[ {"name": "text_1", "text": "hello world", "textBackgroundColor": "rgba(246, 243, 243, 0)" } ]`,
@ -233,15 +197,9 @@ export class ApiTemplateIo implements INodeType {
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf'],
'pdf', operation: ['create'],
], jsonParameters: [true],
operation: [
'create',
],
jsonParameters: [
true,
],
}, },
}, },
placeholder: `{ "name": "text_1" }`, placeholder: `{ "name": "text_1" }`,
@ -256,15 +214,9 @@ export class ApiTemplateIo implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['image'],
'image', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
default: {}, default: {},
@ -320,15 +272,9 @@ export class ApiTemplateIo implements INodeType {
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['pdf'],
'pdf', operation: ['create'],
], jsonParameters: [false],
operation: [
'create',
],
jsonParameters: [
false,
],
}, },
}, },
options: [ options: [
@ -361,16 +307,9 @@ export class ApiTemplateIo implements INodeType {
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['pdf', 'image'],
], download: [true],
resource: [
'pdf',
'image',
],
'download': [
true,
],
}, },
}, },
default: {}, default: {},
@ -380,7 +319,8 @@ export class ApiTemplateIo implements INodeType {
name: 'fileName', name: 'fileName',
type: 'string', type: 'string',
default: '', default: '',
description: 'The name of the downloaded image/pdf. It has to include the extension. For example: report.pdf', description:
'The name of the downloaded image/pdf. It has to include the extension. For example: report.pdf',
}, },
], ],
}, },
@ -410,13 +350,11 @@ export class ApiTemplateIo implements INodeType {
const operation = this.getNodeParameter('operation', 0) as string; const operation = this.getNodeParameter('operation', 0) as string;
if (resource === 'account') { if (resource === 'account') {
// ********************************************************************* // *********************************************************************
// account // account
// ********************************************************************* // *********************************************************************
if (operation === 'get') { if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// account: get // account: get
// ---------------------------------- // ----------------------------------
@ -428,16 +366,14 @@ export class ApiTemplateIo implements INodeType {
returnData.push(responseData); returnData.push(responseData);
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({json:{ error: error.message }}); returnData.push({ json: { error: error.message } });
continue; continue;
} }
throw error; throw error;
} }
} }
} }
} else if (resource === 'image') { } else if (resource === 'image') {
// ********************************************************************* // *********************************************************************
// image // image
// ********************************************************************* // *********************************************************************
@ -466,12 +402,21 @@ export class ApiTemplateIo implements INodeType {
const body = { overrides: [] } as IDataObject; const body = { overrides: [] } as IDataObject;
if (jsonParameters === false) { if (jsonParameters === false) {
const overrides = (this.getNodeParameter('overridesUi', i) as IDataObject || {}).overrideValues as IDataObject[] || []; const overrides =
(((this.getNodeParameter('overridesUi', i) as IDataObject) || {})
.overrideValues as IDataObject[]) || [];
if (overrides.length !== 0) { if (overrides.length !== 0) {
const data: IDataObject[] = []; const data: IDataObject[] = [];
for (const override of overrides) { for (const override of overrides) {
const properties = (override.propertiesUi as IDataObject || {}).propertyValues as IDataObject[] || []; const properties =
data.push(properties.reduce((obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }), {})); (((override.propertiesUi as IDataObject) || {})
.propertyValues as IDataObject[]) || [];
data.push(
properties.reduce(
(obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }),
{},
),
);
} }
body.overrides = data; body.overrides = data;
} }
@ -480,7 +425,9 @@ export class ApiTemplateIo implements INodeType {
if (overrideJson !== '') { if (overrideJson !== '') {
const data = validateJSON(overrideJson); const data = validateJSON(overrideJson);
if (data === undefined) { if (data === undefined) {
throw new NodeOperationError(this.getNode(), 'A valid JSON must be provided.', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'A valid JSON must be provided.', {
itemIndex: i,
});
} }
body.overrides = data; body.overrides = data;
} }
@ -492,7 +439,10 @@ export class ApiTemplateIo implements INodeType {
const binaryProperty = this.getNodeParameter('binaryProperty', i) as string; const binaryProperty = this.getNodeParameter('binaryProperty', i) as string;
const data = await downloadImage.call(this, responseData.download_url); const data = await downloadImage.call(this, responseData.download_url);
const fileName = responseData.download_url.split('/').pop(); const fileName = responseData.download_url.split('/').pop();
const binaryData = await this.helpers.prepareBinaryData(data, options.fileName || fileName); const binaryData = await this.helpers.prepareBinaryData(
data,
options.fileName || fileName,
);
responseData = { responseData = {
json: responseData, json: responseData,
binary: { binary: {
@ -503,7 +453,7 @@ export class ApiTemplateIo implements INodeType {
returnData.push(responseData); returnData.push(responseData);
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({json:{ error: error.message }}); returnData.push({ json: { error: error.message } });
continue; continue;
} }
throw error; throw error;
@ -514,15 +464,12 @@ export class ApiTemplateIo implements INodeType {
return this.prepareOutputData(returnData as unknown as INodeExecutionData[]); return this.prepareOutputData(returnData as unknown as INodeExecutionData[]);
} }
} }
} else if (resource === 'pdf') { } else if (resource === 'pdf') {
// ********************************************************************* // *********************************************************************
// pdf // pdf
// ********************************************************************* // *********************************************************************
if (operation === 'create') { if (operation === 'create') {
// ---------------------------------- // ----------------------------------
// pdf: create // pdf: create
// ---------------------------------- // ----------------------------------
@ -546,16 +493,27 @@ export class ApiTemplateIo implements INodeType {
let data; let data;
if (jsonParameters === false) { if (jsonParameters === false) {
const properties = (this.getNodeParameter('propertiesUi', i) as IDataObject || {}).propertyValues as IDataObject[] || []; const properties =
(((this.getNodeParameter('propertiesUi', i) as IDataObject) || {})
.propertyValues as IDataObject[]) || [];
if (properties.length === 0) { if (properties.length === 0) {
throw new NodeOperationError(this.getNode(), 'The parameter properties cannot be empty', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'The parameter properties cannot be empty',
{ itemIndex: i },
);
} }
data = properties.reduce((obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }), {}); data = properties.reduce(
(obj, value) => Object.assign(obj, { [`${value.key}`]: value.value }),
{},
);
} else { } else {
const propertiesJson = this.getNodeParameter('propertiesJson', i) as string; const propertiesJson = this.getNodeParameter('propertiesJson', i) as string;
data = validateJSON(propertiesJson); data = validateJSON(propertiesJson);
if (data === undefined) { if (data === undefined) {
throw new NodeOperationError(this.getNode(), 'A valid JSON must be provided.', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'A valid JSON must be provided.', {
itemIndex: i,
});
} }
} }
@ -565,7 +523,10 @@ export class ApiTemplateIo implements INodeType {
const binaryProperty = this.getNodeParameter('binaryProperty', i) as string; const binaryProperty = this.getNodeParameter('binaryProperty', i) as string;
const data = await downloadImage.call(this, responseData.download_url); const data = await downloadImage.call(this, responseData.download_url);
const fileName = responseData.download_url.split('/').pop(); const fileName = responseData.download_url.split('/').pop();
const binaryData = await this.helpers.prepareBinaryData(data, options.fileName || fileName); const binaryData = await this.helpers.prepareBinaryData(
data,
options.fileName || fileName,
);
responseData = { responseData = {
json: responseData, json: responseData,
binary: { binary: {
@ -576,7 +537,7 @@ export class ApiTemplateIo implements INodeType {
returnData.push(responseData); returnData.push(responseData);
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({json:{ error: error.message }}); returnData.push({ json: { error: error.message } });
continue; continue;
} }
throw error; throw error;

View file

@ -1,11 +1,6 @@
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { NodeApiError } from 'n8n-workflow'; import { NodeApiError } from 'n8n-workflow';
export async function apiTemplateIoApiRequest( export async function apiTemplateIoApiRequest(
@ -38,7 +33,11 @@ export async function apiTemplateIoApiRequest(
} }
try { try {
const response = await this.helpers.requestWithAuthentication.call(this, 'apiTemplateIoApi',options); const response = await this.helpers.requestWithAuthentication.call(
this,
'apiTemplateIoApi',
options,
);
if (response.status === 'error') { if (response.status === 'error') {
throw new NodeApiError(this.getNode(), response.message); throw new NodeApiError(this.getNode(), response.message);
} }
@ -48,21 +47,21 @@ export async function apiTemplateIoApiRequest(
} }
} }
export async function loadResource( export async function loadResource(this: ILoadOptionsFunctions, resource: 'image' | 'pdf') {
this: ILoadOptionsFunctions,
resource: 'image' | 'pdf',
) {
const target = resource === 'image' ? ['JPEG', 'PNG'] : ['PDF']; const target = resource === 'image' ? ['JPEG', 'PNG'] : ['PDF'];
const templates = await apiTemplateIoApiRequest.call(this, 'GET', '/list-templates'); const templates = await apiTemplateIoApiRequest.call(this, 'GET', '/list-templates');
const filtered = templates.filter(({ format }: { format: 'PDF' | 'JPEG' | 'PNG' }) => target.includes(format)); const filtered = templates.filter(({ format }: { format: 'PDF' | 'JPEG' | 'PNG' }) =>
target.includes(format),
);
return filtered.map(({ format, name, id }: { format: string, name: string, id: string }) => ({ return filtered.map(({ format, name, id }: { format: string; name: string; id: string }) => ({
name: `${name} (${format})`, name: `${name} (${format})`,
value: id, value: id,
})); }));
} }
export function validateJSON(json: string | object | undefined): any { // tslint:disable-line:no-any // tslint:disable-next-line:no-any
export function validateJSON(json: string | object | undefined): any {
let result; let result;
if (typeof json === 'object') { if (typeof json === 'object') {
return json; return json;
@ -75,7 +74,6 @@ export function validateJSON(json: string | object | undefined): any { // tslint
return result; return result;
} }
export function downloadImage(this: IExecuteFunctions, url: string) { export function downloadImage(this: IExecuteFunctions, url: string) {
return this.helpers.request({ return this.helpers.request({
uri: url, uri: url,

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,4 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -13,10 +10,7 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { asanaApiRequest, getWorkspaces } from './GenericFunctions';
asanaApiRequest,
getWorkspaces,
} from './GenericFunctions';
// import { // import {
// createHmac, // createHmac,
@ -41,9 +35,7 @@ export class AsanaTrigger implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
authentication: [ authentication: ['accessToken'],
'accessToken',
],
}, },
}, },
}, },
@ -52,9 +44,7 @@ export class AsanaTrigger implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
authentication: [ authentication: ['oAuth2'],
'oAuth2',
],
}, },
}, },
}, },
@ -101,7 +91,8 @@ export class AsanaTrigger implements INodeType {
}, },
options: [], options: [],
default: '', default: '',
description: 'The workspace ID the resource is registered under. This is only required if you want to allow overriding existing webhooks. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The workspace ID the resource is registered under. This is only required if you want to allow overriding existing webhooks. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}; };
@ -153,7 +144,10 @@ export class AsanaTrigger implements INodeType {
const webhookUrl = this.getNodeWebhookUrl('default') as string; const webhookUrl = this.getNodeWebhookUrl('default') as string;
if (webhookUrl.includes('%20')) { if (webhookUrl.includes('%20')) {
throw new NodeOperationError(this.getNode(), 'The name of the Asana Trigger Node is not allowed to contain any spaces!'); throw new NodeOperationError(
this.getNode(),
'The name of the Asana Trigger Node is not allowed to contain any spaces!',
);
} }
const resource = this.getNodeParameter('resource') as string; const resource = this.getNodeParameter('resource') as string;
@ -225,8 +219,11 @@ export class AsanaTrigger implements INodeType {
// Is regular webhook call // Is regular webhook call
// Check if it contains any events // Check if it contains any events
if (bodyData.events === undefined || !Array.isArray(bodyData.events) || if (
bodyData.events.length === 0) { bodyData.events === undefined ||
!Array.isArray(bodyData.events) ||
bodyData.events.length === 0
) {
// Does not contain any event data so nothing to process so no reason to // Does not contain any event data so nothing to process so no reason to
// start the workflow // start the workflow
return {}; return {};
@ -245,9 +242,7 @@ export class AsanaTrigger implements INodeType {
// } // }
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(req.body.events)],
this.helpers.returnJsonArray(req.body.events),
],
}; };
} }
} }

View file

@ -1,8 +1,4 @@
import { import { IExecuteFunctions, IHookFunctions, ILoadOptionsFunctions } from 'n8n-core';
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -11,9 +7,7 @@ import {
INodePropertyOptions, INodePropertyOptions,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { get } from 'lodash';
get,
} from 'lodash';
/** /**
* Make an API request to Asana * Make an API request to Asana
@ -24,7 +18,15 @@ import {
* @param {object} body * @param {object} body
* @returns {Promise<any>} * @returns {Promise<any>}
*/ */
export async function asanaApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, body: object, query?: IDataObject, uri?: string | undefined): Promise<any> { // tslint:disable-line:no-any export async function asanaApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
endpoint: string,
body: object,
query?: IDataObject,
uri?: string | undefined,
// tslint:disable-next-line:no-any
): Promise<any> {
const authenticationMethod = this.getNodeParameter('authentication', 0) as string; const authenticationMethod = this.getNodeParameter('authentication', 0) as string;
const options: IHttpRequestOptions = { const options: IHttpRequestOptions = {
@ -40,8 +42,15 @@ export async function asanaApiRequest(this: IHookFunctions | IExecuteFunctions |
return this.helpers.requestWithAuthentication.call(this, credentialType, options); return this.helpers.requestWithAuthentication.call(this, credentialType, options);
} }
export async function asanaApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, method: IHttpRequestMethods, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function asanaApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
method: IHttpRequestMethods,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -52,9 +61,7 @@ export async function asanaApiRequestAllItems(this: IExecuteFunctions | ILoadOpt
responseData = await asanaApiRequest.call(this, method, endpoint, body, query, uri); responseData = await asanaApiRequest.call(this, method, endpoint, body, query, uri);
uri = get(responseData, 'next_page.uri'); uri = get(responseData, 'next_page.uri');
returnData.push.apply(returnData, responseData['data']); returnData.push.apply(returnData, responseData['data']);
} while ( } while (responseData['next_page'] !== null);
responseData['next_page'] !== null
);
return returnData; return returnData;
} }
@ -78,15 +85,18 @@ export async function getWorkspaces(this: ILoadOptionsFunctions): Promise<INodeP
} }
returnData.sort((a, b) => { returnData.sort((a, b) => {
if (a.name < b.name) { return -1; } if (a.name < b.name) {
if (a.name > b.name) { return 1; } return -1;
}
if (a.name > b.name) {
return 1;
}
return 0; return 0;
}); });
return returnData; return returnData;
} }
export function getColorOptions(): INodePropertyOptions[] { export function getColorOptions(): INodePropertyOptions[] {
return [ return [
'dark-blue', 'dark-blue',
@ -108,7 +118,7 @@ export function getColorOptions(): INodePropertyOptions[] {
'light-warm-gray', 'light-warm-gray',
'light-yellow', 'light-yellow',
'none', 'none',
].map(value => { ].map((value) => {
return { return {
name: value, name: value,
value, value,

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -11,20 +9,11 @@ import {
INodeTypeDescription, INodeTypeDescription,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { automizyApiRequest, automizyApiRequestAllItems } from './GenericFunctions';
automizyApiRequest,
automizyApiRequestAllItems,
} from './GenericFunctions';
import { import { contactFields, contactOperations } from './ContactDescription';
contactFields,
contactOperations,
} from './ContactDescription';
import { import { listFields, listOperations } from './ListDescription';
listFields,
listOperations,
} from './ListDescription';
export class Automizy implements INodeType { export class Automizy implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -78,9 +67,7 @@ export class Automizy implements INodeType {
loadOptions: { loadOptions: {
// Get all the tags to display them to user so that he can // Get all the tags to display them to user so that he can
// select them easily // select them easily
async getLists( async getLists(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const lists = await automizyApiRequestAllItems.call( const lists = await automizyApiRequestAllItems.call(
this, this,
@ -96,9 +83,7 @@ export class Automizy implements INodeType {
} }
return returnData; return returnData;
}, },
async getTags( async getTags(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const tags = await automizyApiRequestAllItems.call( const tags = await automizyApiRequestAllItems.call(
this, this,
@ -114,9 +99,7 @@ export class Automizy implements INodeType {
} }
return returnData; return returnData;
}, },
async getCustomFields( async getCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const customFields = await automizyApiRequestAllItems.call( const customFields = await automizyApiRequestAllItems.call(
this, this,
@ -144,9 +127,7 @@ export class Automizy implements INodeType {
const resource = this.getNodeParameter('resource', 0) as string; const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string; const operation = this.getNodeParameter('operation', 0) as string;
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
if (resource === 'contact') { if (resource === 'contact') {
if (operation === 'create') { if (operation === 'create') {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
@ -161,12 +142,12 @@ export class Automizy implements INodeType {
Object.assign(body, additionalFields); Object.assign(body, additionalFields);
if (body.customFieldsUi) { if (body.customFieldsUi) {
const customFieldsValues = (body.customFieldsUi as IDataObject).customFieldsValues as IDataObject[]; const customFieldsValues = (body.customFieldsUi as IDataObject)
.customFieldsValues as IDataObject[];
body.customFields = {}; body.customFields = {};
for (const customField of customFieldsValues) { for (const customField of customFieldsValues) {
//@ts-ignore //@ts-ignore
body.customFields[customField.key] = customField.value; body.customFields[customField.key] = customField.value;
} }
@ -185,11 +166,7 @@ export class Automizy implements INodeType {
if (operation === 'delete') { if (operation === 'delete') {
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'DELETE', `/contacts/${contactId}`);
this,
'DELETE',
`/contacts/${contactId}`,
);
responseData = { success: true }; responseData = { success: true };
} }
@ -197,11 +174,7 @@ export class Automizy implements INodeType {
if (operation === 'get') { if (operation === 'get') {
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'GET', `/contacts/${contactId}`);
this,
'GET',
`/contacts/${contactId}`,
);
} }
if (operation === 'getAll') { if (operation === 'getAll') {
@ -220,7 +193,6 @@ export class Automizy implements INodeType {
} }
if (returnAll) { if (returnAll) {
responseData = await automizyApiRequestAllItems.call( responseData = await automizyApiRequestAllItems.call(
this, this,
'contacts', 'contacts',
@ -229,7 +201,6 @@ export class Automizy implements INodeType {
{}, {},
qs, qs,
); );
} else { } else {
qs.limit = this.getNodeParameter('limit', i) as number; qs.limit = this.getNodeParameter('limit', i) as number;
@ -255,12 +226,12 @@ export class Automizy implements INodeType {
Object.assign(body, updateFields); Object.assign(body, updateFields);
if (body.customFieldsUi) { if (body.customFieldsUi) {
const customFieldsValues = (body.customFieldsUi as IDataObject).customFieldsValues as IDataObject[]; const customFieldsValues = (body.customFieldsUi as IDataObject)
.customFieldsValues as IDataObject[];
body.customFields = {}; body.customFields = {};
for (const customField of customFieldsValues) { for (const customField of customFieldsValues) {
//@ts-ignore //@ts-ignore
body.customFields[customField.key] = customField.value; body.customFields[customField.key] = customField.value;
} }
@ -268,17 +239,11 @@ export class Automizy implements INodeType {
delete body.customFieldsUi; delete body.customFieldsUi;
} }
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'PATCH', `/contacts/${email}`, body);
this,
'PATCH',
`/contacts/${email}`,
body,
);
} }
} }
if (resource === 'list') { if (resource === 'list') {
if (operation === 'create') { if (operation === 'create') {
const name = this.getNodeParameter('name', i) as string; const name = this.getNodeParameter('name', i) as string;
@ -286,22 +251,13 @@ export class Automizy implements INodeType {
name, name,
}; };
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'POST', `/smart-lists`, body);
this,
'POST',
`/smart-lists`,
body,
);
} }
if (operation === 'delete') { if (operation === 'delete') {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'DELETE', `/smart-lists/${listId}`);
this,
'DELETE',
`/smart-lists/${listId}`,
);
responseData = { success: true }; responseData = { success: true };
} }
@ -309,11 +265,7 @@ export class Automizy implements INodeType {
if (operation === 'get') { if (operation === 'get') {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'GET', `/smart-lists/${listId}`);
this,
'GET',
`/smart-lists/${listId}`,
);
} }
if (operation === 'getAll') { if (operation === 'getAll') {
@ -330,7 +282,6 @@ export class Automizy implements INodeType {
} }
if (returnAll) { if (returnAll) {
responseData = await automizyApiRequestAllItems.call( responseData = await automizyApiRequestAllItems.call(
this, this,
'smartLists', 'smartLists',
@ -339,17 +290,10 @@ export class Automizy implements INodeType {
{}, {},
qs, qs,
); );
} else { } else {
qs.limit = this.getNodeParameter('limit', i) as number; qs.limit = this.getNodeParameter('limit', i) as number;
responseData = await automizyApiRequest.call( responseData = await automizyApiRequest.call(this, 'GET', `/smart-lists`, {}, qs);
this,
'GET',
`/smart-lists`,
{},
qs,
);
responseData = responseData.smartLists; responseData = responseData.smartLists;
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactOperations: INodeProperties[] = [ export const contactOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact',
],
}, },
}, },
options: [ options: [
@ -52,7 +48,6 @@ export const contactOperations: INodeProperties[] = [
]; ];
export const contactFields: INodeProperties[] = [ export const contactFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* contact:create */ /* contact:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -64,12 +59,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'name@email.com', placeholder: 'name@email.com',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -80,18 +71,15 @@ export const contactFields: INodeProperties[] = [
name: 'listId', name: 'listId',
required: true, required: true,
type: 'options', type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getLists', loadOptionsMethod: 'getLists',
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -102,12 +90,8 @@ export const contactFields: INodeProperties[] = [
type: 'collection', type: 'collection',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -135,7 +119,8 @@ export const contactFields: INodeProperties[] = [
typeOptions: { typeOptions: {
loadOptionsMethod: 'getCustomFields', loadOptionsMethod: 'getCustomFields',
}, },
description: 'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
default: '', default: '',
}, },
{ {
@ -177,7 +162,8 @@ export const contactFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'The status of the contact. You can only send email to contacts with ACTIVE status.', description:
'The status of the contact. You can only send email to contacts with ACTIVE status.',
}, },
{ {
displayName: 'Tag Names or IDs', displayName: 'Tag Names or IDs',
@ -187,7 +173,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
}, },
default: [], default: [],
description: 'The tags you want to set to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The tags you want to set to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },
@ -202,12 +189,8 @@ export const contactFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -224,12 +207,8 @@ export const contactFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -244,18 +223,15 @@ export const contactFields: INodeProperties[] = [
name: 'listId', name: 'listId',
required: true, required: true,
type: 'options', type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
typeOptions: { typeOptions: {
loadOptionsMethod: 'getLists', loadOptionsMethod: 'getLists',
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -266,12 +242,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: false, default: false,
@ -283,15 +255,9 @@ export const contactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
], returnAll: [false],
resource: [
'contact',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -308,12 +274,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -333,7 +295,8 @@ export const contactFields: INodeProperties[] = [
}, },
], ],
default: 'desc', default: 'desc',
description: 'Defines the direction in which search results are ordered. Default value is DESC. Note: It has to be using with the Sort By parameter', description:
'Defines the direction in which search results are ordered. Default value is DESC. Note: It has to be using with the Sort By parameter',
}, },
{ {
displayName: 'Fields', displayName: 'Fields',
@ -346,7 +309,8 @@ export const contactFields: INodeProperties[] = [
displayName: 'Sort By', displayName: 'Sort By',
name: 'sortBy', name: 'sortBy',
type: 'string', type: 'string',
default: 'Defines the field in which search results are sort by. Note: It has to be using with the Direcction parameter', default:
'Defines the field in which search results are sort by. Note: It has to be using with the Direcction parameter',
}, },
], ],
}, },
@ -362,12 +326,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'name@email.com', placeholder: 'name@email.com',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -378,12 +338,8 @@ export const contactFields: INodeProperties[] = [
type: 'collection', type: 'collection',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -397,7 +353,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
}, },
default: [], default: [],
description: 'The tags you want to add to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The tags you want to add to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Custom Fields', displayName: 'Custom Fields',
@ -421,7 +378,8 @@ export const contactFields: INodeProperties[] = [
typeOptions: { typeOptions: {
loadOptionsMethod: 'getCustomFields', loadOptionsMethod: 'getCustomFields',
}, },
description: 'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The end user specified key of the user defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
default: '', default: '',
}, },
{ {
@ -444,7 +402,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
}, },
default: [], default: [],
description: 'The tags you want to add to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The tags you want to add to the contact. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Status', displayName: 'Status',
@ -473,7 +432,8 @@ export const contactFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'The status of the contact. You can only send email to contacts with ACTIVE status.', description:
'The status of the contact. You can only send email to contacts with ACTIVE status.',
}, },
{ {
displayName: 'Tag Names or IDs', displayName: 'Tag Names or IDs',
@ -483,7 +443,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getTags', loadOptionsMethod: 'getTags',
}, },
default: [], default: [],
description: 'The tags you want to set to the contact. Will replace all existing ones. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The tags you want to set to the contact. Will replace all existing ones. Choose from the list, or specify IDs using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
], ],
}, },

View file

@ -1,24 +1,24 @@
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { IExecuteFunctions, IExecuteSingleFunctions, ILoadOptionsFunctions } from 'n8n-core';
IExecuteFunctions,
IExecuteSingleFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { import { IDataObject, NodeApiError } from 'n8n-workflow';
IDataObject, NodeApiError,
} from 'n8n-workflow';
export async function automizyApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, method: string, path: string, body: any = {}, qs: IDataObject = {}, option = {}): Promise<any> { // tslint:disable-line:no-any export async function automizyApiRequest(
this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
const credentials = await this.getCredentials('automizyApi') as IDataObject; method: string,
path: string,
// tslint:disable-next-line:no-any
body: any = {},
qs: IDataObject = {},
option = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = (await this.getCredentials('automizyApi')) as IDataObject;
const options: OptionsWithUri = { const options: OptionsWithUri = {
headers: { headers: {
'Authorization': `Bearer ${credentials.apiToken}`, Authorization: `Bearer ${credentials.apiToken}`,
}, },
method, method,
body, body,
@ -44,8 +44,16 @@ export async function automizyApiRequest(this: IExecuteFunctions | IExecuteSingl
} }
} }
export async function automizyApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function automizyApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -55,9 +63,7 @@ export async function automizyApiRequestAllItems(this: IExecuteFunctions | ILoad
responseData = await automizyApiRequest.call(this, method, endpoint, body, query); responseData = await automizyApiRequest.call(this, method, endpoint, body, query);
query.page++; query.page++;
returnData.push.apply(returnData, responseData[propertyName]); returnData.push.apply(returnData, responseData[propertyName]);
} while ( } while (responseData.pageCount !== responseData.page);
responseData.pageCount !== responseData.page
);
return returnData; return returnData;
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const listOperations: INodeProperties[] = [ export const listOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const listOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list',
],
}, },
}, },
options: [ options: [
@ -52,7 +48,6 @@ export const listOperations: INodeProperties[] = [
]; ];
export const listFields: INodeProperties[] = [ export const listFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* list:create */ /* list:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -63,12 +58,8 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',
@ -83,17 +74,13 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* list:get */ /* list:get */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
@ -103,12 +90,8 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',
@ -122,12 +105,8 @@ export const listFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: false, default: false,
@ -139,15 +118,9 @@ export const listFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['list'],
], returnAll: [false],
resource: [
'list',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -164,12 +137,8 @@ export const listFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: {}, default: {},
@ -189,7 +158,8 @@ export const listFields: INodeProperties[] = [
}, },
], ],
default: 'desc', default: 'desc',
description: 'Defines the direction in which search results are ordered. Default value is DESC. Note: It has to be using with the Sort By parameter', description:
'Defines the direction in which search results are ordered. Default value is DESC. Note: It has to be using with the Sort By parameter',
}, },
{ {
displayName: 'Fields', displayName: 'Fields',
@ -202,7 +172,8 @@ export const listFields: INodeProperties[] = [
displayName: 'Sort By', displayName: 'Sort By',
name: 'sortBy', name: 'sortBy',
type: 'string', type: 'string',
default: 'Defines the field in which search results are sort by. Note: It has to be using with the Direcction parameter', default:
'Defines the field in which search results are sort by. Note: It has to be using with the Direcction parameter',
}, },
], ],
}, },
@ -216,12 +187,8 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',
@ -233,12 +200,8 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['update'],
'update', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -11,30 +9,15 @@ import {
INodeTypeDescription, INodeTypeDescription,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { autopilotApiRequest, autopilotApiRequestAllItems } from './GenericFunctions';
autopilotApiRequest,
autopilotApiRequestAllItems,
} from './GenericFunctions';
import { import { contactFields, contactOperations } from './ContactDescription';
contactFields,
contactOperations,
} from './ContactDescription';
import { import { contactJourneyFields, contactJourneyOperations } from './ContactJourneyDescription';
contactJourneyFields,
contactJourneyOperations,
} from './ContactJourneyDescription';
import { import { contactListFields, contactListOperations } from './ContactListDescription';
contactListFields,
contactListOperations,
} from './ContactListDescription';
import { import { listFields, listOperations } from './ListDescription';
listFields,
listOperations,
} from './ListDescription';
export class Autopilot implements INodeType { export class Autopilot implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -96,15 +79,9 @@ export class Autopilot implements INodeType {
methods = { methods = {
loadOptions: { loadOptions: {
async getCustomFields( async getCustomFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const customFields = await autopilotApiRequest.call( const customFields = await autopilotApiRequest.call(this, 'GET', '/contacts/custom_fields');
this,
'GET',
'/contacts/custom_fields',
);
for (const customField of customFields) { for (const customField of customFields) {
returnData.push({ returnData.push({
name: customField.name, name: customField.name,
@ -113,15 +90,9 @@ export class Autopilot implements INodeType {
} }
return returnData; return returnData;
}, },
async getLists( async getLists(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const { lists } = await autopilotApiRequest.call( const { lists } = await autopilotApiRequest.call(this, 'GET', '/lists');
this,
'GET',
'/lists',
);
for (const list of lists) { for (const list of lists) {
returnData.push({ returnData.push({
name: list.title, name: list.title,
@ -130,15 +101,9 @@ export class Autopilot implements INodeType {
} }
return returnData; return returnData;
}, },
async getTriggers( async getTriggers(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
this: ILoadOptionsFunctions,
): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = []; const returnData: INodePropertyOptions[] = [];
const { triggers } = await autopilotApiRequest.call( const { triggers } = await autopilotApiRequest.call(this, 'GET', '/triggers');
this,
'GET',
'/triggers',
);
for (const trigger of triggers) { for (const trigger of triggers) {
returnData.push({ returnData.push({
name: trigger.journey, name: trigger.journey,
@ -173,7 +138,8 @@ export class Autopilot implements INodeType {
Object.assign(body, additionalFields); Object.assign(body, additionalFields);
if (body.customFieldsUi) { if (body.customFieldsUi) {
const customFieldsValues = (body.customFieldsUi as IDataObject).customFieldsValues as IDataObject[]; const customFieldsValues = (body.customFieldsUi as IDataObject)
.customFieldsValues as IDataObject[];
body.custom = {}; body.custom = {};
@ -203,22 +169,15 @@ export class Autopilot implements INodeType {
delete body.newEmail; delete body.newEmail;
} }
responseData = await autopilotApiRequest.call( responseData = await autopilotApiRequest.call(this, 'POST', `/contact`, {
this, contact: body,
'POST', });
`/contact`,
{ contact: body },
);
} }
if (operation === 'delete') { if (operation === 'delete') {
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
responseData = await autopilotApiRequest.call( responseData = await autopilotApiRequest.call(this, 'DELETE', `/contact/${contactId}`);
this,
'DELETE',
`/contact/${contactId}`,
);
responseData = { success: true }; responseData = { success: true };
} }
@ -226,11 +185,7 @@ export class Autopilot implements INodeType {
if (operation === 'get') { if (operation === 'get') {
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
responseData = await autopilotApiRequest.call( responseData = await autopilotApiRequest.call(this, 'GET', `/contact/${contactId}`);
this,
'GET',
`/contact/${contactId}`,
);
} }
if (operation === 'getAll') { if (operation === 'getAll') {
@ -255,7 +210,6 @@ export class Autopilot implements INodeType {
} }
if (resource === 'contactJourney') { if (resource === 'contactJourney') {
if (operation === 'add') { if (operation === 'add') {
const triggerId = this.getNodeParameter('triggerId', i) as string; const triggerId = this.getNodeParameter('triggerId', i) as string;
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
@ -271,15 +225,14 @@ export class Autopilot implements INodeType {
} }
if (resource === 'contactList') { if (resource === 'contactList') {
if (['add', 'remove', 'exist'].includes(operation)) { if (['add', 'remove', 'exist'].includes(operation)) {
const listId = this.getNodeParameter('listId', i) as string; const listId = this.getNodeParameter('listId', i) as string;
const contactId = this.getNodeParameter('contactId', i) as string; const contactId = this.getNodeParameter('contactId', i) as string;
const method: { [key: string]: string } = { const method: { [key: string]: string } = {
'add': 'POST', add: 'POST',
'remove': 'DELETE', remove: 'DELETE',
'exist': 'GET', exist: 'GET',
}; };
const endpoint = `/list/${listId}/contact/${contactId}`; const endpoint = `/list/${listId}/contact/${contactId}`;
@ -321,19 +274,13 @@ export class Autopilot implements INodeType {
} }
if (resource === 'list') { if (resource === 'list') {
if (operation === 'create') { if (operation === 'create') {
const name = this.getNodeParameter('name', i) as string; const name = this.getNodeParameter('name', i) as string;
const body: IDataObject = { const body: IDataObject = {
name, name,
}; };
responseData = await autopilotApiRequest.call( responseData = await autopilotApiRequest.call(this, 'POST', `/list`, body);
this,
'POST',
`/list`,
body,
);
} }
if (operation === 'getAll') { if (operation === 'getAll') {
@ -342,11 +289,7 @@ export class Autopilot implements INodeType {
if (returnAll === false) { if (returnAll === false) {
qs.limit = this.getNodeParameter('limit', i) as number; qs.limit = this.getNodeParameter('limit', i) as number;
} }
responseData = await autopilotApiRequest.call( responseData = await autopilotApiRequest.call(this, 'GET', '/lists');
this,
'GET',
'/lists',
);
responseData = responseData.lists; responseData = responseData.lists;
@ -361,9 +304,7 @@ export class Autopilot implements INodeType {
} else if (responseData !== undefined) { } else if (responseData !== undefined) {
returnData.push(responseData as IDataObject); returnData.push(responseData as IDataObject);
} }
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ error: error.toString() }); returnData.push({ error: error.toString() });
continue; continue;

View file

@ -1,22 +1,10 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeType, INodeTypeDescription, IWebhookResponseData } from 'n8n-workflow';
IDataObject,
INodeType,
INodeTypeDescription,
IWebhookResponseData,
} from 'n8n-workflow';
import { import { autopilotApiRequest } from './GenericFunctions';
autopilotApiRequest,
} from './GenericFunctions';
import { import { snakeCase } from 'change-case';
snakeCase,
} from 'change-case';
export class AutopilotTrigger implements INodeType { export class AutopilotTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -131,9 +119,7 @@ export class AutopilotTrigger implements INodeType {
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> { async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const req = this.getRequestObject(); const req = this.getRequestObject();
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(req.body)],
this.helpers.returnJsonArray(req.body),
],
}; };
} }
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactOperations: INodeProperties[] = [ export const contactOperations: INodeProperties[] = [
{ {
@ -10,16 +8,15 @@ export const contactOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contact'],
'contact',
],
}, },
}, },
options: [ options: [
{ {
name: 'Create or Update', name: 'Create or Update',
value: 'upsert', value: 'upsert',
description: 'Create a new contact, or update the current one if it already exists (upsert)', description:
'Create a new contact, or update the current one if it already exists (upsert)',
action: 'Create or Update a contact', action: 'Create or Update a contact',
}, },
{ {
@ -46,7 +43,6 @@ export const contactOperations: INodeProperties[] = [
]; ];
export const contactFields: INodeProperties[] = [ export const contactFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* contact:upsert */ /* contact:upsert */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -58,12 +54,8 @@ export const contactFields: INodeProperties[] = [
placeholder: 'name@email.com', placeholder: 'name@email.com',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upsert'],
'upsert', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -75,12 +67,8 @@ export const contactFields: INodeProperties[] = [
type: 'collection', type: 'collection',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upsert'],
'upsert', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: {}, default: {},
@ -114,7 +102,8 @@ export const contactFields: INodeProperties[] = [
typeOptions: { typeOptions: {
loadOptionsMethod: 'getCustomFields', loadOptionsMethod: 'getCustomFields',
}, },
description: 'User-specified key of user-defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'User-specified key of user-defined data. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
default: '', default: '',
}, },
{ {
@ -172,7 +161,8 @@ export const contactFields: INodeProperties[] = [
loadOptionsMethod: 'getLists', loadOptionsMethod: 'getLists',
}, },
default: '', default: '',
description: 'List to which this contact will be added on creation. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'List to which this contact will be added on creation. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Mailing Country', displayName: 'Mailing Country',
@ -215,7 +205,8 @@ export const contactFields: INodeProperties[] = [
name: 'newEmail', name: 'newEmail',
type: 'string', type: 'string',
default: '', default: '',
description: 'If provided, will change the email address of the contact identified by the Email field', description:
'If provided, will change the email address of the contact identified by the Email field',
}, },
{ {
displayName: 'Notify', displayName: 'Notify',
@ -223,7 +214,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
default: true, default: true,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default Autopilot notifies registered REST hook endpoints for contact_added/contact_updated events when a new contact is added or an existing contact is updated via API. Disable to skip notifications.', description:
'By default Autopilot notifies registered REST hook endpoints for contact_added/contact_updated events when a new contact is added or an existing contact is updated via API. Disable to skip notifications.',
}, },
{ {
displayName: 'Number of Employees', displayName: 'Number of Employees',
@ -294,12 +286,8 @@ export const contactFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['delete'],
'delete', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -316,12 +304,8 @@ export const contactFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: '', default: '',
@ -337,12 +321,8 @@ export const contactFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
],
resource: [
'contact',
],
}, },
}, },
default: false, default: false,
@ -354,15 +334,9 @@ export const contactFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contact'],
], returnAll: [false],
resource: [
'contact',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactJourneyOperations: INodeProperties[] = [ export const contactJourneyOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactJourneyOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contactJourney'],
'contactJourney',
],
}, },
}, },
options: [ options: [
@ -28,7 +24,6 @@ export const contactJourneyOperations: INodeProperties[] = [
]; ];
export const contactJourneyFields: INodeProperties[] = [ export const contactJourneyFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* contactJourney:add */ /* contactJourney:add */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -42,16 +37,13 @@ export const contactJourneyFields: INodeProperties[] = [
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactJourney'],
],
resource: [
'contactJourney',
],
}, },
}, },
default: '', default: '',
description: 'List ID. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'List ID. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Contact ID', displayName: 'Contact ID',
@ -60,12 +52,8 @@ export const contactJourneyFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add'],
'add', resource: ['contactJourney'],
],
resource: [
'contactJourney',
],
}, },
}, },
default: '', default: '',

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const contactListOperations: INodeProperties[] = [ export const contactListOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const contactListOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['contactList'],
'contactList',
],
}, },
}, },
options: [ options: [
@ -46,7 +42,6 @@ export const contactListOperations: INodeProperties[] = [
]; ];
export const contactListFields: INodeProperties[] = [ export const contactListFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* contactList:add */ /* contactList:add */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -60,19 +55,13 @@ export const contactListFields: INodeProperties[] = [
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add', 'remove', 'exist', 'getAll'],
'add', resource: ['contactList'],
'remove',
'exist',
'getAll',
],
resource: [
'contactList',
],
}, },
}, },
default: '', default: '',
description: 'ID of the list to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'ID of the list to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Contact ID', displayName: 'Contact ID',
@ -81,14 +70,8 @@ export const contactListFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['add', 'remove', 'exist'],
'add', resource: ['contactList'],
'remove',
'exist',
],
resource: [
'contactList',
],
}, },
}, },
default: '', default: '',
@ -104,12 +87,8 @@ export const contactListFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contactList'],
],
resource: [
'contactList',
],
}, },
}, },
default: false, default: false,
@ -121,15 +100,9 @@ export const contactListFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['contactList'],
], returnAll: [false],
resource: [
'contactList',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {

View file

@ -1,22 +1,21 @@
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { IExecuteFunctions, ILoadOptionsFunctions } from 'n8n-core';
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import { import { IDataObject, IHookFunctions, IWebhookFunctions, NodeApiError } from 'n8n-workflow';
IDataObject,
IHookFunctions,
IWebhookFunctions,
NodeApiError,
} from 'n8n-workflow';
export async function autopilotApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function autopilotApiRequest(
this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions,
const credentials = await this.getCredentials('autopilotApi') as IDataObject; method: string,
resource: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
uri?: string,
option: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = (await this.getCredentials('autopilotApi')) as IDataObject;
const apiKey = `${credentials.apiKey}`; const apiKey = `${credentials.apiKey}`;
@ -47,8 +46,16 @@ export async function autopilotApiRequest(this: IExecuteFunctions | IWebhookFunc
} }
} }
export async function autopilotApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any export async function autopilotApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
method: string,
endpoint: string,
// tslint:disable-next-line:no-any
body: any = {},
query: IDataObject = {},
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean; const returnAll = this.getNodeParameter('returnAll', 0, false) as boolean;
@ -62,8 +69,6 @@ export async function autopilotApiRequestAllItems(this: IExecuteFunctions | ILoa
if (query.limit && returnData.length >= query.limit && returnAll === false) { if (query.limit && returnData.length >= query.limit && returnAll === false) {
return returnData; return returnData;
} }
} while ( } while (responseData.bookmark !== undefined);
responseData.bookmark !== undefined
);
return returnData; return returnData;
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const listOperations: INodeProperties[] = [ export const listOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const listOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['list'],
'list',
],
}, },
}, },
options: [ options: [
@ -34,7 +30,6 @@ export const listOperations: INodeProperties[] = [
]; ];
export const listFields: INodeProperties[] = [ export const listFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* list:create */ /* list:create */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
@ -45,12 +40,8 @@ export const listFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: '', default: '',
@ -66,12 +57,8 @@ export const listFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['list'],
],
resource: [
'list',
],
}, },
}, },
default: false, default: false,
@ -83,15 +70,9 @@ export const listFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['list'],
], returnAll: [false],
resource: [
'list',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {

View file

@ -58,15 +58,14 @@ export class AwsLambda implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['invoke'],
'invoke',
],
}, },
}, },
options: [], options: [],
default: '', default: '',
required: true, required: true,
description: 'The function you want to invoke. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The function you want to invoke. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Qualifier', displayName: 'Qualifier',
@ -74,9 +73,7 @@ export class AwsLambda implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['invoke'],
'invoke',
],
}, },
}, },
required: true, required: true,
@ -101,9 +98,7 @@ export class AwsLambda implements INodeType {
], ],
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['invoke'],
'invoke',
],
}, },
}, },
default: 'RequestResponse', default: 'RequestResponse',
@ -115,9 +110,7 @@ export class AwsLambda implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['invoke'],
'invoke',
],
}, },
}, },
default: '', default: '',
@ -145,7 +138,12 @@ export class AwsLambda implements INodeType {
if (data.NextMarker) { if (data.NextMarker) {
let marker: string = data.NextMarker; let marker: string = data.NextMarker;
while (true) { while (true) {
const dataLoop = await awsApiRequestREST.call(this, 'lambda', 'GET', `/2015-03-31/functions/?MaxItems=50&Marker=${encodeURIComponent(marker)}`); const dataLoop = await awsApiRequestREST.call(
this,
'lambda',
'GET',
`/2015-03-31/functions/?MaxItems=50&Marker=${encodeURIComponent(marker)}`,
);
for (const func of dataLoop.Functions!) { for (const func of dataLoop.Functions!) {
returnData.push({ returnData.push({
@ -167,7 +165,6 @@ export class AwsLambda implements INodeType {
}, },
}; };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData(); const items = this.getInputData();
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];

View file

@ -57,15 +57,14 @@ export class AwsSns implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['publish'],
'publish',
],
}, },
}, },
options: [], options: [],
default: '', default: '',
required: true, required: true,
description: 'The topic you want to publish to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'The topic you want to publish to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Subject', displayName: 'Subject',
@ -73,9 +72,7 @@ export class AwsSns implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['publish'],
'publish',
],
}, },
}, },
default: '', default: '',
@ -88,9 +85,7 @@ export class AwsSns implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['publish'],
'publish',
],
}, },
}, },
required: true, required: true,
@ -134,7 +129,6 @@ export class AwsSns implements INodeType {
}, },
}; };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData(); const items = this.getInputData();
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
@ -142,14 +136,20 @@ export class AwsSns implements INodeType {
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
try { try {
const params = [ const params = [
'TopicArn=' + this.getNodeParameter('topic', i) as string, ('TopicArn=' + this.getNodeParameter('topic', i)) as string,
'Subject=' + this.getNodeParameter('subject', i) as string, ('Subject=' + this.getNodeParameter('subject', i)) as string,
'Message=' + this.getNodeParameter('message', i) as string, ('Message=' + this.getNodeParameter('message', i)) as string,
]; ];
const responseData = await awsApiRequestSOAP.call(
const responseData = await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=Publish&' + params.join('&')); this,
returnData.push({MessageId: responseData.PublishResponse.PublishResult.MessageId} as IDataObject); 'sns',
'GET',
'/?Action=Publish&' + params.join('&'),
);
returnData.push({
MessageId: responseData.PublishResponse.PublishResult.MessageId,
} as IDataObject);
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ error: error.message }); returnData.push({ error: error.message });

View file

@ -1,7 +1,4 @@
import { import { IHookFunctions, IWebhookFunctions } from 'n8n-core';
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import { import {
ILoadOptionsFunctions, ILoadOptionsFunctions,
@ -13,13 +10,9 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { awsApiRequestSOAP } from './GenericFunctions';
awsApiRequestSOAP,
} from './GenericFunctions';
import { import { get } from 'lodash';
get,
} from 'lodash';
export class AwsSnsTrigger implements INodeType { export class AwsSnsTrigger implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -54,7 +47,8 @@ export class AwsSnsTrigger implements INodeType {
displayName: 'Topic Name or ID', displayName: 'Topic Name or ID',
name: 'topic', name: 'topic',
type: 'options', type: 'options',
description: 'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>', description:
'Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>',
required: true, required: true,
typeOptions: { typeOptions: {
loadOptionsMethod: 'getTopics', loadOptionsMethod: 'getTopics',
@ -102,12 +96,17 @@ export class AwsSnsTrigger implements INodeType {
if (webhookData.webhookId === undefined) { if (webhookData.webhookId === undefined) {
return false; return false;
} }
const params = [ const params = [`TopicArn=${topic}`, 'Version=2010-03-31'];
`TopicArn=${topic}`, const data = await awsApiRequestSOAP.call(
'Version=2010-03-31', this,
]; 'sns',
const data = await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=ListSubscriptionsByTopic&' + params.join('&')); 'GET',
const subscriptions = get(data, 'ListSubscriptionsByTopicResponse.ListSubscriptionsByTopicResult.Subscriptions'); '/?Action=ListSubscriptionsByTopic&' + params.join('&'),
);
const subscriptions = get(
data,
'ListSubscriptionsByTopicResponse.ListSubscriptionsByTopicResult.Subscriptions',
);
if (!subscriptions || !subscriptions.member) { if (!subscriptions || !subscriptions.member) {
return false; return false;
} }
@ -131,7 +130,10 @@ export class AwsSnsTrigger implements INodeType {
const topic = this.getNodeParameter('topic') as string; const topic = this.getNodeParameter('topic') as string;
if (webhookUrl.includes('%20')) { if (webhookUrl.includes('%20')) {
throw new NodeOperationError(this.getNode(), 'The name of the SNS Trigger Node is not allowed to contain any spaces!'); throw new NodeOperationError(
this.getNode(),
'The name of the SNS Trigger Node is not allowed to contain any spaces!',
);
} }
const params = [ const params = [
@ -142,20 +144,27 @@ export class AwsSnsTrigger implements INodeType {
'Version=2010-03-31', 'Version=2010-03-31',
]; ];
const { SubscribeResponse } = await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=Subscribe&' + params.join('&')); const { SubscribeResponse } = await awsApiRequestSOAP.call(
this,
'sns',
'GET',
'/?Action=Subscribe&' + params.join('&'),
);
webhookData.webhookId = SubscribeResponse.SubscribeResult.SubscriptionArn; webhookData.webhookId = SubscribeResponse.SubscribeResult.SubscriptionArn;
return true; return true;
}, },
async delete(this: IHookFunctions): Promise<boolean> { async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node'); const webhookData = this.getWorkflowStaticData('node');
const params = [ const params = [`SubscriptionArn=${webhookData.webhookId}`, 'Version=2010-03-31'];
`SubscriptionArn=${webhookData.webhookId}`,
'Version=2010-03-31',
];
try { try {
await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=Unsubscribe&' + params.join('&')); await awsApiRequestSOAP.call(
} catch(error) { this,
'sns',
'GET',
'/?Action=Unsubscribe&' + params.join('&'),
);
} catch (error) {
return false; return false;
} }
delete webhookData.webhookId; delete webhookData.webhookId;
@ -169,17 +178,17 @@ export class AwsSnsTrigger implements INodeType {
const topic = this.getNodeParameter('topic') as string; const topic = this.getNodeParameter('topic') as string;
// @ts-ignore // @ts-ignore
const body = JSON.parse((req.rawBody).toString()); const body = JSON.parse(req.rawBody.toString());
if (body.Type === 'SubscriptionConfirmation' && if (body.Type === 'SubscriptionConfirmation' && body.TopicArn === topic) {
body.TopicArn === topic) {
const { Token } = body; const { Token } = body;
const params = [ const params = [`TopicArn=${topic}`, `Token=${Token}`, 'Version=2010-03-31'];
`TopicArn=${topic}`, await awsApiRequestSOAP.call(
`Token=${Token}`, this,
'Version=2010-03-31', 'sns',
]; 'GET',
await awsApiRequestSOAP.call(this, 'sns', 'GET', '/?Action=ConfirmSubscription&' + params.join('&')); '/?Action=ConfirmSubscription&' + params.join('&'),
);
return { return {
noWebhookResponse: true, noWebhookResponse: true,
@ -192,9 +201,7 @@ export class AwsSnsTrigger implements INodeType {
//TODO verify message signature //TODO verify message signature
return { return {
workflowData: [ workflowData: [this.helpers.returnJsonArray(body)],
this.helpers.returnJsonArray(body),
],
}; };
} }
} }

View file

@ -1,17 +1,8 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { import { awsApiRequestREST } from './GenericFunctions';
awsApiRequestREST,
} from './GenericFunctions';
export class AwsComprehend implements INodeType { export class AwsComprehend implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -132,13 +123,8 @@ export class AwsComprehend implements INodeType {
default: 'en', default: 'en',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['text'],
'text', operation: ['detectSentiment', 'detectEntities'],
],
operation: [
'detectSentiment',
'detectEntities',
],
}, },
}, },
description: 'The language code for text', description: 'The language code for text',
@ -153,9 +139,7 @@ export class AwsComprehend implements INodeType {
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['text'],
'text',
],
}, },
}, },
description: 'The text to send', description: 'The text to send',
@ -166,16 +150,13 @@ export class AwsComprehend implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['text'],
'text', operation: ['detectDominantLanguage'],
],
operation: [
'detectDominantLanguage',
],
}, },
}, },
default: true, default: true,
description: 'Whether to return a simplified version of the response instead of the raw data', description:
'Whether to return a simplified version of the response instead of the raw data',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -184,12 +165,8 @@ export class AwsComprehend implements INodeType {
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['text'],
'text', operation: ['detectEntities'],
],
operation: [
'detectEntities',
],
}, },
}, },
default: {}, default: {},
@ -202,7 +179,8 @@ export class AwsComprehend implements INodeType {
alwaysOpenEditWindow: true, alwaysOpenEditWindow: true,
}, },
default: '', default: '',
description: 'The Amazon Resource Name of an endpoint that is associated with a custom entity recognition model', description:
'The Amazon Resource Name of an endpoint that is associated with a custom entity recognition model',
}, },
], ],
}, },
@ -227,13 +205,23 @@ export class AwsComprehend implements INodeType {
Text: text, Text: text,
}; };
const action = 'Comprehend_20171127.DetectDominantLanguage'; const action = 'Comprehend_20171127.DetectDominantLanguage';
responseData = await awsApiRequestREST.call(this, 'comprehend', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
if (simple === true) { if (simple === true) {
responseData = responseData.Languages.reduce((accumulator: { [key: string]: number }, currentValue: IDataObject) => { responseData = responseData.Languages.reduce(
accumulator[currentValue.LanguageCode as string] = currentValue.Score as number; (accumulator: { [key: string]: number }, currentValue: IDataObject) => {
return accumulator; accumulator[currentValue.LanguageCode as string] = currentValue.Score as number;
}, {}); return accumulator;
},
{},
);
} }
} }
@ -246,7 +234,14 @@ export class AwsComprehend implements INodeType {
Text: text, Text: text,
LanguageCode: languageCode, LanguageCode: languageCode,
}; };
responseData = await awsApiRequestREST.call(this, 'comprehend', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
} }
//https://docs.aws.amazon.com/comprehend/latest/dg/API_DetectEntities.html //https://docs.aws.amazon.com/comprehend/latest/dg/API_DetectEntities.html
@ -265,7 +260,14 @@ export class AwsComprehend implements INodeType {
body.EndpointArn = additionalFields.endpointArn; body.EndpointArn = additionalFields.endpointArn;
} }
responseData = await awsApiRequestREST.call(this, 'comprehend', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'comprehend',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = responseData.Entities; responseData = responseData.Entities;
} }
} }

View file

@ -1,19 +1,10 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { parseString } from 'xml2js';
parseString,
} from 'xml2js';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -22,11 +13,12 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { ICredentialDataDecryptedObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
ICredentialDataDecryptedObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string { function getEndpointForService(
service: string,
credentials: ICredentialDataDecryptedObject,
): string {
let endpoint; let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) { if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint; endpoint = credentials.lambdaEndpoint;
@ -38,7 +30,15 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr
return (endpoint as string).replace('{region}', credentials.region as string); return (endpoint as string).replace('{region}', credentials.region as string);
} }
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
@ -49,7 +49,9 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -68,7 +70,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return JSON.parse(response); return JSON.parse(response);
@ -77,7 +87,15 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {

View file

@ -1,7 +1,5 @@
/* eslint-disable n8n-nodes-base/node-filename-against-convention */ /* eslint-disable n8n-nodes-base/node-filename-against-convention */
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -12,15 +10,9 @@ import {
NodeParameterValue, NodeParameterValue,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { awsApiRequest, awsApiRequestAllItems } from './GenericFunctions';
awsApiRequest,
awsApiRequestAllItems,
} from './GenericFunctions';
import { import { itemFields, itemOperations } from './ItemDescription';
itemFields,
itemOperations,
} from './ItemDescription';
import { import {
FieldsUiValues, FieldsUiValues,
@ -102,22 +94,30 @@ export class AwsDynamoDB implements INodeType {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
try { try {
if (resource === 'item') { if (resource === 'item') {
if (operation === 'upsert') { if (operation === 'upsert') {
// ---------------------------------- // ----------------------------------
// upsert // upsert
// ---------------------------------- // ----------------------------------
// https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
const eavUi = this.getNodeParameter('additionalFields.eavUi.eavValues', i, []) as IAttributeValueUi[]; const eavUi = this.getNodeParameter(
const conditionExpession = this.getNodeParameter('conditionExpression', i, '') as string; 'additionalFields.eavUi.eavValues',
const eanUi = this.getNodeParameter('additionalFields.eanUi.eanValues', i, []) as IAttributeNameUi[]; i,
[],
) as IAttributeValueUi[];
const conditionExpession = this.getNodeParameter(
'conditionExpression',
i,
'',
) as string;
const eanUi = this.getNodeParameter(
'additionalFields.eanUi.eanValues',
i,
[],
) as IAttributeNameUi[];
const body: IRequestBody = { const body: IRequestBody = {
TableName: this.getNodeParameter('tableName', i) as string, TableName: this.getNodeParameter('tableName', i) as string,
@ -139,14 +139,15 @@ export class AwsDynamoDB implements INodeType {
body.ConditionExpression = conditionExpession; body.ConditionExpression = conditionExpession;
} }
const dataToSend = this.getNodeParameter('dataToSend', 0) as 'defineBelow' | 'autoMapInputData'; const dataToSend = this.getNodeParameter('dataToSend', 0) as
| 'defineBelow'
| 'autoMapInputData';
const item: { [key: string]: string } = {}; const item: { [key: string]: string } = {};
if (dataToSend === 'autoMapInputData') { if (dataToSend === 'autoMapInputData') {
const incomingKeys = Object.keys(items[i].json); const incomingKeys = Object.keys(items[i].json);
const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string; const rawInputsToIgnore = this.getNodeParameter('inputsToIgnore', i) as string;
const inputsToIgnore = rawInputsToIgnore.split(',').map(c => c.trim()); const inputsToIgnore = rawInputsToIgnore.split(',').map((c) => c.trim());
for (const key of incomingKeys) { for (const key of incomingKeys) {
if (inputsToIgnore.includes(key)) continue; if (inputsToIgnore.includes(key)) continue;
@ -154,13 +155,10 @@ export class AwsDynamoDB implements INodeType {
} }
body.Item = adjustPutItem(item as PutItemUi); body.Item = adjustPutItem(item as PutItemUi);
} else { } else {
const fields = this.getNodeParameter('fieldsUi.fieldValues', i, []) as FieldsUiValues; const fields = this.getNodeParameter('fieldsUi.fieldValues', i, []) as FieldsUiValues;
fields.forEach(({ fieldId, fieldValue }) => item[fieldId] = fieldValue); fields.forEach(({ fieldId, fieldValue }) => (item[fieldId] = fieldValue));
body.Item = adjustPutItem(item as PutItemUi); body.Item = adjustPutItem(item as PutItemUi);
} }
const headers = { const headers = {
@ -170,9 +168,7 @@ export class AwsDynamoDB implements INodeType {
responseData = await awsApiRequest.call(this, 'dynamodb', 'POST', '/', body, headers); responseData = await awsApiRequest.call(this, 'dynamodb', 'POST', '/', body, headers);
responseData = item; responseData = item;
} else if (operation === 'delete') { } else if (operation === 'delete') {
// ---------------------------------- // ----------------------------------
// delete // delete
// ---------------------------------- // ----------------------------------
@ -186,12 +182,22 @@ export class AwsDynamoDB implements INodeType {
ReturnValues: this.getNodeParameter('returnValues', 0) as string, ReturnValues: this.getNodeParameter('returnValues', 0) as string,
}; };
const eavUi = this.getNodeParameter('additionalFields.eavUi.eavValues', i, []) as IAttributeValueUi[]; const eavUi = this.getNodeParameter(
const eanUi = this.getNodeParameter('additionalFields.eanUi.eanValues', i, []) as IAttributeNameUi[]; 'additionalFields.eavUi.eavValues',
i,
[],
) as IAttributeValueUi[];
const eanUi = this.getNodeParameter(
'additionalFields.eanUi.eanValues',
i,
[],
) as IAttributeNameUi[];
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const simple = this.getNodeParameter('simple', 0, false) as boolean; const simple = this.getNodeParameter('simple', 0, false) as boolean;
const items = this.getNodeParameter('keysUi.keyValues', i, []) as [{ key: string, type: string, value: string }]; const items = this.getNodeParameter('keysUi.keyValues', i, []) as [
{ key: string; type: string; value: string },
];
for (const item of items) { for (const item of items) {
let value = item.value as NodeParameterValue; let value = item.value as NodeParameterValue;
@ -229,9 +235,7 @@ export class AwsDynamoDB implements INodeType {
} else if (simple === true) { } else if (simple === true) {
responseData = decodeItem(responseData.Attributes); responseData = decodeItem(responseData.Attributes);
} }
} else if (operation === 'get') { } else if (operation === 'get') {
// ---------------------------------- // ----------------------------------
// get // get
// ---------------------------------- // ----------------------------------
@ -242,7 +246,11 @@ export class AwsDynamoDB implements INodeType {
const simple = this.getNodeParameter('simple', 0, false) as boolean; const simple = this.getNodeParameter('simple', 0, false) as boolean;
const select = this.getNodeParameter('select', 0) as string; const select = this.getNodeParameter('select', 0) as string;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const eanUi = this.getNodeParameter('additionalFields.eanUi.eanValues', i, []) as IAttributeNameUi[]; const eanUi = this.getNodeParameter(
'additionalFields.eanUi.eanValues',
i,
[],
) as IAttributeNameUi[];
// tslint:disable-next-line: no-any // tslint:disable-next-line: no-any
const body: { [key: string]: any } = { const body: { [key: string]: any } = {
@ -289,9 +297,7 @@ export class AwsDynamoDB implements INodeType {
if (simple && responseData) { if (simple && responseData) {
responseData = decodeItem(responseData); responseData = decodeItem(responseData);
} }
} else if (operation === 'getAll') { } else if (operation === 'getAll') {
// ---------------------------------- // ----------------------------------
// getAll // getAll
// ---------------------------------- // ----------------------------------
@ -303,7 +309,11 @@ export class AwsDynamoDB implements INodeType {
const select = this.getNodeParameter('select', 0) as string; const select = this.getNodeParameter('select', 0) as string;
const returnAll = this.getNodeParameter('returnAll', 0) as boolean; const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const scan = this.getNodeParameter('scan', 0) as boolean; const scan = this.getNodeParameter('scan', 0) as boolean;
const eanUi = this.getNodeParameter('options.eanUi.eanValues', i, []) as IAttributeNameUi[]; const eanUi = this.getNodeParameter(
'options.eanUi.eanValues',
i,
[],
) as IAttributeNameUi[];
const body: IRequestBody = { const body: IRequestBody = {
TableName: this.getNodeParameter('tableName', i) as string, TableName: this.getNodeParameter('tableName', i) as string,
@ -315,14 +325,16 @@ export class AwsDynamoDB implements INodeType {
body['FilterExpression'] = filterExpression; body['FilterExpression'] = filterExpression;
} }
} else { } else {
body['KeyConditionExpression'] = this.getNodeParameter('keyConditionExpression', i) as string; body['KeyConditionExpression'] = this.getNodeParameter(
'keyConditionExpression',
i,
) as string;
} }
const { const { indexName, projectionExpression, filterExpression } = this.getNodeParameter(
indexName, 'options',
projectionExpression, i,
filterExpression, ) as {
} = this.getNodeParameter('options', i) as {
indexName: string; indexName: string;
projectionExpression: string; projectionExpression: string;
filterExpression: string; filterExpression: string;
@ -358,11 +370,18 @@ export class AwsDynamoDB implements INodeType {
const headers = { const headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Amz-Target': (scan) ? 'DynamoDB_20120810.Scan' : 'DynamoDB_20120810.Query', 'X-Amz-Target': scan ? 'DynamoDB_20120810.Scan' : 'DynamoDB_20120810.Query',
}; };
if (returnAll === true && select !== 'COUNT') { if (returnAll === true && select !== 'COUNT') {
responseData = await awsApiRequestAllItems.call(this, 'dynamodb', 'POST', '/', body, headers); responseData = await awsApiRequestAllItems.call(
this,
'dynamodb',
'POST',
'/',
body,
headers,
);
} else { } else {
body.Limit = this.getNodeParameter('limit', 0, 1) as number; body.Limit = this.getNodeParameter('limit', 0, 1) as number;
responseData = await awsApiRequest.call(this, 'dynamodb', 'POST', '/', body, headers); responseData = await awsApiRequest.call(this, 'dynamodb', 'POST', '/', body, headers);
@ -373,14 +392,12 @@ export class AwsDynamoDB implements INodeType {
if (simple === true) { if (simple === true) {
responseData = responseData.map(simplify); responseData = responseData.map(simplify);
} }
} }
Array.isArray(responseData) Array.isArray(responseData)
? returnData.push(...responseData) ? returnData.push(...responseData)
: returnData.push(responseData); : returnData.push(responseData);
} }
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ error: error.message }); returnData.push({ error: error.message });

View file

@ -1,10 +1,6 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { sign } from 'aws4';
sign,
} from 'aws4';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -13,17 +9,14 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { ICredentialDataDecryptedObject, IDataObject, INodeExecutionData } from 'n8n-workflow';
ICredentialDataDecryptedObject,
IDataObject,
INodeExecutionData,
} from 'n8n-workflow';
import { import { IRequestBody } from './types';
IRequestBody,
} from './types';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string { function getEndpointForService(
service: string,
credentials: ICredentialDataDecryptedObject,
): string {
let endpoint; let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) { if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint; endpoint = credentials.lambdaEndpoint;
@ -35,7 +28,15 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr
return (endpoint as string).replace('{region}', credentials.region as string); return (endpoint as string).replace('{region}', credentials.region as string);
} }
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: object | IRequestBody, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: object | IRequestBody,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
@ -43,18 +44,23 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
const options = sign({ const options = sign(
// @ts-ignore {
uri: endpoint, // @ts-ignore
service, uri: endpoint,
region: credentials.region as string, service,
method, region: credentials.region as string,
path: '/', method,
headers: { ...headers }, path: '/',
body: JSON.stringify(body), headers: { ...headers },
}, securityHeaders); body: JSON.stringify(body),
},
securityHeaders,
);
try { try {
return JSON.parse(await this.helpers.request!(options)); return JSON.parse(await this.helpers.request!(options));
@ -66,7 +72,11 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
if (error.statusCode === 403) { if (error.statusCode === 403) {
if (errorMessage === 'The security token included in the request is invalid.') { if (errorMessage === 'The security token included in the request is invalid.') {
throw new Error('The AWS credentials are not valid!'); throw new Error('The AWS credentials are not valid!');
} else if (errorMessage.startsWith('The request signature we calculated does not match the signature you provided')) { } else if (
errorMessage.startsWith(
'The request signature we calculated does not match the signature you provided',
)
) {
throw new Error('The AWS credentials are not valid!'); throw new Error('The AWS credentials are not valid!');
} }
} }
@ -75,9 +85,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestAllItems(
export async function awsApiRequestAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: IRequestBody, headers?: object): Promise<any> { // tslint:disable-line:no-any this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: IRequestBody,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -88,9 +104,7 @@ export async function awsApiRequestAllItems(this: IHookFunctions | IExecuteFunct
body!.ExclusiveStartKey = responseData.LastEvaluatedKey; body!.ExclusiveStartKey = responseData.LastEvaluatedKey;
} }
returnData.push(...responseData.Items); returnData.push(...responseData.Items);
} while ( } while (responseData.LastEvaluatedKey !== undefined);
responseData.LastEvaluatedKey !== undefined
);
return returnData; return returnData;
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const itemOperations: INodeProperties[] = [ export const itemOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const itemOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item',
],
}, },
}, },
options: [ options: [
@ -52,14 +48,13 @@ export const itemFields: INodeProperties[] = [
{ {
displayName: 'Table Name or ID', displayName: 'Table Name or ID',
name: 'tableName', name: 'tableName',
description: 'Table to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Table to operate on. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
type: 'options', type: 'options',
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item',
],
}, },
}, },
default: [], default: [],
@ -89,9 +84,7 @@ export const itemFields: INodeProperties[] = [
], ],
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upsert'],
'upsert',
],
}, },
}, },
default: 'defineBelow', default: 'defineBelow',
@ -103,16 +96,13 @@ export const itemFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upsert'],
'upsert', dataToSend: ['autoMapInputData'],
],
dataToSend: [
'autoMapInputData',
],
}, },
}, },
default: '', default: '',
description: 'List of input properties to avoid sending, separated by commas. Leave empty to send all properties.', description:
'List of input properties to avoid sending, separated by commas. Leave empty to send all properties.',
placeholder: 'Enter properties...', placeholder: 'Enter properties...',
}, },
{ {
@ -126,12 +116,8 @@ export const itemFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upsert'],
'upsert', dataToSend: ['defineBelow'],
],
dataToSend: [
'defineBelow',
],
}, },
}, },
default: {}, default: {},
@ -164,19 +150,16 @@ export const itemFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['upsert'],
],
operation: [
'upsert',
],
}, },
}, },
options: [ options: [
{ {
displayName: 'Expression Attribute Values', displayName: 'Expression Attribute Values',
name: 'eavUi', name: 'eavUi',
description: 'Substitution tokens for attribute names in an expression. Only needed when the parameter "condition expression" is set.', description:
'Substitution tokens for attribute names in an expression. Only needed when the parameter "condition expression" is set.',
placeholder: 'Add Attribute Value', placeholder: 'Add Attribute Value',
type: 'fixedCollection', type: 'fixedCollection',
default: {}, default: {},
@ -227,7 +210,8 @@ export const itemFields: INodeProperties[] = [
name: 'conditionExpression', name: 'conditionExpression',
type: 'string', type: 'string',
default: '', default: '',
description: 'A condition that must be satisfied in order for a conditional upsert to succeed. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.', description:
'A condition that must be satisfied in order for a conditional upsert to succeed. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.',
}, },
{ {
displayName: 'Expression Attribute Names', displayName: 'Expression Attribute Names',
@ -258,7 +242,8 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'One or more substitution tokens for attribute names in an expression. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.', description:
'One or more substitution tokens for attribute names in an expression. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.',
}, },
], ],
}, },
@ -272,12 +257,8 @@ export const itemFields: INodeProperties[] = [
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
options: [ options: [
@ -293,7 +274,8 @@ export const itemFields: INodeProperties[] = [
}, },
], ],
default: 'NONE', default: 'NONE',
description: 'Use ReturnValues if you want to get the item attributes as they appeared before they were deleted', description:
'Use ReturnValues if you want to get the item attributes as they appeared before they were deleted',
}, },
{ {
displayName: 'Keys', displayName: 'Keys',
@ -306,12 +288,8 @@ export const itemFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
options: [ options: [
@ -354,7 +332,8 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'Item\'s primary key. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.', description:
"Item's primary key. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.",
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -362,15 +341,9 @@ export const itemFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['delete'],
], returnValues: ['ALL_OLD'],
operation: [
'delete',
],
returnValues: [
'ALL_OLD',
],
}, },
}, },
default: true, default: true,
@ -384,12 +357,8 @@ export const itemFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
options: [ options: [
@ -398,7 +367,8 @@ export const itemFields: INodeProperties[] = [
name: 'conditionExpression', name: 'conditionExpression',
type: 'string', type: 'string',
default: '', default: '',
description: 'A condition that must be satisfied in order for a conditional delete to succeed', description:
'A condition that must be satisfied in order for a conditional delete to succeed',
}, },
{ {
displayName: 'Expression Attribute Names', displayName: 'Expression Attribute Names',
@ -429,12 +399,14 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'One or more substitution tokens for attribute names in an expression. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">Info</a>.', description:
'One or more substitution tokens for attribute names in an expression. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">Info</a>.',
}, },
{ {
displayName: 'Expression Attribute Values', displayName: 'Expression Attribute Values',
name: 'expressionAttributeUi', name: 'expressionAttributeUi',
description: 'Substitution tokens for attribute names in an expression. Only needed when the parameter "condition expression" is set.', description:
'Substitution tokens for attribute names in an expression. Only needed when the parameter "condition expression" is set.',
placeholder: 'Add Attribute Value', placeholder: 'Add Attribute Value',
type: 'fixedCollection', type: 'fixedCollection',
default: {}, default: {},
@ -492,12 +464,8 @@ export const itemFields: INodeProperties[] = [
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
options: [ options: [
@ -523,16 +491,9 @@ export const itemFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['get'],
], select: ['ALL_PROJECTED_ATTRIBUTES', 'ALL_ATTRIBUTES'],
operation: [
'get',
],
select: [
'ALL_PROJECTED_ATTRIBUTES',
'ALL_ATTRIBUTES',
],
}, },
}, },
default: true, default: true,
@ -549,12 +510,8 @@ export const itemFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
options: [ options: [
@ -597,7 +554,8 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'Item\'s primary key. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.', description:
"Item's primary key. For example, with a simple primary key, you only need to provide a value for the partition key. For a composite primary key, you must provide values for both the partition key and the sort key.",
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -607,12 +565,8 @@ export const itemFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
options: [ options: [
@ -653,7 +607,8 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'One or more substitution tokens for attribute names in an expression. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.', description:
'One or more substitution tokens for attribute names in an expression. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">View details</a>.',
}, },
{ {
displayName: 'Read Type', displayName: 'Read Type',
@ -670,7 +625,8 @@ export const itemFields: INodeProperties[] = [
}, },
], ],
default: 'eventuallyConsistentRead', default: 'eventuallyConsistentRead',
description: 'Type of read to perform on the table. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html">View details</a>.', description:
'Type of read to perform on the table. <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadConsistency.html">View details</a>.',
}, },
], ],
}, },
@ -684,16 +640,13 @@ export const itemFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
description: 'Whether to do an scan or query. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html" >differences</a>.', description:
'Whether to do an scan or query. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-query-scan.html" >differences</a>.',
}, },
{ {
displayName: 'Filter Expression', displayName: 'Filter Expression',
@ -701,18 +654,18 @@ export const itemFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
scan: [ scan: [true],
true,
],
}, },
}, },
default: '', default: '',
description: 'A filter expression determines which items within the Scan results should be returned to you. All of the other results are discarded. Empty value will return all Scan results.', description:
'A filter expression determines which items within the Scan results should be returned to you. All of the other results are discarded. Empty value will return all Scan results.',
}, },
{ {
displayName: 'Key Condition Expression', displayName: 'Key Condition Expression',
name: 'keyConditionExpression', name: 'keyConditionExpression',
description: 'Condition to determine the items to be retrieved. The condition must perform an equality test on a single partition key value, in this format: <code>partitionKeyName = :partitionkeyval</code>', description:
'Condition to determine the items to be retrieved. The condition must perform an equality test on a single partition key value, in this format: <code>partitionKeyName = :partitionkeyval</code>',
// eslint-disable-next-line n8n-nodes-base/node-param-placeholder-miscased-id // eslint-disable-next-line n8n-nodes-base/node-param-placeholder-miscased-id
placeholder: 'id = :id', placeholder: 'id = :id',
default: '', default: '',
@ -720,15 +673,9 @@ export const itemFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
], scan: [false],
operation: [
'getAll',
],
scan: [
false,
],
}, },
}, },
}, },
@ -746,12 +693,8 @@ export const itemFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -797,12 +740,8 @@ export const itemFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -814,12 +753,8 @@ export const itemFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', returnAll: [false],
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -835,12 +770,8 @@ export const itemFields: INodeProperties[] = [
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -870,17 +801,9 @@ export const itemFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
], select: ['ALL_PROJECTED_ATTRIBUTES', 'ALL_ATTRIBUTES', 'SPECIFIC_ATTRIBUTES'],
operation: [
'getAll',
],
select: [
'ALL_PROJECTED_ATTRIBUTES',
'ALL_ATTRIBUTES',
'SPECIFIC_ATTRIBUTES',
],
}, },
}, },
default: true, default: true,
@ -894,19 +817,16 @@ export const itemFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['item'],
'item', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
{ {
displayName: 'Index Name', displayName: 'Index Name',
name: 'indexName', name: 'indexName',
description: 'Name of the index to query. It can be any secondary local or global index on the table.', description:
'Name of the index to query. It can be any secondary local or global index on the table.',
type: 'string', type: 'string',
default: '', default: '',
}, },
@ -915,7 +835,8 @@ export const itemFields: INodeProperties[] = [
name: 'projectionExpression', name: 'projectionExpression',
type: 'string', type: 'string',
default: '', default: '',
description: 'Text that identifies one or more attributes to retrieve from the table. These attributes can include scalars, sets, or elements of a JSON document. The attributes in the expression must be separated by commas.', description:
'Text that identifies one or more attributes to retrieve from the table. These attributes can include scalars, sets, or elements of a JSON document. The attributes in the expression must be separated by commas.',
}, },
{ {
displayName: 'Filter Expression', displayName: 'Filter Expression',
@ -923,13 +844,12 @@ export const itemFields: INodeProperties[] = [
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
'/scan': [ '/scan': [false],
false,
],
}, },
}, },
default: '', default: '',
description: 'Text that contains conditions that DynamoDB applies after the Query operation, but before the data is returned. Items that do not satisfy the FilterExpression criteria are not returned.', description:
'Text that contains conditions that DynamoDB applies after the Query operation, but before the data is returned. Items that do not satisfy the FilterExpression criteria are not returned.',
}, },
{ {
displayName: 'Expression Attribute Names', displayName: 'Expression Attribute Names',
@ -960,7 +880,8 @@ export const itemFields: INodeProperties[] = [
], ],
}, },
], ],
description: 'One or more substitution tokens for attribute names in an expression. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">Info</a>.', description:
'One or more substitution tokens for attribute names in an expression. Check <a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html">Info</a>.',
}, },
], ],
}, },

View file

@ -32,27 +32,36 @@ export interface IAttributeNameUi {
} }
type AttributeValueType = type AttributeValueType =
| 'B' // binary | 'B' // binary
| 'BOOL' // boolean | 'BOOL' // boolean
| 'BS' // binary set | 'BS' // binary set
| 'L' // list | 'L' // list
| 'M' // map | 'M' // map
| 'N' // number | 'N' // number
| 'NULL' | 'NULL'
| 'NS' // number set | 'NS' // number set
| 'S' // string | 'S' // string
| 'SS'; // string set | 'SS'; // string set
export type PartitionKey = { export type PartitionKey = {
details: { details: {
name: string; name: string;
type: string; type: string;
value: string; value: string;
}, };
}; };
export enum EAttributeValueType { export enum EAttributeValueType {
S = 'S', SS = 'SS', M = 'M', L = 'L', NS = 'NS', N = 'N', BOOL = 'BOOL', B = 'B', BS = 'BS', NULL = 'NULL', S = 'S',
SS = 'SS',
M = 'M',
L = 'L',
NS = 'NS',
N = 'N',
BOOL = 'BOOL',
B = 'B',
BS = 'BS',
NULL = 'NULL',
} }
export interface IExpressionAttributeValue { export interface IExpressionAttributeValue {
@ -74,6 +83,6 @@ export type PutItemUi = {
export type AdjustedPutItem = { export type AdjustedPutItem = {
[attribute: string]: { [attribute: string]: {
[type: string]: string [type: string]: string;
} };
}; };

View file

@ -1,7 +1,4 @@
import { import { IDataObject, INodeExecutionData } from 'n8n-workflow';
IDataObject,
INodeExecutionData,
} from 'n8n-workflow';
import { import {
AdjustedPutItem, AdjustedPutItem,
@ -14,9 +11,10 @@ import {
PutItemUi, PutItemUi,
} from './types'; } from './types';
const addColon = (attribute: string) => attribute = attribute.charAt(0) === ':' ? attribute : `:${attribute}`; const addColon = (attribute: string) =>
(attribute = attribute.charAt(0) === ':' ? attribute : `:${attribute}`);
const addPound = (key: string) => key = key.charAt(0) === '#' ? key : `#${key}`; const addPound = (key: string) => (key = key.charAt(0) === '#' ? key : `#${key}`);
export function adjustExpressionAttributeValues(eavUi: IAttributeValueUi[]) { export function adjustExpressionAttributeValues(eavUi: IAttributeValueUi[]) {
const eav: IAttributeValue = {}; const eav: IAttributeValue = {};
@ -100,7 +98,7 @@ export function validateJSON(input: any): object {
export function copyInputItem(item: INodeExecutionData, properties: string[]): IDataObject { export function copyInputItem(item: INodeExecutionData, properties: string[]): IDataObject {
// Prepare the data to insert and copy it to be returned // Prepare the data to insert and copy it to be returned
let newItem: IDataObject; let newItem: IDataObject;
newItem = {}; newItem = {};
for (const property of properties) { for (const property of properties) {
if (item.json[property] === undefined) { if (item.json[property] === undefined) {
newItem[property] = null; newItem[property] = null;

View file

@ -10,11 +10,12 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { ICredentialDataDecryptedObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
ICredentialDataDecryptedObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string { function getEndpointForService(
service: string,
credentials: ICredentialDataDecryptedObject,
): string {
let endpoint; let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) { if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint; endpoint = credentials.lambdaEndpoint;
@ -28,7 +29,15 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr
return (endpoint as string).replace('{region}', credentials.region as string); return (endpoint as string).replace('{region}', credentials.region as string);
} }
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
@ -39,7 +48,9 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -58,7 +69,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return JSON.parse(response); return JSON.parse(response);
@ -67,7 +86,15 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IBinaryKeyData, IBinaryKeyData,
@ -12,10 +10,7 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { awsApiRequestREST, keysTPascalCase } from './GenericFunctions';
awsApiRequestREST,
keysTPascalCase,
} from './GenericFunctions';
export class AwsRekognition implements INodeType { export class AwsRekognition implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -70,12 +65,8 @@ export class AwsRekognition implements INodeType {
type: 'options', type: 'options',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
],
resource: [
'image',
],
}, },
}, },
options: [ options: [
@ -110,12 +101,8 @@ export class AwsRekognition implements INodeType {
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
],
resource: [
'image',
],
}, },
}, },
description: 'Whether the image to analize should be taken from binary field', description: 'Whether the image to analize should be taken from binary field',
@ -124,15 +111,9 @@ export class AwsRekognition implements INodeType {
displayName: 'Binary Property', displayName: 'Binary Property',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
], binaryData: [true],
resource: [
'image',
],
binaryData: [
true,
],
}, },
}, },
name: 'binaryPropertyName', name: 'binaryPropertyName',
@ -146,15 +127,9 @@ export class AwsRekognition implements INodeType {
name: 'bucket', name: 'bucket',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
], binaryData: [false],
resource: [
'image',
],
binaryData: [
false,
],
}, },
}, },
type: 'string', type: 'string',
@ -167,15 +142,9 @@ export class AwsRekognition implements INodeType {
name: 'name', name: 'name',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
], binaryData: [false],
resource: [
'image',
],
binaryData: [
false,
],
}, },
}, },
type: 'string', type: 'string',
@ -190,12 +159,8 @@ export class AwsRekognition implements INodeType {
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyze'],
'analyze', resource: ['image'],
],
resource: [
'image',
],
}, },
}, },
default: {}, default: {},
@ -208,9 +173,7 @@ export class AwsRekognition implements INodeType {
placeholder: 'Add Region of Interest', placeholder: 'Add Region of Interest',
displayOptions: { displayOptions: {
show: { show: {
'/type': [ '/type': ['detectText'],
'detectText',
],
}, },
}, },
typeOptions: { typeOptions: {
@ -225,21 +188,24 @@ export class AwsRekognition implements INodeType {
displayName: 'Height', displayName: 'Height',
name: 'height', name: 'height',
type: 'number', type: 'number',
description: 'Height of the bounding box as a ratio of the overall image height', description:
'Height of the bounding box as a ratio of the overall image height',
default: 0, default: 0,
}, },
{ {
displayName: 'Left', displayName: 'Left',
name: 'left', name: 'left',
type: 'number', type: 'number',
description: 'Left coordinate of the bounding box as a ratio of overall image width', description:
'Left coordinate of the bounding box as a ratio of overall image width',
default: 0, default: 0,
}, },
{ {
displayName: 'Top', displayName: 'Top',
name: 'top', name: 'top',
type: 'number', type: 'number',
description: 'Top coordinate of the bounding box as a ratio of overall image height', description:
'Top coordinate of the bounding box as a ratio of overall image height',
default: 0, default: 0,
}, },
{ {
@ -258,9 +224,7 @@ export class AwsRekognition implements INodeType {
name: 'version', name: 'version',
displayOptions: { displayOptions: {
show: { show: {
'/binaryData': [ '/binaryData': [false],
false,
],
}, },
}, },
type: 'string', type: 'string',
@ -275,9 +239,7 @@ export class AwsRekognition implements INodeType {
placeholder: 'Add Word Filter', placeholder: 'Add Word Filter',
displayOptions: { displayOptions: {
show: { show: {
'/type': [ '/type': ['detectText'],
'detectText',
],
}, },
}, },
typeOptions: { typeOptions: {
@ -288,21 +250,24 @@ export class AwsRekognition implements INodeType {
displayName: 'Min Bounding Box Height', displayName: 'Min Bounding Box Height',
name: 'MinBoundingBoxHeight', name: 'MinBoundingBoxHeight',
type: 'number', type: 'number',
description: 'Sets the minimum height of the word bounding box. Words with bounding box heights lesser than this value will be excluded from the result. Value is relative to the video frame height.', description:
'Sets the minimum height of the word bounding box. Words with bounding box heights lesser than this value will be excluded from the result. Value is relative to the video frame height.',
default: 0, default: 0,
}, },
{ {
displayName: 'Min Bounding Box Width', displayName: 'Min Bounding Box Width',
name: 'MinBoundingBoxWidth', name: 'MinBoundingBoxWidth',
type: 'number', type: 'number',
description: 'Sets the minimum width of the word bounding box. Words with bounding boxes widths lesser than this value will be excluded from the result. Value is relative to the video frame width.', description:
'Sets the minimum width of the word bounding box. Words with bounding boxes widths lesser than this value will be excluded from the result. Value is relative to the video frame width.',
default: 0, default: 0,
}, },
{ {
displayName: 'Min Confidence', displayName: 'Min Confidence',
name: 'MinConfidence', name: 'MinConfidence',
type: 'number', type: 'number',
description: 'Sets the confidence of word detection. Words with detection confidence below this will be excluded from the result. Values should be between 50 and 100 as Text in Video will not return any result below 50.', description:
'Sets the confidence of word detection. Words with detection confidence below this will be excluded from the result. Values should be between 50 and 100 as Text in Video will not return any result below 50.',
default: 0, default: 0,
}, },
], ],
@ -313,17 +278,15 @@ export class AwsRekognition implements INodeType {
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
'/type': [ '/type': ['detectModerationLabels', 'detectLabels'],
'detectModerationLabels',
'detectLabels',
],
}, },
}, },
default: 0, default: 0,
typeOptions: { typeOptions: {
minValue: 0, minValue: 0,
}, },
description: 'Maximum number of labels you want the service to return in the response. The service returns the specified number of highest confidence labels.', description:
'Maximum number of labels you want the service to return in the response. The service returns the specified number of highest confidence labels.',
}, },
{ {
displayName: 'Min Confidence', displayName: 'Min Confidence',
@ -331,10 +294,7 @@ export class AwsRekognition implements INodeType {
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
'/type': [ '/type': ['detectModerationLabels', 'detectLabels'],
'detectModerationLabels',
'detectLabels',
],
}, },
}, },
default: 0, default: 0,
@ -342,7 +302,8 @@ export class AwsRekognition implements INodeType {
minValue: 0, minValue: 0,
maxValue: 100, maxValue: 100,
}, },
description: 'Specifies the minimum confidence level for the labels to return. Amazon Rekognition doesn\'t return any labels with a confidence level lower than this specified value.', description:
"Specifies the minimum confidence level for the labels to return. Amazon Rekognition doesn't return any labels with a confidence level lower than this specified value.",
}, },
{ {
displayName: 'Attributes', displayName: 'Attributes',
@ -350,9 +311,7 @@ export class AwsRekognition implements INodeType {
type: 'multiOptions', type: 'multiOptions',
displayOptions: { displayOptions: {
show: { show: {
'/type': [ '/type': ['detectFaces'],
'detectFaces',
],
}, },
}, },
options: [ options: [
@ -438,7 +397,9 @@ export class AwsRekognition implements INodeType {
body.Filters = {}; body.Filters = {};
const box = (additionalFields.regionsOfInterestUi as IDataObject || {}).regionsOfInterestValues as IDataObject[] || []; const box =
(((additionalFields.regionsOfInterestUi as IDataObject) || {})
.regionsOfInterestValues as IDataObject[]) || [];
if (box.length !== 0) { if (box.length !== 0) {
//@ts-ignore //@ts-ignore
@ -447,7 +408,7 @@ export class AwsRekognition implements INodeType {
}); });
} }
const wordFilter = additionalFields.wordFilterUi as IDataObject || {}; const wordFilter = (additionalFields.wordFilterUi as IDataObject) || {};
if (Object.keys(wordFilter).length !== 0) { if (Object.keys(wordFilter).length !== 0) {
//@ts-ignore //@ts-ignore
body.Filters.WordFilter = keysTPascalCase(wordFilter); body.Filters.WordFilter = keysTPascalCase(wordFilter);
@ -456,15 +417,20 @@ export class AwsRekognition implements INodeType {
const binaryData = this.getNodeParameter('binaryData', 0) as boolean; const binaryData = this.getNodeParameter('binaryData', 0) as boolean;
if (binaryData) { if (binaryData) {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) as string; const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) as string;
if (items[i].binary === undefined) { if (items[i].binary === undefined) {
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
itemIndex: i,
});
} }
if ((items[i].binary as IBinaryKeyData)[binaryPropertyName] === undefined) { if ((items[i].binary as IBinaryKeyData)[binaryPropertyName] === undefined) {
throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`No binary data property "${binaryPropertyName}" does not exists on item!`,
{ itemIndex: i },
);
} }
const binaryPropertyData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; const binaryPropertyData = (items[i].binary as IBinaryKeyData)[binaryPropertyName];
@ -474,9 +440,7 @@ export class AwsRekognition implements INodeType {
Bytes: binaryPropertyData.data, Bytes: binaryPropertyData.data,
}, },
}); });
} else { } else {
const bucket = this.getNodeParameter('bucket', i) as string; const bucket = this.getNodeParameter('bucket', i) as string;
const name = this.getNodeParameter('name', i) as string; const name = this.getNodeParameter('name', i) as string;
@ -496,8 +460,15 @@ export class AwsRekognition implements INodeType {
} }
} }
responseData = await awsApiRequestREST.call(this, 'rekognition', 'POST', '', JSON.stringify(body), {}, { 'X-Amz-Target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'rekognition',
'POST',
'',
JSON.stringify(body),
{},
{ 'X-Amz-Target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
} }
} }
} }

View file

@ -1,23 +1,12 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { get } from 'lodash';
get,
} from 'lodash';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { parseString } from 'xml2js';
parseString,
} from 'xml2js';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -26,27 +15,39 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
IDataObject,
NodeApiError,
NodeOperationError,
} from 'n8n-workflow';
import { import { pascalCase } from 'change-case';
pascalCase,
} from 'change-case';
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer | IDataObject, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string | Buffer | IDataObject,
query: IDataObject = {},
headers?: object,
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
const endpoint = new URL(((credentials.rekognitionEndpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); const endpoint = new URL(
(((credentials.rekognitionEndpoint as string) || '').replace(
'{region}',
credentials.region as string,
) || `https://${service}.${credentials.region}.amazonaws.com`) + path,
);
// Sign AWS API request with the user credentials // Sign AWS API request with the user credentials
const signOpts = {headers: headers || {}, host: endpoint.host, method, path, body} as Request; const signOpts = { headers: headers || {}, host: endpoint.host, method, path, body } as Request;
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -68,8 +69,29 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers?: object, options: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
const response = await awsApiRequest.call(this, service, method, path, body, query, headers, options, region); this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers?: object,
options: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(
this,
service,
method,
path,
body,
query,
headers,
options,
region,
);
try { try {
return JSON.parse(response); return JSON.parse(response);
} catch (error) { } catch (error) {
@ -77,8 +99,29 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer | IDataObject, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
const response = await awsApiRequest.call(this, service, method, path, body, query, headers, option, region); this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string | Buffer | IDataObject,
query: IDataObject = {},
headers?: object,
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(
this,
service,
method,
path,
body,
query,
headers,
option,
region,
);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
parseString(response, { explicitArray: false }, (err, data) => { parseString(response, { explicitArray: false }, (err, data) => {
@ -93,18 +136,42 @@ export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, propertyName: string, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers: IDataObject = {}, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAPAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
propertyName: string,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers: IDataObject = {},
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
do { do {
responseData = await awsApiRequestSOAP.call(this, service, method, path, body, query, headers, option, region); responseData = await awsApiRequestSOAP.call(
this,
service,
method,
path,
body,
query,
headers,
option,
region,
);
//https://forums.aws.amazon.com/thread.jspa?threadID=55746 //https://forums.aws.amazon.com/thread.jspa?threadID=55746
if (get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`)) { if (get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`)) {
query['continuation-token'] = get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`); query['continuation-token'] = get(
responseData,
`${propertyName.split('.')[0]}.NextContinuationToken`,
);
} }
if (get(responseData, propertyName)) { if (get(responseData, propertyName)) {
if (Array.isArray(get(responseData, propertyName))) { if (Array.isArray(get(responseData, propertyName))) {
@ -125,7 +192,9 @@ export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteF
} }
function queryToString(params: IDataObject) { function queryToString(params: IDataObject) {
return Object.keys(params).map(key => key + '=' + params[key]).join('&'); return Object.keys(params)
.map((key) => key + '=' + params[key])
.join('&');
} }
export function keysTPascalCase(object: IDataObject) { export function keysTPascalCase(object: IDataObject) {

View file

@ -1,20 +1,10 @@
import { paramCase, snakeCase } from 'change-case';
import { import { createHash } from 'crypto';
paramCase,
snakeCase,
} from 'change-case';
import { import { Builder } from 'xml2js';
createHash,
} from 'crypto';
import { import { IExecuteFunctions } from 'n8n-core';
Builder,
} from 'xml2js';
import {
IExecuteFunctions,
} from 'n8n-core';
import { import {
IBinaryKeyData, IBinaryKeyData,
@ -26,20 +16,11 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { bucketFields, bucketOperations } from './BucketDescription';
bucketFields,
bucketOperations,
} from './BucketDescription';
import { import { folderFields, folderOperations } from './FolderDescription';
folderFields,
folderOperations,
} from './FolderDescription';
import { import { fileFields, fileOperations } from './FileDescription';
fileFields,
fileOperations,
} from './FileDescription';
import { import {
awsApiRequestREST, awsApiRequestREST,
@ -121,7 +102,8 @@ export class AwsS3 implements INodeType {
headers['x-amz-acl'] = paramCase(additionalFields.acl as string); headers['x-amz-acl'] = paramCase(additionalFields.acl as string);
} }
if (additionalFields.bucketObjectLockEnabled) { if (additionalFields.bucketObjectLockEnabled) {
headers['x-amz-bucket-object-lock-enabled'] = additionalFields.bucketObjectLockEnabled as boolean; headers['x-amz-bucket-object-lock-enabled'] =
additionalFields.bucketObjectLockEnabled as boolean;
} }
if (additionalFields.grantFullControl) { if (additionalFields.grantFullControl) {
headers['x-amz-grant-full-control'] = ''; headers['x-amz-grant-full-control'] = '';
@ -146,7 +128,7 @@ export class AwsS3 implements INodeType {
const body: IDataObject = { const body: IDataObject = {
CreateBucketConfiguration: { CreateBucketConfiguration: {
'$': { $: {
xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/', xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/',
}, },
}, },
@ -159,7 +141,15 @@ export class AwsS3 implements INodeType {
const builder = new Builder(); const builder = new Builder();
data = builder.buildObject(body); data = builder.buildObject(body);
} }
responseData = await awsApiRequestSOAP.call(this, `${name}.s3`, 'PUT', '', data, qs, headers); responseData = await awsApiRequestSOAP.call(
this,
`${name}.s3`,
'PUT',
'',
data,
qs,
headers,
);
returnData.push({ success: true }); returnData.push({ success: true });
} }
@ -168,7 +158,15 @@ export class AwsS3 implements INodeType {
if (operation === 'delete') { if (operation === 'delete') {
const name = this.getNodeParameter('name', i) as string; const name = this.getNodeParameter('name', i) as string;
responseData = await awsApiRequestSOAP.call(this, `${name}.s3`, 'DELETE', '', '', {}, headers); responseData = await awsApiRequestSOAP.call(
this,
`${name}.s3`,
'DELETE',
'',
'',
{},
headers,
);
returnData.push({ success: true }); returnData.push({ success: true });
} }
@ -176,10 +174,24 @@ export class AwsS3 implements INodeType {
if (operation === 'getAll') { if (operation === 'getAll') {
const returnAll = this.getNodeParameter('returnAll', 0) as boolean; const returnAll = this.getNodeParameter('returnAll', 0) as boolean;
if (returnAll) { if (returnAll) {
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListAllMyBucketsResult.Buckets.Bucket', 's3', 'GET', ''); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListAllMyBucketsResult.Buckets.Bucket',
's3',
'GET',
'',
);
} else { } else {
qs.limit = this.getNodeParameter('limit', 0) as number; qs.limit = this.getNodeParameter('limit', 0) as number;
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListAllMyBucketsResult.Buckets.Bucket', 's3', 'GET', '', '', qs); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListAllMyBucketsResult.Buckets.Bucket',
's3',
'GET',
'',
'',
qs,
);
responseData = responseData.slice(0, qs.limit); responseData = responseData.slice(0, qs.limit);
} }
returnData.push.apply(returnData, responseData); returnData.push.apply(returnData, responseData);
@ -217,16 +229,38 @@ export class AwsS3 implements INodeType {
qs['list-type'] = 2; qs['list-type'] = 2;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); location: '',
});
const region = responseData.LocationConstraint._ as string; const region = responseData.LocationConstraint._ as string;
if (returnAll) { if (returnAll) {
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
} else { } else {
qs['max-keys'] = this.getNodeParameter('limit', 0) as number; qs['max-keys'] = this.getNodeParameter('limit', 0) as number;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
responseData = responseData.ListBucketResult.Contents; responseData = responseData.ListBucketResult.Contents;
} }
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
@ -251,13 +285,27 @@ export class AwsS3 implements INodeType {
path = `/${additionalFields.parentFolderKey}${folderName}/`; path = `/${additionalFields.parentFolderKey}${folderName}/`;
} }
if (additionalFields.storageClass) { if (additionalFields.storageClass) {
headers['x-amz-storage-class'] = (snakeCase(additionalFields.storageClass as string)).toUpperCase(); headers['x-amz-storage-class'] = snakeCase(
additionalFields.storageClass as string,
).toUpperCase();
} }
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'PUT', path, '', qs, headers, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'PUT',
path,
'',
qs,
headers,
{},
region,
);
returnData.push({ success: true }); returnData.push({ success: true });
} }
//https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html //https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html
@ -265,24 +313,45 @@ export class AwsS3 implements INodeType {
const bucketName = this.getNodeParameter('bucketName', i) as string; const bucketName = this.getNodeParameter('bucketName', i) as string;
const folderKey = this.getNodeParameter('folderKey', i) as string; const folderKey = this.getNodeParameter('folderKey', i) as string;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '/', '', { 'list-type': 2, prefix: folderKey }, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'/',
'',
{ 'list-type': 2, prefix: folderKey },
{},
{},
region,
);
// folder empty then just delete it // folder empty then just delete it
if (responseData.length === 0) { if (responseData.length === 0) {
responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'DELETE',
`/${folderKey}`,
'',
qs,
{},
{},
region,
);
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'DELETE', `/${folderKey}`, '', qs, {}, {}, region); responseData = { deleted: [{ Key: folderKey }] };
responseData = { deleted: [ { 'Key': folderKey } ] };
} else { } else {
// delete everything inside the folder // delete everything inside the folder
const body: IDataObject = { const body: IDataObject = {
Delete: { Delete: {
'$': { $: {
xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/', xmlns: 'http://s3.amazonaws.com/doc/2006-03-01/',
}, },
Object: [], Object: [],
@ -303,7 +372,17 @@ export class AwsS3 implements INodeType {
headers['Content-Type'] = 'application/xml'; headers['Content-Type'] = 'application/xml';
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'POST', '/', data, { delete: '' } , headers, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'POST',
'/',
data,
{ delete: '' },
headers,
{},
region,
);
responseData = { deleted: responseData.DeleteResult.Deleted }; responseData = { deleted: responseData.DeleteResult.Deleted };
} }
@ -325,18 +404,45 @@ export class AwsS3 implements INodeType {
qs['list-type'] = 2; qs['list-type'] = 2;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
if (returnAll) { if (returnAll) {
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
} else { } else {
qs.limit = this.getNodeParameter('limit', 0) as number; qs.limit = this.getNodeParameter('limit', 0) as number;
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
} }
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
responseData = responseData.filter((e: IDataObject) => (e.Key as string).endsWith('/') && e.Size === '0' && e.Key !== options.folderKey); responseData = responseData.filter(
(e: IDataObject) =>
(e.Key as string).endsWith('/') && e.Size === '0' && e.Key !== options.folderKey,
);
if (qs.limit) { if (qs.limit) {
responseData = responseData.splice(0, qs.limit as number); responseData = responseData.splice(0, qs.limit as number);
} }
@ -357,7 +463,9 @@ export class AwsS3 implements INodeType {
headers['x-amz-request-payer'] = 'requester'; headers['x-amz-request-payer'] = 'requester';
} }
if (additionalFields.storageClass) { if (additionalFields.storageClass) {
headers['x-amz-storage-class'] = (snakeCase(additionalFields.storageClass as string)).toUpperCase(); headers['x-amz-storage-class'] = snakeCase(
additionalFields.storageClass as string,
).toUpperCase();
} }
if (additionalFields.acl) { if (additionalFields.acl) {
headers['x-amz-acl'] = paramCase(additionalFields.acl as string); headers['x-amz-acl'] = paramCase(additionalFields.acl as string);
@ -375,37 +483,52 @@ export class AwsS3 implements INodeType {
headers['x-amz-grant-write-acp'] = ''; headers['x-amz-grant-write-acp'] = '';
} }
if (additionalFields.lockLegalHold) { if (additionalFields.lockLegalHold) {
headers['x-amz-object-lock-legal-hold'] = (additionalFields.lockLegalHold as boolean) ? 'ON' : 'OFF'; headers['x-amz-object-lock-legal-hold'] = (additionalFields.lockLegalHold as boolean)
? 'ON'
: 'OFF';
} }
if (additionalFields.lockMode) { if (additionalFields.lockMode) {
headers['x-amz-object-lock-mode'] = (additionalFields.lockMode as string).toUpperCase(); headers['x-amz-object-lock-mode'] = (
additionalFields.lockMode as string
).toUpperCase();
} }
if (additionalFields.lockRetainUntilDate) { if (additionalFields.lockRetainUntilDate) {
headers['x-amz-object-lock-retain-until-date'] = additionalFields.lockRetainUntilDate as string; headers['x-amz-object-lock-retain-until-date'] =
additionalFields.lockRetainUntilDate as string;
} }
if (additionalFields.serverSideEncryption) { if (additionalFields.serverSideEncryption) {
headers['x-amz-server-side-encryption'] = additionalFields.serverSideEncryption as string; headers['x-amz-server-side-encryption'] =
additionalFields.serverSideEncryption as string;
} }
if (additionalFields.encryptionAwsKmsKeyId) { if (additionalFields.encryptionAwsKmsKeyId) {
headers['x-amz-server-side-encryption-aws-kms-key-id'] = additionalFields.encryptionAwsKmsKeyId as string; headers['x-amz-server-side-encryption-aws-kms-key-id'] =
additionalFields.encryptionAwsKmsKeyId as string;
} }
if (additionalFields.serverSideEncryptionContext) { if (additionalFields.serverSideEncryptionContext) {
headers['x-amz-server-side-encryption-context'] = additionalFields.serverSideEncryptionContext as string; headers['x-amz-server-side-encryption-context'] =
additionalFields.serverSideEncryptionContext as string;
} }
if (additionalFields.serversideEncryptionCustomerAlgorithm) { if (additionalFields.serversideEncryptionCustomerAlgorithm) {
headers['x-amz-server-side-encryption-customer-algorithm'] = additionalFields.serversideEncryptionCustomerAlgorithm as string; headers['x-amz-server-side-encryption-customer-algorithm'] =
additionalFields.serversideEncryptionCustomerAlgorithm as string;
} }
if (additionalFields.serversideEncryptionCustomerKey) { if (additionalFields.serversideEncryptionCustomerKey) {
headers['x-amz-server-side-encryption-customer-key'] = additionalFields.serversideEncryptionCustomerKey as string; headers['x-amz-server-side-encryption-customer-key'] =
additionalFields.serversideEncryptionCustomerKey as string;
} }
if (additionalFields.serversideEncryptionCustomerKeyMD5) { if (additionalFields.serversideEncryptionCustomerKeyMD5) {
headers['x-amz-server-side-encryption-customer-key-MD5'] = additionalFields.serversideEncryptionCustomerKeyMD5 as string; headers['x-amz-server-side-encryption-customer-key-MD5'] =
additionalFields.serversideEncryptionCustomerKeyMD5 as string;
} }
if (additionalFields.taggingDirective) { if (additionalFields.taggingDirective) {
headers['x-amz-tagging-directive'] = (additionalFields.taggingDirective as string).toUpperCase(); headers['x-amz-tagging-directive'] = (
additionalFields.taggingDirective as string
).toUpperCase();
} }
if (additionalFields.metadataDirective) { if (additionalFields.metadataDirective) {
headers['x-amz-metadata-directive'] = (additionalFields.metadataDirective as string).toUpperCase(); headers['x-amz-metadata-directive'] = (
additionalFields.metadataDirective as string
).toUpperCase();
} }
const destinationParts = destinationPath.split('/'); const destinationParts = destinationPath.split('/');
@ -414,17 +537,27 @@ export class AwsS3 implements INodeType {
const destination = `/${destinationParts.slice(2, destinationParts.length).join('/')}`; const destination = `/${destinationParts.slice(2, destinationParts.length).join('/')}`;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'PUT', destination, '', qs, headers, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'PUT',
destination,
'',
qs,
headers,
{},
region,
);
returnData.push(responseData.CopyObjectResult); returnData.push(responseData.CopyObjectResult);
} }
//https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html //https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html
if (operation === 'download') { if (operation === 'download') {
const bucketName = this.getNodeParameter('bucketName', i) as string; const bucketName = this.getNodeParameter('bucketName', i) as string;
const fileKey = this.getNodeParameter('fileKey', i) as string; const fileKey = this.getNodeParameter('fileKey', i) as string;
@ -432,14 +565,29 @@ export class AwsS3 implements INodeType {
const fileName = fileKey.split('/')[fileKey.split('/').length - 1]; const fileName = fileKey.split('/')[fileKey.split('/').length - 1];
if (fileKey.substring(fileKey.length - 1) === '/') { if (fileKey.substring(fileKey.length - 1) === '/') {
throw new NodeOperationError(this.getNode(), 'Downloding a whole directory is not yet supported, please provide a file key'); throw new NodeOperationError(
this.getNode(),
'Downloding a whole directory is not yet supported, please provide a file key',
);
} }
let region = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); let region = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
region = region.LocationConstraint._; region = region.LocationConstraint._;
const response = await awsApiRequestREST.call(this, `${bucketName}.s3`, 'GET', `/${fileKey}`, '', qs, {}, { encoding: null, resolveWithFullResponse: true }, region); const response = await awsApiRequestREST.call(
this,
`${bucketName}.s3`,
'GET',
`/${fileKey}`,
'',
qs,
{},
{ encoding: null, resolveWithFullResponse: true },
region,
);
let mimeType: string | undefined; let mimeType: string | undefined;
if (response.headers['content-type']) { if (response.headers['content-type']) {
@ -460,11 +608,18 @@ export class AwsS3 implements INodeType {
items[i] = newItem; items[i] = newItem;
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string; const dataPropertyNameDownload = this.getNodeParameter(
'binaryPropertyName',
i,
) as string;
const data = Buffer.from(response.body as string, 'utf8'); const data = Buffer.from(response.body as string, 'utf8');
items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(data as unknown as Buffer, fileName, mimeType); items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(
data as unknown as Buffer,
fileName,
mimeType,
);
} }
//https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html //https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html
if (operation === 'delete') { if (operation === 'delete') {
@ -478,11 +633,23 @@ export class AwsS3 implements INodeType {
qs.versionId = options.versionId as string; qs.versionId = options.versionId as string;
} }
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'DELETE', `/${fileKey}`, '', qs, {}, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'DELETE',
`/${fileKey}`,
'',
qs,
{},
{},
region,
);
returnData.push({ success: true }); returnData.push({ success: true });
} }
@ -504,19 +671,45 @@ export class AwsS3 implements INodeType {
qs['list-type'] = 2; qs['list-type'] = 2;
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
if (returnAll) { if (returnAll) {
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
} else { } else {
qs.limit = this.getNodeParameter('limit', 0) as number; qs.limit = this.getNodeParameter('limit', 0) as number;
responseData = await awsApiRequestSOAPAllItems.call(this, 'ListBucketResult.Contents', `${bucketName}.s3`, 'GET', '', '', qs, {}, {}, region); responseData = await awsApiRequestSOAPAllItems.call(
this,
'ListBucketResult.Contents',
`${bucketName}.s3`,
'GET',
'',
'',
qs,
{},
{},
region,
);
responseData = responseData.splice(0, qs.limit); responseData = responseData.splice(0, qs.limit);
} }
if (Array.isArray(responseData)) { if (Array.isArray(responseData)) {
responseData = responseData.filter((e: IDataObject) => !(e.Key as string).endsWith('/') && e.Size !== '0'); responseData = responseData.filter(
(e: IDataObject) => !(e.Key as string).endsWith('/') && e.Size !== '0',
);
if (qs.limit) { if (qs.limit) {
responseData = responseData.splice(0, qs.limit as number); responseData = responseData.splice(0, qs.limit as number);
} }
@ -529,7 +722,8 @@ export class AwsS3 implements INodeType {
const fileName = this.getNodeParameter('fileName', i) as string; const fileName = this.getNodeParameter('fileName', i) as string;
const isBinaryData = this.getNodeParameter('binaryData', i) as boolean; const isBinaryData = this.getNodeParameter('binaryData', i) as boolean;
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const tagsValues = (this.getNodeParameter('tagsUi', i) as IDataObject).tagsValues as IDataObject[]; const tagsValues = (this.getNodeParameter('tagsUi', i) as IDataObject)
.tagsValues as IDataObject[];
let path = '/'; let path = '/';
let body; let body;
@ -540,7 +734,9 @@ export class AwsS3 implements INodeType {
path = `/${additionalFields.parentFolderKey}/`; path = `/${additionalFields.parentFolderKey}/`;
} }
if (additionalFields.storageClass) { if (additionalFields.storageClass) {
headers['x-amz-storage-class'] = (snakeCase(additionalFields.storageClass as string)).toUpperCase(); headers['x-amz-storage-class'] = snakeCase(
additionalFields.storageClass as string,
).toUpperCase();
} }
if (additionalFields.acl) { if (additionalFields.acl) {
headers['x-amz-acl'] = paramCase(additionalFields.acl as string); headers['x-amz-acl'] = paramCase(additionalFields.acl as string);
@ -558,39 +754,54 @@ export class AwsS3 implements INodeType {
headers['x-amz-grant-write-acp'] = ''; headers['x-amz-grant-write-acp'] = '';
} }
if (additionalFields.lockLegalHold) { if (additionalFields.lockLegalHold) {
headers['x-amz-object-lock-legal-hold'] = (additionalFields.lockLegalHold as boolean) ? 'ON' : 'OFF'; headers['x-amz-object-lock-legal-hold'] = (additionalFields.lockLegalHold as boolean)
? 'ON'
: 'OFF';
} }
if (additionalFields.lockMode) { if (additionalFields.lockMode) {
headers['x-amz-object-lock-mode'] = (additionalFields.lockMode as string).toUpperCase(); headers['x-amz-object-lock-mode'] = (
additionalFields.lockMode as string
).toUpperCase();
} }
if (additionalFields.lockRetainUntilDate) { if (additionalFields.lockRetainUntilDate) {
headers['x-amz-object-lock-retain-until-date'] = additionalFields.lockRetainUntilDate as string; headers['x-amz-object-lock-retain-until-date'] =
additionalFields.lockRetainUntilDate as string;
} }
if (additionalFields.serverSideEncryption) { if (additionalFields.serverSideEncryption) {
headers['x-amz-server-side-encryption'] = additionalFields.serverSideEncryption as string; headers['x-amz-server-side-encryption'] =
additionalFields.serverSideEncryption as string;
} }
if (additionalFields.encryptionAwsKmsKeyId) { if (additionalFields.encryptionAwsKmsKeyId) {
headers['x-amz-server-side-encryption-aws-kms-key-id'] = additionalFields.encryptionAwsKmsKeyId as string; headers['x-amz-server-side-encryption-aws-kms-key-id'] =
additionalFields.encryptionAwsKmsKeyId as string;
} }
if (additionalFields.serverSideEncryptionContext) { if (additionalFields.serverSideEncryptionContext) {
headers['x-amz-server-side-encryption-context'] = additionalFields.serverSideEncryptionContext as string; headers['x-amz-server-side-encryption-context'] =
additionalFields.serverSideEncryptionContext as string;
} }
if (additionalFields.serversideEncryptionCustomerAlgorithm) { if (additionalFields.serversideEncryptionCustomerAlgorithm) {
headers['x-amz-server-side-encryption-customer-algorithm'] = additionalFields.serversideEncryptionCustomerAlgorithm as string; headers['x-amz-server-side-encryption-customer-algorithm'] =
additionalFields.serversideEncryptionCustomerAlgorithm as string;
} }
if (additionalFields.serversideEncryptionCustomerKey) { if (additionalFields.serversideEncryptionCustomerKey) {
headers['x-amz-server-side-encryption-customer-key'] = additionalFields.serversideEncryptionCustomerKey as string; headers['x-amz-server-side-encryption-customer-key'] =
additionalFields.serversideEncryptionCustomerKey as string;
} }
if (additionalFields.serversideEncryptionCustomerKeyMD5) { if (additionalFields.serversideEncryptionCustomerKeyMD5) {
headers['x-amz-server-side-encryption-customer-key-MD5'] = additionalFields.serversideEncryptionCustomerKeyMD5 as string; headers['x-amz-server-side-encryption-customer-key-MD5'] =
additionalFields.serversideEncryptionCustomerKeyMD5 as string;
} }
if (tagsValues) { if (tagsValues) {
const tags: string[] = []; const tags: string[] = [];
tagsValues.forEach((o: IDataObject) => { tags.push(`${o.key}=${o.value}`); }); tagsValues.forEach((o: IDataObject) => {
tags.push(`${o.key}=${o.value}`);
});
headers['x-amz-tagging'] = tags.join('&'); headers['x-amz-tagging'] = tags.join('&');
} }
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', { location: '' }); responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'GET', '', '', {
location: '',
});
const region = responseData.LocationConstraint._; const region = responseData.LocationConstraint._;
@ -598,15 +809,24 @@ export class AwsS3 implements INodeType {
const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) as string; const binaryPropertyName = this.getNodeParameter('binaryPropertyName', 0) as string;
if (items[i].binary === undefined) { if (items[i].binary === undefined) {
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
itemIndex: i,
});
} }
if ((items[i].binary as IBinaryKeyData)[binaryPropertyName] === undefined) { if ((items[i].binary as IBinaryKeyData)[binaryPropertyName] === undefined) {
throw new NodeOperationError(this.getNode(), `No binary data property "${binaryPropertyName}" does not exists on item!`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`No binary data property "${binaryPropertyName}" does not exists on item!`,
{ itemIndex: i },
);
} }
const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName]; const binaryData = (items[i].binary as IBinaryKeyData)[binaryPropertyName];
const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); const binaryDataBuffer = await this.helpers.getBinaryDataBuffer(
i,
binaryPropertyName,
);
body = binaryDataBuffer; body = binaryDataBuffer;
@ -614,10 +834,18 @@ export class AwsS3 implements INodeType {
headers['Content-MD5'] = createHash('md5').update(body).digest('base64'); headers['Content-MD5'] = createHash('md5').update(body).digest('base64');
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'PUT', `${path}${fileName || binaryData.fileName}`, body, qs, headers, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'PUT',
`${path}${fileName || binaryData.fileName}`,
body,
qs,
headers,
{},
region,
);
} else { } else {
const fileContent = this.getNodeParameter('fileContent', i) as string; const fileContent = this.getNodeParameter('fileContent', i) as string;
body = Buffer.from(fileContent, 'utf8'); body = Buffer.from(fileContent, 'utf8');
@ -626,7 +854,17 @@ export class AwsS3 implements INodeType {
headers['Content-MD5'] = createHash('md5').update(fileContent).digest('base64'); headers['Content-MD5'] = createHash('md5').update(fileContent).digest('base64');
responseData = await awsApiRequestSOAP.call(this, `${bucketName}.s3`, 'PUT', `${path}${fileName}`, body, qs, headers, {}, region); responseData = await awsApiRequestSOAP.call(
this,
`${bucketName}.s3`,
'PUT',
`${path}${fileName}`,
body,
qs,
headers,
{},
region,
);
} }
returnData.push({ success: true }); returnData.push({ success: true });
} }

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const bucketOperations: INodeProperties[] = [ export const bucketOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const bucketOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket',
],
}, },
}, },
options: [ options: [
@ -46,10 +42,9 @@ export const bucketOperations: INodeProperties[] = [
]; ];
export const bucketFields: INodeProperties[] = [ export const bucketFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* bucket:create */
/* bucket:create */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
{ {
displayName: 'Name', displayName: 'Name',
name: 'name', name: 'name',
@ -58,12 +53,8 @@ export const bucketFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'A succinct description of the nature, symptoms, cause, or effect of the bucket', description: 'A succinct description of the nature, symptoms, cause, or effect of the bucket',
@ -75,12 +66,8 @@ export const bucketFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
default: {}, default: {},
@ -122,7 +109,8 @@ export const bucketFields: INodeProperties[] = [
name: 'grantFullControl', name: 'grantFullControl',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether to allow grantee the read, write, read ACP, and write ACP permissions on the bucket', description:
'Whether to allow grantee the read, write, read ACP, and write ACP permissions on the bucket',
}, },
{ {
displayName: 'Grant Read', displayName: 'Grant Read',
@ -143,7 +131,8 @@ export const bucketFields: INodeProperties[] = [
name: 'grantWrite', name: 'grantWrite',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether to allow grantee to create, overwrite, and delete any object in the bucket', description:
'Whether to allow grantee to create, overwrite, and delete any object in the bucket',
}, },
{ {
displayName: 'Grant Write ACP', displayName: 'Grant Write ACP',
@ -157,14 +146,15 @@ export const bucketFields: INodeProperties[] = [
name: 'region', name: 'region',
type: 'string', type: 'string',
default: '', default: '',
description: 'Region you want to create the bucket in, by default the buckets are created on the region defined on the credentials', description:
'Region you want to create the bucket in, by default the buckets are created on the region defined on the credentials',
}, },
], ],
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* bucket:delete */ /* bucket:delete */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Name', displayName: 'Name',
name: 'name', name: 'name',
@ -173,32 +163,24 @@ export const bucketFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
description: 'Name of the AWS S3 bucket to delete', description: 'Name of the AWS S3 bucket to delete',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* bucket:getAll */ /* bucket:getAll */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Return All', displayName: 'Return All',
name: 'returnAll', name: 'returnAll',
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['bucket'],
],
resource: [
'bucket',
],
}, },
}, },
default: false, default: false,
@ -210,15 +192,9 @@ export const bucketFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['bucket'],
], returnAll: [false],
resource: [
'bucket',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -228,9 +204,9 @@ export const bucketFields: INodeProperties[] = [
default: 100, default: 100,
description: 'Max number of results to return', description: 'Max number of results to return',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* bucket:search */ /* bucket:search */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -239,12 +215,8 @@ export const bucketFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket', operation: ['search'],
],
operation: [
'search',
],
}, },
}, },
}, },
@ -254,12 +226,8 @@ export const bucketFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['search'],
'search', resource: ['bucket'],
],
resource: [
'bucket',
],
}, },
}, },
default: false, default: false,
@ -271,15 +239,9 @@ export const bucketFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['search'],
'search', resource: ['bucket'],
], returnAll: [false],
resource: [
'bucket',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -296,12 +258,8 @@ export const bucketFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['bucket'],
'bucket', operation: ['search'],
],
operation: [
'search',
],
}, },
}, },
default: {}, default: {},
@ -332,7 +290,8 @@ export const bucketFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
default: false, default: false,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true', description:
'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true',
}, },
{ {
displayName: 'Prefix', displayName: 'Prefix',
@ -346,14 +305,16 @@ export const bucketFields: INodeProperties[] = [
name: 'requesterPays', name: 'requesterPays',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.', description:
'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.',
}, },
{ {
displayName: 'Start After', displayName: 'Start After',
name: 'startAfter', name: 'startAfter',
type: 'string', type: 'string',
default: '', default: '',
description: 'StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this specified key.', description:
'StartAfter is where you want Amazon S3 to start listing from. Amazon S3 starts listing after this specified key.',
}, },
], ],
}, },

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const fileOperations: INodeProperties[] = [ export const fileOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const fileOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file',
],
}, },
}, },
options: [ options: [
@ -52,10 +48,9 @@ export const fileOperations: INodeProperties[] = [
]; ];
export const fileFields: INodeProperties[] = [ export const fileFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* file:copy */
/* file:copy */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
{ {
displayName: 'Source Path', displayName: 'Source Path',
name: 'sourcePath', name: 'sourcePath',
@ -65,15 +60,12 @@ export const fileFields: INodeProperties[] = [
placeholder: '/bucket/my-image.jpg', placeholder: '/bucket/my-image.jpg',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['copy'],
],
operation: [
'copy',
],
}, },
}, },
description: 'The name of the source bucket and key name of the source object, separated by a slash (/)', description:
'The name of the source bucket and key name of the source object, separated by a slash (/)',
}, },
{ {
displayName: 'Destination Path', displayName: 'Destination Path',
@ -84,15 +76,12 @@ export const fileFields: INodeProperties[] = [
placeholder: '/bucket/my-second-image.jpg', placeholder: '/bucket/my-second-image.jpg',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['copy'],
],
operation: [
'copy',
],
}, },
}, },
description: 'The name of the destination bucket and key name of the destination object, separated by a slash (/)', description:
'The name of the destination bucket and key name of the destination object, separated by a slash (/)',
}, },
{ {
displayName: 'Additional Fields', displayName: 'Additional Fields',
@ -101,12 +90,8 @@ export const fileFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['copy'],
],
operation: [
'copy',
],
}, },
}, },
default: {}, default: {},
@ -153,7 +138,8 @@ export const fileFields: INodeProperties[] = [
name: 'grantFullControl', name: 'grantFullControl',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object', description:
'Whether to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object',
}, },
{ {
displayName: 'Grant Read', displayName: 'Grant Read',
@ -205,7 +191,7 @@ export const fileFields: INodeProperties[] = [
name: 'lockRetainUntilDate', name: 'lockRetainUntilDate',
type: 'dateTime', type: 'dateTime',
default: '', default: '',
description: 'The date and time when you want this object\'s Object Lock to expire', description: "The date and time when you want this object's Object Lock to expire",
}, },
{ {
displayName: 'Metadata Directive', displayName: 'Metadata Directive',
@ -222,14 +208,16 @@ export const fileFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request', description:
'Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request',
}, },
{ {
displayName: 'Requester Pays', displayName: 'Requester Pays',
name: 'requesterPays', name: 'requesterPays',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.', description:
'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.',
}, },
{ {
displayName: 'Server Side Encryption', displayName: 'Server Side Encryption',
@ -246,7 +234,8 @@ export const fileFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'The server-side encryption algorithm used when storing this object in Amazon S3', description:
'The server-side encryption algorithm used when storing this object in Amazon S3',
}, },
{ {
displayName: 'Server Side Encryption Context', displayName: 'Server Side Encryption Context',
@ -267,14 +256,16 @@ export const fileFields: INodeProperties[] = [
name: 'serversideEncryptionCustomerAlgorithm', name: 'serversideEncryptionCustomerAlgorithm',
type: 'string', type: 'string',
default: '', default: '',
description: 'Specifies the algorithm to use to when encrypting the object (for example, AES256)', description:
'Specifies the algorithm to use to when encrypting the object (for example, AES256)',
}, },
{ {
displayName: 'Server Side Encryption Customer Key', displayName: 'Server Side Encryption Customer Key',
name: 'serversideEncryptionCustomerKey', name: 'serversideEncryptionCustomerKey',
type: 'string', type: 'string',
default: '', default: '',
description: 'Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data', description:
'Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data',
}, },
{ {
displayName: 'Server Side Encryption Customer Key MD5', displayName: 'Server Side Encryption Customer Key MD5',
@ -331,13 +322,14 @@ export const fileFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request', description:
'Specifies whether the metadata is copied from the source object or replaced with metadata provided in the request',
}, },
], ],
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* file:upload */ /* file:upload */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -346,12 +338,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['upload'],
],
operation: [
'upload',
],
}, },
}, },
}, },
@ -364,15 +352,9 @@ export const fileFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['upload'],
], binaryData: [false],
operation: [
'upload',
],
binaryData: [
false,
],
}, },
}, },
}, },
@ -383,15 +365,9 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['upload'],
], binaryData: [true],
operation: [
'upload',
],
binaryData: [
true,
],
}, },
}, },
description: 'If not set the binary data filename will be used', description: 'If not set the binary data filename will be used',
@ -403,12 +379,8 @@ export const fileFields: INodeProperties[] = [
default: true, default: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upload'],
'upload', resource: ['file'],
],
resource: [
'file',
],
}, },
}, },
description: 'Whether the data to upload should be taken from binary field', description: 'Whether the data to upload should be taken from binary field',
@ -420,15 +392,9 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upload'],
'upload', resource: ['file'],
], binaryData: [false],
resource: [
'file',
],
binaryData: [
false,
],
}, },
}, },
placeholder: '', placeholder: '',
@ -442,17 +408,10 @@ export const fileFields: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['upload'],
'upload', resource: ['file'],
], binaryData: [true],
resource: [
'file',
],
binaryData: [
true,
],
}, },
}, },
placeholder: '', placeholder: '',
description: 'Name of the binary property which contains the data for the file to be uploaded', description: 'Name of the binary property which contains the data for the file to be uploaded',
@ -464,12 +423,8 @@ export const fileFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['upload'],
],
operation: [
'upload',
],
}, },
}, },
default: {}, default: {},
@ -516,7 +471,8 @@ export const fileFields: INodeProperties[] = [
name: 'grantFullControl', name: 'grantFullControl',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object', description:
'Whether to give the grantee READ, READ_ACP, and WRITE_ACP permissions on the object',
}, },
{ {
displayName: 'Grant Read', displayName: 'Grant Read',
@ -568,7 +524,7 @@ export const fileFields: INodeProperties[] = [
name: 'lockRetainUntilDate', name: 'lockRetainUntilDate',
type: 'dateTime', type: 'dateTime',
default: '', default: '',
description: 'The date and time when you want this object\'s Object Lock to expire', description: "The date and time when you want this object's Object Lock to expire",
}, },
{ {
displayName: 'Parent Folder Key', displayName: 'Parent Folder Key',
@ -582,7 +538,8 @@ export const fileFields: INodeProperties[] = [
name: 'requesterPays', name: 'requesterPays',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.', description:
'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.',
}, },
{ {
displayName: 'Server Side Encryption', displayName: 'Server Side Encryption',
@ -599,7 +556,8 @@ export const fileFields: INodeProperties[] = [
}, },
], ],
default: '', default: '',
description: 'The server-side encryption algorithm used when storing this object in Amazon S3', description:
'The server-side encryption algorithm used when storing this object in Amazon S3',
}, },
{ {
displayName: 'Server Side Encryption Context', displayName: 'Server Side Encryption Context',
@ -620,14 +578,16 @@ export const fileFields: INodeProperties[] = [
name: 'serversideEncryptionCustomerAlgorithm', name: 'serversideEncryptionCustomerAlgorithm',
type: 'string', type: 'string',
default: '', default: '',
description: 'Specifies the algorithm to use to when encrypting the object (for example, AES256)', description:
'Specifies the algorithm to use to when encrypting the object (for example, AES256)',
}, },
{ {
displayName: 'Server Side Encryption Customer Key', displayName: 'Server Side Encryption Customer Key',
name: 'serversideEncryptionCustomerKey', name: 'serversideEncryptionCustomerKey',
type: 'string', type: 'string',
default: '', default: '',
description: 'Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data', description:
'Specifies the customer-provided encryption key for Amazon S3 to use in encrypting data',
}, },
{ {
displayName: 'Server Side Encryption Customer Key MD5', displayName: 'Server Side Encryption Customer Key MD5',
@ -682,12 +642,8 @@ export const fileFields: INodeProperties[] = [
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['upload'],
],
operation: [
'upload',
],
}, },
}, },
options: [ options: [
@ -712,9 +668,9 @@ export const fileFields: INodeProperties[] = [
], ],
description: 'Optional extra headers to add to the message (most headers are allowed)', description: 'Optional extra headers to add to the message (most headers are allowed)',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* file:download */ /* file:download */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -723,12 +679,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['download'],
],
operation: [
'download',
],
}, },
}, },
}, },
@ -740,12 +692,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['download'],
],
operation: [
'download',
],
}, },
}, },
}, },
@ -757,19 +705,15 @@ export const fileFields: INodeProperties[] = [
default: 'data', default: 'data',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['download'],
'download', resource: ['file'],
],
resource: [
'file',
],
}, },
}, },
description: 'Name of the binary property to which to write the data of the read file', description: 'Name of the binary property to which to write the data of the read file',
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* file:delete */ /* file:delete */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -778,12 +722,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
}, },
@ -795,12 +735,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
}, },
@ -812,12 +748,8 @@ export const fileFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
options: [ options: [
@ -829,9 +761,9 @@ export const fileFields: INodeProperties[] = [
}, },
], ],
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* file:getAll */ /* file:getAll */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -840,12 +772,8 @@ export const fileFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -855,12 +783,8 @@ export const fileFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['file'],
],
resource: [
'file',
],
}, },
}, },
default: false, default: false,
@ -872,15 +796,9 @@ export const fileFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['file'],
], returnAll: [false],
resource: [
'file',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -898,12 +816,8 @@ export const fileFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['file'],
'file', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -913,7 +827,8 @@ export const fileFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
default: false, default: false,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true', description:
'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true',
}, },
{ {
displayName: 'Folder Key', displayName: 'Folder Key',

View file

@ -1,6 +1,4 @@
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export const folderOperations: INodeProperties[] = [ export const folderOperations: INodeProperties[] = [
{ {
@ -10,9 +8,7 @@ export const folderOperations: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder',
],
}, },
}, },
options: [ options: [
@ -40,10 +36,9 @@ export const folderOperations: INodeProperties[] = [
]; ];
export const folderFields: INodeProperties[] = [ export const folderFields: INodeProperties[] = [
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */ /* folder:create */
/* folder:create */ /* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -52,12 +47,8 @@ export const folderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -69,12 +60,8 @@ export const folderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
}, },
@ -85,12 +72,8 @@ export const folderFields: INodeProperties[] = [
placeholder: 'Add Field', placeholder: 'Add Field',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
default: {}, default: {},
@ -107,7 +90,8 @@ export const folderFields: INodeProperties[] = [
name: 'requesterPays', name: 'requesterPays',
type: 'boolean', type: 'boolean',
default: false, default: false,
description: 'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.', description:
'Whether the requester will pay for requests and data transfer. While Requester Pays is enabled, anonymous access to this bucket is disabled.',
}, },
{ {
displayName: 'Storage Class', displayName: 'Storage Class',
@ -148,9 +132,9 @@ export const folderFields: INodeProperties[] = [
}, },
], ],
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* folder:delete */ /* folder:delete */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -159,12 +143,8 @@ export const folderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
}, },
@ -176,18 +156,14 @@ export const folderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['delete'],
],
operation: [
'delete',
],
}, },
}, },
}, },
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
/* folder:getAll */ /* folder:getAll */
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
{ {
displayName: 'Bucket Name', displayName: 'Bucket Name',
name: 'bucketName', name: 'bucketName',
@ -196,12 +172,8 @@ export const folderFields: INodeProperties[] = [
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
}, },
@ -211,12 +183,8 @@ export const folderFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['folder'],
],
resource: [
'folder',
],
}, },
}, },
default: false, default: false,
@ -228,15 +196,9 @@ export const folderFields: INodeProperties[] = [
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['getAll'],
'getAll', resource: ['folder'],
], returnAll: [false],
resource: [
'folder',
],
returnAll: [
false,
],
}, },
}, },
typeOptions: { typeOptions: {
@ -254,12 +216,8 @@ export const folderFields: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['folder'],
'folder', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -269,7 +227,8 @@ export const folderFields: INodeProperties[] = [
type: 'boolean', type: 'boolean',
default: false, default: false,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true', description:
'The owner field is not present in listV2 by default, if you want to return owner field with each key in the result then set the fetch owner field to true',
}, },
{ {
displayName: 'Folder Key', displayName: 'Folder Key',

View file

@ -1,23 +1,12 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { get } from 'lodash';
get,
} from 'lodash';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { parseString } from 'xml2js';
parseString,
} from 'xml2js';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -26,21 +15,41 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { IDataObject, JsonObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
IDataObject, JsonObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string | Buffer,
query: IDataObject = {},
headers?: object,
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
const endpoint = new URL(((credentials.s3Endpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); const endpoint = new URL(
(((credentials.s3Endpoint as string) || '').replace('{region}', credentials.region as string) ||
`https://${service}.${credentials.region}.amazonaws.com`) + path,
);
// Sign AWS API request with the user credentials // Sign AWS API request with the user credentials
const signOpts = {headers: headers || {}, host: endpoint.host, method, path: `${endpoint.pathname}?${queryToString(query).replace(/\+/g, '%2B')}`, body} as Request; const signOpts = {
headers: headers || {},
host: endpoint.host,
method,
path: `${endpoint.pathname}?${queryToString(query).replace(/\+/g, '%2B')}`,
body,
} as Request;
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -59,12 +68,33 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
try { try {
return await this.helpers.request!(options); return await this.helpers.request!(options);
} catch (error) { } catch (error) {
throw new NodeApiError(this.getNode(), (error as JsonObject)); throw new NodeApiError(this.getNode(), error as JsonObject);
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers?: object, options: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
const response = await awsApiRequest.call(this, service, method, path, body, query, headers, options, region); this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers?: object,
options: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(
this,
service,
method,
path,
body,
query,
headers,
options,
region,
);
try { try {
return JSON.parse(response); return JSON.parse(response);
} catch (error) { } catch (error) {
@ -72,8 +102,29 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string | Buffer, query: IDataObject = {}, headers?: object, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
const response = await awsApiRequest.call(this, service, method, path, body, query, headers, option, region); this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string | Buffer,
query: IDataObject = {},
headers?: object,
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(
this,
service,
method,
path,
body,
query,
headers,
option,
region,
);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
parseString(response, { explicitArray: false }, (err, data) => { parseString(response, { explicitArray: false }, (err, data) => {
@ -88,18 +139,42 @@ export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, propertyName: string, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers: IDataObject = {}, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAPAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
propertyName: string,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers: IDataObject = {},
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
do { do {
responseData = await awsApiRequestSOAP.call(this, service, method, path, body, query, headers, option, region); responseData = await awsApiRequestSOAP.call(
this,
service,
method,
path,
body,
query,
headers,
option,
region,
);
//https://forums.aws.amazon.com/thread.jspa?threadID=55746 //https://forums.aws.amazon.com/thread.jspa?threadID=55746
if (get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`)) { if (get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`)) {
query['continuation-token'] = get(responseData, `${propertyName.split('.')[0]}.NextContinuationToken`); query['continuation-token'] = get(
responseData,
`${propertyName.split('.')[0]}.NextContinuationToken`,
);
} }
if (get(responseData, propertyName)) { if (get(responseData, propertyName)) {
if (Array.isArray(get(responseData, propertyName))) { if (Array.isArray(get(responseData, propertyName))) {
@ -120,5 +195,7 @@ export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteF
} }
function queryToString(params: IDataObject) { function queryToString(params: IDataObject) {
return Object.keys(params).map(key => key + '=' + params[key]).join('&'); return Object.keys(params)
.map((key) => key + '=' + params[key])
.join('&');
} }

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,10 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { parseString } from 'xml2js';
parseString,
} from 'xml2js';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -22,18 +13,27 @@ import {
IWebhookFunctions, IWebhookFunctions,
} from 'n8n-core'; } from 'n8n-core';
import { import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
IDataObject, NodeApiError, NodeOperationError,
} from 'n8n-workflow';
import { import { get } from 'lodash';
get,
} from 'lodash';
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
const endpoint = new URL(((credentials.sesEndpoint as string || '').replace('{region}', credentials.region as string) || `https://${service}.${credentials.region}.amazonaws.com`) + path); const endpoint = new URL(
(((credentials.sesEndpoint as string) || '').replace(
'{region}',
credentials.region as string,
) || `https://${service}.${credentials.region}.amazonaws.com`) + path,
);
// Sign AWS API request with the user credentials // Sign AWS API request with the user credentials
@ -41,7 +41,9 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -60,7 +62,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return JSON.parse(response); return JSON.parse(response);
@ -69,7 +79,15 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
@ -85,9 +103,19 @@ export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAPAllItems(
export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, propertyName: string, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers: IDataObject = {}, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
propertyName: string,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers: IDataObject = {},
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -98,7 +126,10 @@ export async function awsApiRequestSOAPAllItems(this: IHookFunctions | IExecuteF
responseData = await awsApiRequestSOAP.call(this, service, method, path, body, query); responseData = await awsApiRequestSOAP.call(this, service, method, path, body, query);
if (get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`)) { if (get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`)) {
query['NextToken'] = get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`); query['NextToken'] = get(
responseData,
`${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`,
);
} }
if (get(responseData, propertyName)) { if (get(responseData, propertyName)) {
if (Array.isArray(get(responseData, propertyName))) { if (Array.isArray(get(responseData, propertyName))) {

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IDataObject, IDataObject,
@ -14,17 +12,11 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { URL } from 'url';
URL,
} from 'url';
import { import { awsApiRequestSOAP } from '../GenericFunctions';
awsApiRequestSOAP,
} from '../GenericFunctions';
import { import { pascalCase } from 'change-case';
pascalCase,
} from 'change-case';
export class AwsSqs implements INodeType { export class AwsSqs implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -71,15 +63,14 @@ export class AwsSqs implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['sendMessage'],
'sendMessage',
],
}, },
}, },
options: [], options: [],
default: '', default: '',
required: true, required: true,
description: 'Queue to send a message to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.', description:
'Queue to send a message to. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code-examples/expressions/">expression</a>.',
}, },
{ {
displayName: 'Queue Type', displayName: 'Queue Type',
@ -112,12 +103,8 @@ export class AwsSqs implements INodeType {
type: 'string', type: 'string',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['sendMessage'],
'sendMessage', sendInputData: [false],
],
sendInputData: [
false,
],
}, },
}, },
required: true, required: true,
@ -132,12 +119,11 @@ export class AwsSqs implements INodeType {
name: 'messageGroupId', name: 'messageGroupId',
type: 'string', type: 'string',
default: '', default: '',
description: 'Tag that specifies that a message belongs to a specific message group. Applies only to FIFO (first-in-first-out) queues.', description:
'Tag that specifies that a message belongs to a specific message group. Applies only to FIFO (first-in-first-out) queues.',
displayOptions: { displayOptions: {
show: { show: {
queueType: [ queueType: ['fifo'],
'fifo',
],
}, },
}, },
required: true, required: true,
@ -148,9 +134,7 @@ export class AwsSqs implements INodeType {
type: 'collection', type: 'collection',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['sendMessage'],
'sendMessage',
],
}, },
}, },
default: {}, default: {},
@ -162,9 +146,7 @@ export class AwsSqs implements INodeType {
type: 'number', type: 'number',
displayOptions: { displayOptions: {
show: { show: {
'/queueType': [ '/queueType': ['standard'],
'standard',
],
}, },
}, },
description: 'How long, in seconds, to delay a message for', description: 'How long, in seconds, to delay a message for',
@ -201,7 +183,8 @@ export class AwsSqs implements INodeType {
name: 'dataPropertyName', name: 'dataPropertyName',
type: 'string', type: 'string',
default: 'data', default: 'data',
description: 'Name of the binary property which contains the data for the message attribute', description:
'Name of the binary property which contains the data for the message attribute',
}, },
], ],
}, },
@ -252,12 +235,11 @@ export class AwsSqs implements INodeType {
name: 'messageDeduplicationId', name: 'messageDeduplicationId',
type: 'string', type: 'string',
default: '', default: '',
description: 'Token used for deduplication of sent messages. Applies only to FIFO (first-in-first-out) queues.', description:
'Token used for deduplication of sent messages. Applies only to FIFO (first-in-first-out) queues.',
displayOptions: { displayOptions: {
show: { show: {
'/queueType': [ '/queueType': ['fifo'],
'fifo',
],
}, },
}, },
}, },
@ -270,10 +252,7 @@ export class AwsSqs implements INodeType {
loadOptions: { loadOptions: {
// Get all the available queues to display them to user so that it can be selected easily // Get all the available queues to display them to user so that it can be selected easily
async getQueues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> { async getQueues(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const params = [ const params = ['Version=2012-11-05', `Action=ListQueues`];
'Version=2012-11-05',
`Action=ListQueues`,
];
let data; let data;
try { try {
@ -307,7 +286,6 @@ export class AwsSqs implements INodeType {
}, },
}; };
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> { async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData(); const items = this.getInputData();
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
@ -319,15 +297,14 @@ export class AwsSqs implements INodeType {
const queueUrl = this.getNodeParameter('queue', i) as string; const queueUrl = this.getNodeParameter('queue', i) as string;
const queuePath = new URL(queueUrl).pathname; const queuePath = new URL(queueUrl).pathname;
const params = [ const params = ['Version=2012-11-05', `Action=${pascalCase(operation)}`];
'Version=2012-11-05',
`Action=${pascalCase(operation)}`,
];
const options = this.getNodeParameter('options', i, {}) as IDataObject; const options = this.getNodeParameter('options', i, {}) as IDataObject;
const sendInputData = this.getNodeParameter('sendInputData', i) as boolean; const sendInputData = this.getNodeParameter('sendInputData', i) as boolean;
const message = sendInputData ? JSON.stringify(items[i].json) : this.getNodeParameter('message', i) as string; const message = sendInputData
? JSON.stringify(items[i].json)
: (this.getNodeParameter('message', i) as string);
params.push(`MessageBody=${message}`); params.push(`MessageBody=${message}`);
if (options.delaySeconds) { if (options.delaySeconds) {
@ -336,7 +313,11 @@ export class AwsSqs implements INodeType {
const queueType = this.getNodeParameter('queueType', i, {}) as string; const queueType = this.getNodeParameter('queueType', i, {}) as string;
if (queueType === 'fifo') { if (queueType === 'fifo') {
const messageDeduplicationId = this.getNodeParameter('options.messageDeduplicationId', i, '') as string; const messageDeduplicationId = this.getNodeParameter(
'options.messageDeduplicationId',
i,
'',
) as string;
if (messageDeduplicationId) { if (messageDeduplicationId) {
params.push(`MessageDeduplicationId=${messageDeduplicationId}`); params.push(`MessageDeduplicationId=${messageDeduplicationId}`);
} }
@ -349,7 +330,9 @@ export class AwsSqs implements INodeType {
let attributeCount = 0; let attributeCount = 0;
// Add string values // Add string values
(this.getNodeParameter('options.messageAttributes.string', i, []) as INodeParameters[]).forEach((attribute) => { (
this.getNodeParameter('options.messageAttributes.string', i, []) as INodeParameters[]
).forEach((attribute) => {
attributeCount++; attributeCount++;
params.push(`MessageAttribute.${attributeCount}.Name=${attribute.name}`); params.push(`MessageAttribute.${attributeCount}.Name=${attribute.name}`);
params.push(`MessageAttribute.${attributeCount}.Value.StringValue=${attribute.value}`); params.push(`MessageAttribute.${attributeCount}.Value.StringValue=${attribute.value}`);
@ -357,17 +340,27 @@ export class AwsSqs implements INodeType {
}); });
// Add binary values // Add binary values
(this.getNodeParameter('options.messageAttributes.binary', i, []) as INodeParameters[]).forEach((attribute) => { (
this.getNodeParameter('options.messageAttributes.binary', i, []) as INodeParameters[]
).forEach((attribute) => {
attributeCount++; attributeCount++;
const dataPropertyName = attribute.dataPropertyName as string; const dataPropertyName = attribute.dataPropertyName as string;
const item = items[i]; const item = items[i];
if (item.binary === undefined) { if (item.binary === undefined) {
throw new NodeOperationError(this.getNode(), 'No binary data set. So message attribute cannot be added!', { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
'No binary data set. So message attribute cannot be added!',
{ itemIndex: i },
);
} }
if (item.binary[dataPropertyName] === undefined) { if (item.binary[dataPropertyName] === undefined) {
throw new NodeOperationError(this.getNode(), `The binary property "${dataPropertyName}" does not exist. So message attribute cannot be added!`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`The binary property "${dataPropertyName}" does not exist. So message attribute cannot be added!`,
{ itemIndex: i },
);
} }
const binaryData = item.binary[dataPropertyName].data; const binaryData = item.binary[dataPropertyName].data;
@ -378,7 +371,9 @@ export class AwsSqs implements INodeType {
}); });
// Add number values // Add number values
(this.getNodeParameter('options.messageAttributes.number', i, []) as INodeParameters[]).forEach((attribute) => { (
this.getNodeParameter('options.messageAttributes.number', i, []) as INodeParameters[]
).forEach((attribute) => {
attributeCount++; attributeCount++;
params.push(`MessageAttribute.${attributeCount}.Name=${attribute.name}`); params.push(`MessageAttribute.${attributeCount}.Name=${attribute.name}`);
params.push(`MessageAttribute.${attributeCount}.Value.StringValue=${attribute.value}`); params.push(`MessageAttribute.${attributeCount}.Value.StringValue=${attribute.value}`);
@ -387,7 +382,12 @@ export class AwsSqs implements INodeType {
let responseData; let responseData;
try { try {
responseData = await awsApiRequestSOAP.call(this, 'sqs', 'GET', `${queuePath}?${params.join('&')}`); responseData = await awsApiRequestSOAP.call(
this,
'sqs',
'GET',
`${queuePath}?${params.join('&')}`,
);
} catch (error) { } catch (error) {
throw new NodeApiError(this.getNode(), error); throw new NodeApiError(this.getNode(), error);
} }

View file

@ -1,6 +1,4 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import {
IBinaryKeyData, IBinaryKeyData,
@ -64,13 +62,12 @@ export class AwsTextract implements INodeType {
default: 'data', default: 'data',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyzeExpense'],
'analyzeExpense',
],
}, },
}, },
required: true, required: true,
description: 'The name of the input field containing the binary file data to be uploaded. Supported file types: PNG, JPEG.', description:
'The name of the input field containing the binary file data to be uploaded. Supported file types: PNG, JPEG.',
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -78,22 +75,28 @@ export class AwsTextract implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['analyzeExpense'],
'analyzeExpense',
],
}, },
}, },
default: true, default: true,
description: 'Whether to return a simplified version of the response instead of the raw data', description:
'Whether to return a simplified version of the response instead of the raw data',
}, },
], ],
}; };
methods = { methods = {
credentialTest: { credentialTest: {
async awsTextractApiCredentialTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult> { async awsTextractApiCredentialTest(
this: ICredentialTestFunctions,
credential: ICredentialsDecrypted,
): Promise<INodeCredentialTestResult> {
try { try {
await validateCredentials.call(this, credential.data as ICredentialDataDecryptedObject, 'sts'); await validateCredentials.call(
this,
credential.data as ICredentialDataDecryptedObject,
'sts',
);
} catch (error) { } catch (error) {
return { return {
status: 'Error', status: 'Error',
@ -122,11 +125,17 @@ export class AwsTextract implements INodeType {
const simple = this.getNodeParameter('simple', i) as boolean; const simple = this.getNodeParameter('simple', i) as boolean;
if (items[i].binary === undefined) { if (items[i].binary === undefined) {
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', { itemIndex: i }); throw new NodeOperationError(this.getNode(), 'No binary data exists on item!', {
itemIndex: i,
});
} }
if ((items[i].binary as IBinaryKeyData)[binaryProperty] === undefined) { if ((items[i].binary as IBinaryKeyData)[binaryProperty] === undefined) {
throw new NodeOperationError(this.getNode(), `No binary data property "${binaryProperty}" does not exists on item!`, { itemIndex: i }); throw new NodeOperationError(
this.getNode(),
`No binary data property "${binaryProperty}" does not exists on item!`,
{ itemIndex: i },
);
} }
const binaryPropertyData = (items[i].binary as IBinaryKeyData)[binaryProperty]; const binaryPropertyData = (items[i].binary as IBinaryKeyData)[binaryProperty];
@ -138,7 +147,14 @@ export class AwsTextract implements INodeType {
}; };
const action = 'Textract.AnalyzeExpense'; const action = 'Textract.AnalyzeExpense';
responseData = await awsApiRequestREST.call(this, 'textract', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }) as IExpenseDocument; responseData = (await awsApiRequestREST.call(
this,
'textract',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
)) as IExpenseDocument;
if (simple) { if (simple) {
responseData = simplify(responseData); responseData = simplify(responseData);
} }

View file

@ -1,19 +1,10 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import { parseString } from 'xml2js';
parseString,
} from 'xml2js';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -29,7 +20,10 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string { function getEndpointForService(
service: string,
credentials: ICredentialDataDecryptedObject,
): string {
let endpoint; let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) { if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint; endpoint = credentials.lambdaEndpoint;
@ -41,7 +35,15 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr
return (endpoint as string).replace('{region}', credentials.region as string); return (endpoint as string).replace('{region}', credentials.region as string);
} }
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
@ -52,7 +54,9 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -73,7 +77,8 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const user = JSON.parse(errorMessage).Message.split(' ')[1]; const user = JSON.parse(errorMessage).Message.split(' ')[1];
throw new NodeApiError(this.getNode(), error, { throw new NodeApiError(this.getNode(), error, {
message: 'Unauthorized — please check your AWS policy configuration', message: 'Unauthorized — please check your AWS policy configuration',
description: `Make sure an identity-based policy allows user ${user} to perform textract:AnalyzeExpense` }); description: `Make sure an identity-based policy allows user ${user} to perform textract:AnalyzeExpense`,
});
} }
} }
@ -81,7 +86,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return JSON.parse(response); return JSON.parse(response);
@ -90,7 +103,15 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestSOAP(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestSOAP(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
@ -121,25 +142,40 @@ export interface IExpenseDocument {
{ {
SummaryFields: [ SummaryFields: [
{ {
LabelDetection: { Text: string }, LabelDetection: { Text: string };
ValueDetection: { Text: string }, ValueDetection: { Text: string };
Type: { Text: string } Type: { Text: string };
}] },
}]; ];
},
];
} }
export async function validateCredentials(this: ICredentialTestFunctions, decryptedCredentials: ICredentialDataDecryptedObject, service: string): Promise<any> { // tslint:disable-line:no-any export async function validateCredentials(
this: ICredentialTestFunctions,
decryptedCredentials: ICredentialDataDecryptedObject,
service: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = decryptedCredentials; const credentials = decryptedCredentials;
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
const endpoint = new URL(getEndpointForService(service, credentials) + `?Action=GetCallerIdentity&Version=2011-06-15`); const endpoint = new URL(
getEndpointForService(service, credentials) + `?Action=GetCallerIdentity&Version=2011-06-15`,
);
// Sign AWS API request with the user credentials // Sign AWS API request with the user credentials
const signOpts = { host: endpoint.host, method: 'POST', path: '?Action=GetCallerIdentity&Version=2011-06-15' } as Request; const signOpts = {
host: endpoint.host,
method: 'POST',
path: '?Action=GetCallerIdentity&Version=2011-06-15',
} as Request;
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);

View file

@ -1,18 +1,8 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';
import { import { awsApiRequestREST, awsApiRequestRESTAllItems } from './GenericFunctions';
awsApiRequestREST,
awsApiRequestRESTAllItems,
} from './GenericFunctions';
export class AwsTranscribe implements INodeType { export class AwsTranscribe implements INodeType {
description: INodeTypeDescription = { description: INodeTypeDescription = {
@ -88,14 +78,8 @@ export class AwsTranscribe implements INodeType {
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['create', 'get', 'delete'],
],
operation: [
'create',
'get',
'delete',
],
}, },
}, },
description: 'The name of the job', description: 'The name of the job',
@ -107,12 +91,8 @@ export class AwsTranscribe implements INodeType {
default: '', default: '',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
description: 'The S3 object location of the input media file', description: 'The S3 object location of the input media file',
@ -123,16 +103,13 @@ export class AwsTranscribe implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['create'],
],
operation: [
'create',
],
}, },
}, },
default: false, default: false,
description: 'Whether to set this field to true to enable automatic language identification', description:
'Whether to set this field to true to enable automatic language identification',
}, },
{ {
displayName: 'Language', displayName: 'Language',
@ -170,15 +147,9 @@ export class AwsTranscribe implements INodeType {
], ],
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['create'],
], detectLanguage: [false],
operation: [
'create',
],
detectLanguage: [
false,
],
}, },
}, },
default: 'en-US', default: 'en-US',
@ -194,9 +165,7 @@ export class AwsTranscribe implements INodeType {
placeholder: 'Add Option', placeholder: 'Add Option',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create',
],
}, },
}, },
default: {}, default: {},
@ -207,7 +176,8 @@ export class AwsTranscribe implements INodeType {
type: 'boolean', type: 'boolean',
default: false, default: false,
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'Instructs Amazon Transcribe to process each audiochannel separately and then merge the transcription output of each channel into a single transcription. You can\'t set both Max Speaker Labels and Channel Identification in the same request. If you set both, your request returns a BadRequestException.', description:
"Instructs Amazon Transcribe to process each audiochannel separately and then merge the transcription output of each channel into a single transcription. You can't set both Max Speaker Labels and Channel Identification in the same request. If you set both, your request returns a BadRequestException.",
}, },
{ {
displayName: 'Max Alternatives', displayName: 'Max Alternatives',
@ -229,7 +199,8 @@ export class AwsTranscribe implements INodeType {
minValue: 2, minValue: 2,
maxValue: 10, maxValue: 10,
}, },
description: 'The maximum number of speakers to identify in the input audio. If there are more speakers in the audio than this number, multiple speakers are identified as a single speaker.', description:
'The maximum number of speakers to identify in the input audio. If there are more speakers in the audio than this number, multiple speakers are identified as a single speaker.',
}, },
{ {
displayName: 'Vocabulary Name', displayName: 'Vocabulary Name',
@ -243,7 +214,8 @@ export class AwsTranscribe implements INodeType {
name: 'vocabularyFilterName', name: 'vocabularyFilterName',
type: 'string', type: 'string',
default: '', default: '',
description: 'The name of the vocabulary filter to use when transcribing the audio. The filter that you specify must have the same language code as the transcription job.', description:
'The name of the vocabulary filter to use when transcribing the audio. The filter that you specify must have the same language code as the transcription job.',
}, },
{ {
displayName: 'Vocabulary Filter Method', displayName: 'Vocabulary Filter Method',
@ -262,10 +234,10 @@ export class AwsTranscribe implements INodeType {
name: 'Tag', name: 'Tag',
value: 'tag', value: 'tag',
}, },
], ],
default: 'remove', default: 'remove',
description: '<p>Set to mask to remove filtered text from the transcript and replace it with three asterisks ("***") as placeholder text.</p><p>Set to remove to remove filtered text from the transcript without using placeholder text. Set to tag to mark the word in the transcription output that matches the vocabulary filter. When you set the filter method to tag, the words matching your vocabulary filter are not masked or removed.</p>', description:
'<p>Set to mask to remove filtered text from the transcript and replace it with three asterisks ("***") as placeholder text.</p><p>Set to remove to remove filtered text from the transcript without using placeholder text. Set to tag to mark the word in the transcription output that matches the vocabulary filter. When you set the filter method to tag, the words matching your vocabulary filter are not masked or removed.</p>',
}, },
], ],
}, },
@ -276,16 +248,13 @@ export class AwsTranscribe implements INodeType {
default: true, default: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['get'],
],
operation: [
'get',
],
}, },
}, },
// eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether // eslint-disable-next-line n8n-nodes-base/node-param-description-boolean-without-whether
description: 'By default, the response only contains metadata about the transcript. Enable this option to retrieve the transcript instead.', description:
'By default, the response only contains metadata about the transcript. Enable this option to retrieve the transcript instead.',
}, },
{ {
displayName: 'Simplify', displayName: 'Simplify',
@ -293,19 +262,14 @@ export class AwsTranscribe implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['get'],
], returnTranscript: [true],
operation: [
'get',
],
returnTranscript: [
true,
],
}, },
}, },
default: true, default: true,
description: 'Whether to return a simplified version of the response instead of the raw data', description:
'Whether to return a simplified version of the response instead of the raw data',
}, },
{ {
displayName: 'Return All', displayName: 'Return All',
@ -313,12 +277,8 @@ export class AwsTranscribe implements INodeType {
type: 'boolean', type: 'boolean',
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
default: false, default: false,
@ -334,15 +294,9 @@ export class AwsTranscribe implements INodeType {
}, },
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['getAll'],
], returnAll: [false],
operation: [
'getAll',
],
returnAll: [
false,
],
}, },
}, },
description: 'Max number of results to return', description: 'Max number of results to return',
@ -355,12 +309,8 @@ export class AwsTranscribe implements INodeType {
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['transcriptionJob'],
'transcriptionJob', operation: ['getAll'],
],
operation: [
'getAll',
],
}, },
}, },
options: [ options: [
@ -433,7 +383,9 @@ export class AwsTranscribe implements INodeType {
} }
if (options.channelIdentification) { if (options.channelIdentification) {
Object.assign(body.Settings, { ChannelIdentification: options.channelIdentification }); Object.assign(body.Settings, {
ChannelIdentification: options.channelIdentification,
});
} }
if (options.maxAlternatives) { if (options.maxAlternatives) {
@ -469,7 +421,14 @@ export class AwsTranscribe implements INodeType {
} }
const action = 'Transcribe.StartTranscriptionJob'; const action = 'Transcribe.StartTranscriptionJob';
responseData = await awsApiRequestREST.call(this, 'transcribe', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'transcribe',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = responseData.TranscriptionJob; responseData = responseData.TranscriptionJob;
} }
//https://docs.aws.amazon.com/transcribe/latest/dg/API_DeleteTranscriptionJob.html //https://docs.aws.amazon.com/transcribe/latest/dg/API_DeleteTranscriptionJob.html
@ -481,7 +440,14 @@ export class AwsTranscribe implements INodeType {
}; };
const action = 'Transcribe.DeleteTranscriptionJob'; const action = 'Transcribe.DeleteTranscriptionJob';
responseData = await awsApiRequestREST.call(this, 'transcribe', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'transcribe',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = { success: true }; responseData = { success: true };
} }
//https://docs.aws.amazon.com/transcribe/latest/dg/API_GetTranscriptionJob.html //https://docs.aws.amazon.com/transcribe/latest/dg/API_GetTranscriptionJob.html
@ -494,14 +460,29 @@ export class AwsTranscribe implements INodeType {
}; };
const action = 'Transcribe.GetTranscriptionJob'; const action = 'Transcribe.GetTranscriptionJob';
responseData = await awsApiRequestREST.call(this, 'transcribe', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'transcribe',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = responseData.TranscriptionJob; responseData = responseData.TranscriptionJob;
if (resolve === true && responseData.TranscriptionJobStatus === 'COMPLETED') { if (resolve === true && responseData.TranscriptionJobStatus === 'COMPLETED') {
responseData = await this.helpers.request({ method: 'GET', uri: responseData.Transcript.TranscriptFileUri, json: true }); responseData = await this.helpers.request({
method: 'GET',
uri: responseData.Transcript.TranscriptFileUri,
json: true,
});
const simple = this.getNodeParameter('simple', 0) as boolean; const simple = this.getNodeParameter('simple', 0) as boolean;
if (simple === true) { if (simple === true) {
responseData = { transcript: responseData.results.transcripts.map((data: IDataObject) => data.transcript).join(' ') }; responseData = {
transcript: responseData.results.transcripts
.map((data: IDataObject) => data.transcript)
.join(' '),
};
} }
} }
} }
@ -521,12 +502,26 @@ export class AwsTranscribe implements INodeType {
} }
if (returnAll === true) { if (returnAll === true) {
responseData = await awsApiRequestRESTAllItems.call(this, 'TranscriptionJobSummaries', 'transcribe', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestRESTAllItems.call(
this,
'TranscriptionJobSummaries',
'transcribe',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
} else { } else {
const limit = this.getNodeParameter('limit', i) as number; const limit = this.getNodeParameter('limit', i) as number;
body['MaxResults'] = limit; body['MaxResults'] = limit;
responseData = await awsApiRequestREST.call(this, 'transcribe', 'POST', '', JSON.stringify(body), { 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' }); responseData = await awsApiRequestREST.call(
this,
'transcribe',
'POST',
'',
JSON.stringify(body),
{ 'x-amz-target': action, 'Content-Type': 'application/x-amz-json-1.1' },
);
responseData = responseData.TranscriptionJobSummaries; responseData = responseData.TranscriptionJobSummaries;
} }
} }
@ -537,7 +532,6 @@ export class AwsTranscribe implements INodeType {
} else { } else {
returnData.push(responseData as IDataObject); returnData.push(responseData as IDataObject);
} }
} catch (error) { } catch (error) {
if (this.continueOnFail()) { if (this.continueOnFail()) {
returnData.push({ error: error.message }); returnData.push({ error: error.message });

View file

@ -1,15 +1,8 @@
import { import { URL } from 'url';
URL,
} from 'url';
import { import { Request, sign } from 'aws4';
Request,
sign,
} from 'aws4';
import { import { OptionsWithUri } from 'request';
OptionsWithUri,
} from 'request';
import { import {
IExecuteFunctions, IExecuteFunctions,
@ -25,11 +18,12 @@ import {
NodeOperationError, NodeOperationError,
} from 'n8n-workflow'; } from 'n8n-workflow';
import { import { get } from 'lodash';
get,
} from 'lodash';
function getEndpointForService(service: string, credentials: ICredentialDataDecryptedObject): string { function getEndpointForService(
service: string,
credentials: ICredentialDataDecryptedObject,
): string {
let endpoint; let endpoint;
if (service === 'lambda' && credentials.lambdaEndpoint) { if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint; endpoint = credentials.lambdaEndpoint;
@ -41,7 +35,15 @@ function getEndpointForService(service: string, credentials: ICredentialDataDecr
return (endpoint as string).replace('{region}', credentials.region as string); return (endpoint as string).replace('{region}', credentials.region as string);
} }
export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequest(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions | IWebhookFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws'); const credentials = await this.getCredentials('aws');
// Concatenate path and instantiate URL object so it parses correctly query strings // Concatenate path and instantiate URL object so it parses correctly query strings
@ -52,7 +54,9 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
const securityHeaders = { const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(), accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(), secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined, sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
}; };
sign(signOpts, securityHeaders); sign(signOpts, securityHeaders);
@ -71,7 +75,15 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I
} }
} }
export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, service: string, method: string, path: string, body?: string, headers?: object): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestREST(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
service: string,
method: string,
path: string,
body?: string,
headers?: object,
// tslint:disable-next-line:no-any
): Promise<any> {
const response = await awsApiRequest.call(this, service, method, path, body, headers); const response = await awsApiRequest.call(this, service, method, path, body, headers);
try { try {
return JSON.parse(response); return JSON.parse(response);
@ -80,8 +92,19 @@ export async function awsApiRequestREST(this: IHookFunctions | IExecuteFunctions
} }
} }
export async function awsApiRequestRESTAllItems(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, service: string, method: string, path: string, body?: string, query: IDataObject = {}, headers: IDataObject = {}, option: IDataObject = {}, region?: string): Promise<any> { // tslint:disable-line:no-any export async function awsApiRequestRESTAllItems(
this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions,
propertyName: string,
service: string,
method: string,
path: string,
body?: string,
query: IDataObject = {},
headers: IDataObject = {},
option: IDataObject = {},
region?: string,
// tslint:disable-next-line:no-any
): Promise<any> {
const returnData: IDataObject[] = []; const returnData: IDataObject[] = [];
let responseData; let responseData;
@ -92,7 +115,10 @@ export async function awsApiRequestRESTAllItems(this: IHookFunctions | IExecuteF
responseData = await awsApiRequestREST.call(this, service, method, path, body, query); responseData = await awsApiRequestREST.call(this, service, method, path, body, query);
if (get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`)) { if (get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`)) {
query['NextToken'] = get(responseData, `${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`); query['NextToken'] = get(
responseData,
`${propertyNameArray[0]}.${propertyNameArray[1]}.NextToken`,
);
} }
if (get(responseData, propertyName)) { if (get(responseData, propertyName)) {
if (Array.isArray(get(responseData, propertyName))) { if (Array.isArray(get(responseData, propertyName))) {

View file

@ -1,12 +1,6 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { INodeType, INodeTypeBaseDescription, INodeTypeDescription } from 'n8n-workflow';
INodeType,
INodeTypeBaseDescription,
INodeTypeDescription,
} from 'n8n-workflow';
import { router } from './v1/actions/router'; import { router } from './v1/actions/router';
import { versionDescription } from './v1/actions/versionDescription'; import { versionDescription } from './v1/actions/versionDescription';

View file

@ -1,8 +1,4 @@
import { import { AllEntities, Entity, PropertiesOf } from 'n8n-workflow';
AllEntities,
Entity,
PropertiesOf,
} from 'n8n-workflow';
type BambooHrMap = { type BambooHrMap = {
employee: 'create' | 'get' | 'getAll' | 'update'; employee: 'create' | 'get' | 'getAll' | 'update';

View file

@ -8,16 +8,13 @@ export const companyReportGetDescription: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['companyReport'],
],
resource: [
'companyReport',
],
}, },
}, },
default: '', default: '',
description: 'ID of the report. You can get the report number by hovering over the report name on the reports page and grabbing the ID.', description:
'ID of the report. You can get the report number by hovering over the report name on the reports page and grabbing the ID.',
}, },
{ {
displayName: 'Format', displayName: 'Format',
@ -48,12 +45,8 @@ export const companyReportGetDescription: INodeProperties[] = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['companyReport'],
],
resource: [
'companyReport',
],
}, },
}, },
default: 'JSON', default: 'JSON',
@ -68,17 +61,11 @@ export const companyReportGetDescription: INodeProperties[] = [
description: 'The name of the output field to put the binary file data in', description: 'The name of the output field to put the binary file data in',
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['companyReport'],
],
resource: [
'companyReport',
],
}, },
hide: { hide: {
format: [ format: ['JSON'],
'JSON',
],
}, },
}, },
}, },
@ -90,12 +77,8 @@ export const companyReportGetDescription: INodeProperties[] = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['get'],
'get', resource: ['companyReport'],
],
resource: [
'companyReport',
],
}, },
}, },
options: [ options: [

View file

@ -1,15 +1,8 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeExecutionData } from 'n8n-workflow';
IDataObject,
INodeExecutionData,
} from 'n8n-workflow';
import { import { apiRequest } from '../../../transport';
apiRequest,
} from '../../../transport';
export async function get(this: IExecuteFunctions, index: number) { export async function get(this: IExecuteFunctions, index: number) {
const body: IDataObject = {}; const body: IDataObject = {};
@ -25,16 +18,26 @@ export async function get(this: IExecuteFunctions, index: number) {
const endpoint = `reports/${reportId}/?format=${format}&fd=${fd}`; const endpoint = `reports/${reportId}/?format=${format}&fd=${fd}`;
if (format === 'JSON') { if (format === 'JSON') {
const responseData = await apiRequest.call(this, requestMethod, endpoint, body, {}, { resolveWithFullResponse: true }); const responseData = await apiRequest.call(
this,
requestMethod,
endpoint,
body,
{},
{ resolveWithFullResponse: true },
);
return this.helpers.returnJsonArray(responseData.body); return this.helpers.returnJsonArray(responseData.body);
} }
const output: string = this.getNodeParameter('output', index) as string; const output: string = this.getNodeParameter('output', index) as string;
const response = await apiRequest.call(this, requestMethod, endpoint, body, {} as IDataObject, const response = await apiRequest.call(this, requestMethod, endpoint, body, {} as IDataObject, {
{ encoding: null, json: false, resolveWithFullResponse: true }); encoding: null,
json: false,
resolveWithFullResponse: true,
});
let mimeType = response.headers['content-type'] as string | undefined; let mimeType = response.headers['content-type'] as string | undefined;
mimeType = mimeType ? mimeType.split(';').find(value => value.includes('/')) : undefined; mimeType = mimeType ? mimeType.split(';').find((value) => value.includes('/')) : undefined;
const contentDisposition = response.headers['content-disposition']; const contentDisposition = response.headers['content-disposition'];
const fileNameRegex = /(?<=filename=").*\b/; const fileNameRegex = /(?<=filename=").*\b/;
const match = fileNameRegex.exec(contentDisposition); const match = fileNameRegex.exec(contentDisposition);
@ -58,7 +61,11 @@ export async function get(this: IExecuteFunctions, index: number) {
} }
newItem.binary = { newItem.binary = {
[output]: await this.helpers.prepareBinaryData(response.body as unknown as Buffer, fileName, mimeType), [output]: await this.helpers.prepareBinaryData(
response.body as unknown as Buffer,
fileName,
mimeType,
),
}; };
return this.prepareOutputData(newItem as unknown as INodeExecutionData[]); return this.prepareOutputData(newItem as unknown as INodeExecutionData[]);

View file

@ -1,7 +1,4 @@
import { get as execute } from './execute'; import { get as execute } from './execute';
import { companyReportGetDescription as description } from './description'; import { companyReportGetDescription as description } from './description';
export { export { description, execute };
description,
execute,
};

View file

@ -1,12 +1,8 @@
import * as get from './get'; import * as get from './get';
import { import { INodeProperties } from 'n8n-workflow';
INodeProperties,
} from 'n8n-workflow';
export { export { get };
get,
};
export const descriptions: INodeProperties[] = [ export const descriptions: INodeProperties[] = [
{ {
@ -16,9 +12,7 @@ export const descriptions: INodeProperties[] = [
noDataExpression: true, noDataExpression: true,
displayOptions: { displayOptions: {
show: { show: {
resource: [ resource: ['companyReport'],
'companyReport',
],
}, },
}, },
options: [ options: [

View file

@ -1,10 +1,6 @@
import { import { EmployeeProperties } from '../../Interfaces';
EmployeeProperties,
} from '../../Interfaces';
import { import { createEmployeeSharedDescription } from './shareDescription';
createEmployeeSharedDescription,
} from './shareDescription';
export const employeeCreateDescription: EmployeeProperties = [ export const employeeCreateDescription: EmployeeProperties = [
{ {
@ -14,16 +10,13 @@ export const employeeCreateDescription: EmployeeProperties = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['employee'],
],
resource: [
'employee',
],
}, },
}, },
default: false, default: false,
description: 'Whether the employee to create was added to a pay schedule synced with Trax Payroll', description:
'Whether the employee to create was added to a pay schedule synced with Trax Payroll',
}, },
{ {
displayName: 'First Name', displayName: 'First Name',
@ -32,12 +25,8 @@ export const employeeCreateDescription: EmployeeProperties = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['employee'],
],
resource: [
'employee',
],
}, },
}, },
default: '', default: '',
@ -49,12 +38,8 @@ export const employeeCreateDescription: EmployeeProperties = [
required: true, required: true,
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['employee'],
],
resource: [
'employee',
],
}, },
}, },
default: '', default: '',
@ -68,12 +53,8 @@ export const employeeCreateDescription: EmployeeProperties = [
default: {}, default: {},
displayOptions: { displayOptions: {
show: { show: {
operation: [ operation: ['create'],
'create', resource: ['employee'],
],
resource: [
'employee',
],
}, },
}, },
options: [ options: [

View file

@ -1,23 +1,17 @@
import { import { IExecuteFunctions } from 'n8n-core';
IExecuteFunctions,
} from 'n8n-core';
import { import { IDataObject, INodeExecutionData } from 'n8n-workflow';
IDataObject,
INodeExecutionData,
} from 'n8n-workflow';
import { import { apiRequest } from '../../../transport';
apiRequest,
} from '../../../transport';
import moment from 'moment'; import moment from 'moment';
import { import { capitalCase } from 'change-case';
capitalCase
} from 'change-case';
export async function create(this: IExecuteFunctions, index: number): Promise<INodeExecutionData[]> { export async function create(
this: IExecuteFunctions,
index: number,
): Promise<INodeExecutionData[]> {
const body: IDataObject = {}; const body: IDataObject = {};
const requestMethod = 'POST'; const requestMethod = 'POST';
const endpoint = 'employees'; const endpoint = 'employees';
@ -30,8 +24,12 @@ export async function create(this: IExecuteFunctions, index: number): Promise<IN
const synced = this.getNodeParameter('synced', index) as boolean; const synced = this.getNodeParameter('synced', index) as boolean;
if (synced) { if (synced) {
Object.assign(body, { address: this.getNodeParameter('address.value', index, {}) as IDataObject }); Object.assign(body, {
Object.assign(body, { payRate: this.getNodeParameter('payRate.value', index, {}) as IDataObject }); address: this.getNodeParameter('address.value', index, {}) as IDataObject,
});
Object.assign(body, {
payRate: this.getNodeParameter('payRate.value', index, {}) as IDataObject,
});
body.department = this.getNodeParameter('department', index) as string; body.department = this.getNodeParameter('department', index) as string;
body.dateOfBirth = this.getNodeParameter('dateOfBirth', index); body.dateOfBirth = this.getNodeParameter('dateOfBirth', index);
body.division = this.getNodeParameter('division', index) as string; body.division = this.getNodeParameter('division', index) as string;
@ -47,8 +45,12 @@ export async function create(this: IExecuteFunctions, index: number): Promise<IN
body.preferredName = this.getNodeParameter('preferredName', index) as string; body.preferredName = this.getNodeParameter('preferredName', index) as string;
body.ssn = this.getNodeParameter('ssn', index) as string; body.ssn = this.getNodeParameter('ssn', index) as string;
} else { } else {
Object.assign(body, { address: this.getNodeParameter('additionalFields.address.value', index, {}) as IDataObject }); Object.assign(body, {
Object.assign(body, { payRate: this.getNodeParameter('additionalFields.payRate.value', index, {}) as IDataObject }); address: this.getNodeParameter('additionalFields.address.value', index, {}) as IDataObject,
});
Object.assign(body, {
payRate: this.getNodeParameter('additionalFields.payRate.value', index, {}) as IDataObject,
});
delete additionalFields.address; delete additionalFields.address;
delete additionalFields.payRate; delete additionalFields.payRate;
} }
@ -88,7 +90,14 @@ export async function create(this: IExecuteFunctions, index: number): Promise<IN
} }
//response //response
const responseData = await apiRequest.call(this, requestMethod, endpoint, body, {}, { resolveWithFullResponse: true }); const responseData = await apiRequest.call(
this,
requestMethod,
endpoint,
body,
{},
{ resolveWithFullResponse: true },
);
//obtain employeeID //obtain employeeID
const rawEmployeeId = responseData.headers.location.lastIndexOf('/'); const rawEmployeeId = responseData.headers.location.lastIndexOf('/');

Some files were not shown because too many files have changed in this diff Show more