From 7d625572c1f7d0dac24859fb38d141698558787a Mon Sep 17 00:00:00 2001 From: shraddha shaligram Date: Tue, 30 Jun 2020 13:35:31 -0700 Subject: [PATCH 1/3] add basic customer.io trigger --- .../credentials/CustomerIoApi.credentials.ts | 19 + .../nodes-base/nodes/Aws/GenericFunctions.ts | 4 +- .../CustomerIo/CustomerIoTrigger.node.ts | 330 ++++++++++++++++++ .../nodes/CustomerIo/GenericFunctions.ts | 48 +++ .../nodes/CustomerIo/customer.Io.png | Bin 0 -> 1790 bytes .../nodes/Mailchimp/MailchimpTrigger.node.ts | 18 +- packages/nodes-base/package.json | 4 +- 7 files changed, 411 insertions(+), 12 deletions(-) create mode 100644 packages/nodes-base/credentials/CustomerIoApi.credentials.ts create mode 100644 packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts create mode 100644 packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts create mode 100644 packages/nodes-base/nodes/CustomerIo/customer.Io.png diff --git a/packages/nodes-base/credentials/CustomerIoApi.credentials.ts b/packages/nodes-base/credentials/CustomerIoApi.credentials.ts new file mode 100644 index 0000000000..2cc92c81af --- /dev/null +++ b/packages/nodes-base/credentials/CustomerIoApi.credentials.ts @@ -0,0 +1,19 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class CustomerIoApi implements ICredentialType { + name = 'customerIoApi'; + displayName = 'Customer.io API'; + properties = [ + { + displayName: 'API Key', + name: 'apiKey', + type: 'string' as NodePropertyTypes, + default: '', + }, + + ]; +} diff --git a/packages/nodes-base/nodes/Aws/GenericFunctions.ts b/packages/nodes-base/nodes/Aws/GenericFunctions.ts index 6ffa92c8ee..ef334b1d67 100644 --- a/packages/nodes-base/nodes/Aws/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Aws/GenericFunctions.ts @@ -19,8 +19,8 @@ export async function awsApiRequest(this: IHookFunctions | IExecuteFunctions | I const endpoint = `${service}.${credentials.region}.amazonaws.com`; // Sign AWS API request with the user credentials - const signOpts = {headers: headers || {}, host: endpoint, method, path, body}; - sign(signOpts, {accessKeyId: `${credentials.accessKeyId}`, secretAccessKey: `${credentials.secretAccessKey}`}); + const signOpts = { headers: headers || {}, host: endpoint, method, path, body }; + sign(signOpts, { accessKeyId: `${credentials.accessKeyId}`, secretAccessKey: `${credentials.secretAccessKey}` }); const options: OptionsWithUri = { headers: signOpts.headers, diff --git a/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts new file mode 100644 index 0000000000..5a3f7c2ef9 --- /dev/null +++ b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts @@ -0,0 +1,330 @@ +import { + IHookFunctions, + IWebhookFunctions, +} from 'n8n-core'; +import { + INodeTypeDescription, + INodeType, + IDataObject, + IWebhookResponseData, +} from 'n8n-workflow'; +import { + apiRequest, +} from './GenericFunctions'; + +export class CustomerIoTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Customer.io Trigger', + name: 'customerIo', + group: ['trigger'], + icon: 'file:customer.Io.png', + version: 1, + subtitle: '=Updates: {{$parameter["updates"].join(", ")}}', + description: 'Starts the workflow on a Customer.io update.', + defaults: { + name: 'Customer.io Trigger', + color: '#00FF00', + }, + inputs: [], + outputs: ['main'], + credentials: [ + { + name: 'customerIoApi', + required: true, + } + ], + webhooks: [ + { + name: 'default', + httpMethod: 'POST', + responseMode: 'onReceived', + path: 'webhook', + }, + ], + properties: [ + { + displayName: 'Events', + name: 'events', + type: 'multiOptions', + default: [], + description: 'The events that can trigger the webhook and whether they are enabled.', + options: [ + { + name: 'Customer Subscribed', + value: 'customer.subscribed', + description: 'Whether the webhook is triggered when a list subscriber is added.', + }, + { + name: 'Customer Unsubscribe', + value: 'customer.unsubscribed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email Attempted', + value: 'email.attempted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email Bounced', + value: 'email.bounced', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email clicked', + value: 'email.clicked', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email converted', + value: 'email.converted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email delivered', + value: 'email.delivered', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email drafted', + value: 'email.drafted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email failed', + value: 'email.failed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email opened', + value: 'email.opened', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email sent', + value: 'email.sent', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Email spammed', + value: 'email.spammed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push attempted', + value: 'push.attempted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push bounced', + value: 'push.bounced', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push clicked', + value: 'push.clicked', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push delivered', + value: 'push.delivered', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push drafted', + value: 'push.drafted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push failed', + value: 'push.failed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push opened', + value: 'push.opened', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Push sent', + value: 'push.sent', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Slack attempted', + value: 'slack.attempted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Slack clicked', + value: 'slack.clicked', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Slack drafted', + value: 'slack.drafted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Slack failed', + value: 'slack.failed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'Slack sent', + value: 'slack.sent', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS attempted', + value: 'slack.attempted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS bounced', + value: 'slack.bounced', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS clicked', + value: 'slack.clicked', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS delivered', + value: 'slack.delivered', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS drafted', + value: 'slack.drafted', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS failed', + value: 'slack.failed', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + { + name: 'SMS sent', + value: 'slack.sent', + description: 'Whether the webhook is triggered when a list member unsubscribes.', + }, + + ], + }, + ], + }; + // @ts-ignore (because of request) + webhookMethods = { + default: { + async checkExists(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + console.log("in checkexists function") + if (webhookData.webhookId === undefined) { + // No webhook id is set so no webhook can exist + return false; + } + const endpoint = `/reporting_webhooks/${webhookData.webhookId}`; + try { + await apiRequest.call(this, 'GET', endpoint, {}); + } catch (err) { + if (err.statusCode === 404) { + return false; + } + throw new Error(`Customer.io Error: ${err}`); + } + + return true; + }, + async create(this: IHookFunctions): Promise { + let webhook; + const webhookUrl = this.getNodeWebhookUrl('default'); + const events = this.getNodeParameter('events', []) as string[]; + + const endpoint1 = '/reporting_webhooks'; + for (const event of events) { + var obj = event.split('.'); + + // var obj2 = JSON.stringify(obj); + // var key = obj[0]; //push + // var val = JSON.stringify(obj[1]); //attempted + + // var obj1: { obj2: boolean; } = { obj2: true }; //{'attempted':true} + + + } + const body = { + endpoint: webhookUrl, + // events: events.reduce((object, currentValue) => { + // // @ts-ignore + // var obj = currentValue.split('.'); + + // //object[currentValue] = true; + + // return object; + // }, {}), + "events": { + "customer": { + "subscribed": false, + "unsubscribed": true + }, + }, + }; + console.log(body); + try { + webhook = await apiRequest.call(this, 'POST', endpoint1, body); + } catch (e) { + throw e; + } + if (webhook.id === undefined) { + return false; + } + const webhookData = this.getWorkflowStaticData('node'); + webhookData.webhookId = webhook.id as string; + webhookData.events = events; + return true; + + }, + async delete(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + + if (webhookData.webhookId !== undefined) { + const endpoint = `/reporting_webhooks/${webhookData.webhookId}`; + try { + await apiRequest.call(this, endpoint, 'DELETE', {}); + } catch (e) { + return false; + } + delete webhookData.webhookId; + delete webhookData.events; + + } + return true; + }, + } + }; + + + + async webhook(this: IWebhookFunctions): Promise { + const bodyData = this.getBodyData(); + const webhookData = this.getWorkflowStaticData('node') as IDataObject; + const req = this.getRequestObject(); + if (req.body.id !== webhookData.id) { + return {}; + } + // @ts-ignore + if (!webhookData.events.includes(req.body.type) + // @ts-ignore + && !webhookData.sources.includes(req.body.type)) { + return {}; + } + return { + workflowData: [ + this.helpers.returnJsonArray([bodyData]) + ], + }; + } + + +} diff --git a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts new file mode 100644 index 0000000000..5474ec3397 --- /dev/null +++ b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts @@ -0,0 +1,48 @@ +import { + IExecuteFunctions, + IHookFunctions, + ILoadOptionsFunctions, +} from 'n8n-core'; + +import { OptionsWithUri } from 'request'; +import { IDataObject } from 'n8n-workflow'; + +export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('customerIoApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + query = query || {}; + + const options: OptionsWithUri = { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${credentials.apiKey}`, + }, + method, + body, + qs: query, + uri: `https://beta-api.customer.io/v1/api${endpoint}`, + json: true, + }; + console.log(options); + try { + return await this.helpers.request!(options); + } catch (error) { + if (error.statusCode === 401) { + // Return a clear error + throw new Error('The Customer.io credentials are not valid!'); + } + + if (error.response && error.response.body && error.response.body.error_code) { + // Try to return the error prettier + const errorBody = error.response.body; + throw new Error(`Customer.io error response [${errorBody.error_code}]: ${errorBody.description}`); + } + + // Expected error data did not get returned so throw the actual error + throw error; + } +} diff --git a/packages/nodes-base/nodes/CustomerIo/customer.Io.png b/packages/nodes-base/nodes/CustomerIo/customer.Io.png new file mode 100644 index 0000000000000000000000000000000000000000..7c5ae3010a4c7490ce71d9a7d3d611ad5de5c436 GIT binary patch literal 1790 zcmZ{lX*Ao38pi*LBoai1s-#*(#Zt9|5=&JjmP$*hr4cC;yHqq8!MWNDA-L7UZE7cR z%d`e#X=bR=rg{}cV`=Cu%BWPemfGeprBvNG_tX7w&wHNtInQ&>@BRAb`dvJSRMAlZ z002q$a`#ub^MT+n#diAoCQ)IKSfURR0Dir#`ZXM?$k<3Pe;)w2ZVUjtECAS1RJ;WM zNX7%e5?w)+0RWmUdVJ~N5G>-tId@?HV5&N53l$B5?M3APfcb?3fojf_)GJEmB(jf( z@*GU}kcQ3Tm5(d{fUc0;iGgu%S1M>stsqQa`l*)RS073e7{5;?S{WtCawhvdtg)KN z478@3JF=Iy`5cp%`zOfG3?(fj7#kaJSM>_&5Ohe5icSPR4itaFFT}jYf+^`RUrDjz zaLdM4Q>IqJLVg|iR`?=jcu>Sin?F5&dWPFl@EwV*Ony48+Yg%OaXKC4$Jpu)%G`NV zWzmWh6e~&EXT;wj!jnnuXn`vQfT8-^%$3yJ+-A^tHpY`i{44&$Eo9zd`Gop#CEZlG z(d@<9b!jB++shuJJu6({0^{l902$0dw$H%&40~p5t$5JQG?nqsuI;QC7-#|Q`bAmJ zP0|DJ`jVzD!jo%kJu&EKqkMX^u<+VYe(B{s*@hk@fCo*`&I`-_=N=Zk0pA{DV0KP) z)R=#3lRVABRAGWn3hafq_#1CH}V!%Fd` zf;++YIDRZDIp5OEzd%c1QLZ#l;xLh+?y!4gGjyca4i=mZeeD;bdLAs#3J5VFPZ&*O zn9J4R+OEAP1a3J<;~!0a1h&wP?|T$Oe1G}E$<+^1qi+p@*~Jmn-URE8N4Vj??;TT_&a-Gc1FvCa%z6!vf@P07H!Oq4 zo?lsVQRP>@@}(GHUm^%w=0K^`b8P7tVhwT6|LiDHqNA&R-fvy4Xq;b9QmRnlJ~4lw zqWz;G ziB3h{I)uBIvT%i7ue2o;FMl_;c5~4m2S?v_O+ObAdw-#NZna!j8~3GcF363kyTgC= z4x|a~hf!xMU5%_HQomV|geOL2QVf<~f7S@qz-VU{=u=n@@S$^6E2edK7((~DisbR9 z5ZI@|PI9!fO7s~?evJr$(kQ=1l!AAoPtLova$28-{K&HjuWj zQ_}t{W@K!!Xvj>={xMN3=-L%ivL>vPN(v3W7ugA*9!&(j>;Jk{5OaE=YAJ2vt8Ed5 zFN*4E{zWzdIm-p7?=@CVS%@R7gNOc##*2lPF@Ml7Be~MyPFAG%TkKT_wd*D@@=Zonwl;No!(8jZ`4X&$9G=2epJsT%6$@m9k{SwbuB6RA+C|m6w6CVp{lz&vT-n zkWRowV>Wdks-7b`@q`&U@U1>P@x^e#6FSIv0OyTyccXdB>-iNXwkK*wD}{3C*hvAo9#>+7l&r@SdgY8iYGvi%*f877=u zypMGHxT!Kge}4@*L6V7u;oa^pu=QQrg(M5hK;+m`R*;b19Vrj%ZR85d zUb}N~YU%dR$_?4?w6-4`XzIj!>3v$$x*GyHq(>X!w?Hm8^Cz3cVx1!DS1`fkd%eKJ z+)&vVyeU?`V}x1A=(I>^y4_9wt&QNL&DL^bK+PMnjqKz}Ci>OWDe^c(b;iz(@H$kE zGS;@_k?iQRWk9IfXo;uBvi4>O@_pfIdpa=3YYBCfGb!p0Q^iWdDIfkD$IoWk>dv;# z>>a!eqa=^uq^R(uXs5`;XoUebcpJP0o?v0)7-;S2WNq(chd+tOJK^z*R-=;t0TNhI YjF{B_50oWdRaO81+2f*nGl`!0ANL6eeE Date: Tue, 30 Jun 2020 17:47:17 -0400 Subject: [PATCH 2/3] :zap: small fix --- packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts index 5a3f7c2ef9..bc9f0e2711 100644 --- a/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts +++ b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts @@ -22,7 +22,7 @@ export class CustomerIoTrigger implements INodeType { subtitle: '=Updates: {{$parameter["updates"].join(", ")}}', description: 'Starts the workflow on a Customer.io update.', defaults: { - name: 'Customer.io Trigger', + name: 'CustomerDotIO Trigger', color: '#00FF00', }, inputs: [], From 4b02ed2f37bf1810a5fa55d92ad2c3800c532ea7 Mon Sep 17 00:00:00 2001 From: ricardo Date: Mon, 3 Aug 2020 17:11:57 -0400 Subject: [PATCH 3/3] :zap: Improvements --- .../CustomerIo/CustomerIoTrigger.node.ts | 158 +++++++++--------- .../nodes/CustomerIo/GenericFunctions.ts | 23 ++- 2 files changed, 98 insertions(+), 83 deletions(-) diff --git a/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts index bc9f0e2711..5db8a4f899 100644 --- a/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts +++ b/packages/nodes-base/nodes/CustomerIo/CustomerIoTrigger.node.ts @@ -2,16 +2,28 @@ import { IHookFunctions, IWebhookFunctions, } from 'n8n-core'; + import { INodeTypeDescription, INodeType, IDataObject, IWebhookResponseData, } from 'n8n-workflow'; + import { apiRequest, + eventExists, } from './GenericFunctions'; +interface IEvent{ + customer?: IDataObject; + email?: IDataObject; + push?: IDataObject; + slack?: IDataObject; + sms?: IDataObject; + webhook?: IDataObject; +} + export class CustomerIoTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Customer.io Trigger', @@ -19,10 +31,9 @@ export class CustomerIoTrigger implements INodeType { group: ['trigger'], icon: 'file:customer.Io.png', version: 1, - subtitle: '=Updates: {{$parameter["updates"].join(", ")}}', - description: 'Starts the workflow on a Customer.io update.', + description: 'Starts the workflow on a Customer.io update. (Beta)', defaults: { - name: 'CustomerDotIO Trigger', + name: 'Customer.io Trigger', color: '#00FF00', }, inputs: [], @@ -31,7 +42,7 @@ export class CustomerIoTrigger implements INodeType { { name: 'customerIoApi', required: true, - } + }, ], webhooks: [ { @@ -176,40 +187,39 @@ export class CustomerIoTrigger implements INodeType { }, { name: 'SMS attempted', - value: 'slack.attempted', + value: 'sms.attempted', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS bounced', - value: 'slack.bounced', + value: 'sms.bounced', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS clicked', - value: 'slack.clicked', + value: 'sms.clicked', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS delivered', - value: 'slack.delivered', + value: 'sms.delivered', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS drafted', - value: 'slack.drafted', + value: 'sms.drafted', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS failed', - value: 'slack.failed', + value: 'sms.failed', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, { name: 'SMS sent', - value: 'slack.sent', + value: 'sms.sent', description: 'Whether the webhook is triggered when a list member unsubscribes.', }, - ], }, ], @@ -218,72 +228,77 @@ export class CustomerIoTrigger implements INodeType { webhookMethods = { default: { async checkExists(this: IHookFunctions): Promise { + const webhookUrl = this.getNodeWebhookUrl('default'); + const webhookData = this.getWorkflowStaticData('node'); - console.log("in checkexists function") - if (webhookData.webhookId === undefined) { - // No webhook id is set so no webhook can exist - return false; - } - const endpoint = `/reporting_webhooks/${webhookData.webhookId}`; - try { - await apiRequest.call(this, 'GET', endpoint, {}); - } catch (err) { - if (err.statusCode === 404) { - return false; - } - throw new Error(`Customer.io Error: ${err}`); + + const currentEvents = this.getNodeParameter('events', []) as string[]; + + const endpoint = '/reporting_webhooks'; + + let { reporting_webhooks: webhooks } = await apiRequest.call(this, 'GET', endpoint, {}); + + if (webhooks === null) { + webhooks = []; } - return true; + for (const webhook of webhooks) { + if (webhook.endpoint === webhookUrl && + eventExists(currentEvents, webhook.events)) { + webhookData.webhookId = webhook.id; + return true; + } + } + + return false; }, async create(this: IHookFunctions): Promise { let webhook; const webhookUrl = this.getNodeWebhookUrl('default'); const events = this.getNodeParameter('events', []) as string[]; - const endpoint1 = '/reporting_webhooks'; + const endpoint = '/reporting_webhooks'; + + const data: IEvent = { + customer: {}, + email: {}, + push: {}, + slack: {}, + sms: {}, + webhook: {}, + }; + for (const event of events) { - var obj = event.split('.'); - - // var obj2 = JSON.stringify(obj); - // var key = obj[0]; //push - // var val = JSON.stringify(obj[1]); //attempted - - // var obj1: { obj2: boolean; } = { obj2: true }; //{'attempted':true} - - + const option = event.split('.')[1]; + if (event.startsWith('customer')) { + data.customer![option] = true; + } + if (event.startsWith('email')) { + data.email![option] = true; + } + if (event.startsWith('push')) { + data.push![option] = true; + } + if (event.startsWith('slack')) { + data.slack![option] = true; + } + if (event.startsWith('sms')) { + data.sms![option] = true; + } + if (event.startsWith('webhook')) { + data.webhook![option] = true; + } } const body = { endpoint: webhookUrl, - // events: events.reduce((object, currentValue) => { - // // @ts-ignore - // var obj = currentValue.split('.'); - - // //object[currentValue] = true; - - // return object; - // }, {}), - "events": { - "customer": { - "subscribed": false, - "unsubscribed": true - }, - }, + events: data, }; - console.log(body); - try { - webhook = await apiRequest.call(this, 'POST', endpoint1, body); - } catch (e) { - throw e; - } - if (webhook.id === undefined) { - return false; - } + + webhook = await apiRequest.call(this, 'POST', endpoint, body); + const webhookData = this.getWorkflowStaticData('node'); webhookData.webhookId = webhook.id as string; - webhookData.events = events; return true; - }, async delete(this: IHookFunctions): Promise { const webhookData = this.getWorkflowStaticData('node'); @@ -291,40 +306,23 @@ export class CustomerIoTrigger implements INodeType { if (webhookData.webhookId !== undefined) { const endpoint = `/reporting_webhooks/${webhookData.webhookId}`; try { - await apiRequest.call(this, endpoint, 'DELETE', {}); + await apiRequest.call(this, 'DELETE', endpoint, {}); } catch (e) { return false; } delete webhookData.webhookId; - delete webhookData.events; - } return true; }, } }; - - async webhook(this: IWebhookFunctions): Promise { const bodyData = this.getBodyData(); - const webhookData = this.getWorkflowStaticData('node') as IDataObject; - const req = this.getRequestObject(); - if (req.body.id !== webhookData.id) { - return {}; - } - // @ts-ignore - if (!webhookData.events.includes(req.body.type) - // @ts-ignore - && !webhookData.sources.includes(req.body.type)) { - return {}; - } return { workflowData: [ - this.helpers.returnJsonArray([bodyData]) + this.helpers.returnJsonArray(bodyData) ], }; } - - } diff --git a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts index 5474ec3397..48e475f533 100644 --- a/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts +++ b/packages/nodes-base/nodes/CustomerIo/GenericFunctions.ts @@ -4,8 +4,17 @@ import { ILoadOptionsFunctions, } from 'n8n-core'; -import { OptionsWithUri } from 'request'; -import { IDataObject } from 'n8n-workflow'; +import { + OptionsWithUri, +} from 'request'; + +import { + IDataObject, +} from 'n8n-workflow'; + +import { + get, +} from 'lodash'; export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoadOptionsFunctions, method: string, endpoint: string, body: object, query?: IDataObject): Promise { // tslint:disable-line:no-any const credentials = this.getCredentials('customerIoApi'); @@ -27,7 +36,6 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa uri: `https://beta-api.customer.io/v1/api${endpoint}`, json: true, }; - console.log(options); try { return await this.helpers.request!(options); } catch (error) { @@ -46,3 +54,12 @@ export async function apiRequest(this: IHookFunctions | IExecuteFunctions | ILoa throw error; } } + +export function eventExists (currentEvents : string[], webhookEvents: IDataObject) { + for (const currentEvent of currentEvents) { + if (get(webhookEvents, `${currentEvent.split('.')[0]}.${currentEvent.split('.')[1]}`) !== true) { + return false; + } + } + return true; +}