🔀 Merge branch 'feature/calendly-trigger' of https://github.com/RicardoE105/n8n into RicardoE105-feature/calendly-trigger

This commit is contained in:
Jan Oberhauser 2020-03-13 12:54:51 +01:00
commit 1b1f8eb131
5 changed files with 219 additions and 2 deletions

View file

@ -0,0 +1,17 @@
import {
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';
export class CalendlyApi implements ICredentialType {
name = 'calendlyApi';
displayName = 'Calendly API';
properties = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string' as NodePropertyTypes,
default: '',
},
];
}

View file

@ -0,0 +1,147 @@
import {
IHookFunctions,
IWebhookFunctions,
} from 'n8n-core';
import {
INodeTypeDescription,
INodeType,
IWebhookResponseData,
} from 'n8n-workflow';
import {
calendlyApiRequest,
} from './GenericFunctions';
export class CalendlyTrigger implements INodeType {
description: INodeTypeDescription = {
displayName: 'Calendly Trigger',
name: 'calendlyTrigger',
icon: 'file:calendly.png',
group: ['trigger'],
version: 1,
description: 'Starts the workflow when Calendly events occure.',
defaults: {
name: 'Calendly Trigger',
color: '#374252',
},
inputs: [],
outputs: ['main'],
credentials: [
{
name: 'calendlyApi',
required: true,
},
],
webhooks: [
{
name: 'default',
httpMethod: 'POST',
responseMode: 'onReceived',
path: 'webhook',
},
],
properties: [
{
displayName: 'Events',
name: 'events',
type: 'multiOptions',
options: [
{
name: 'invitee.created',
value: 'invitee.created',
description: 'Receive notifications when a new Calendly event is created',
},
{
name: 'invitee.canceled',
value: 'invitee.canceled',
description: 'Receive notifications when a Calendly event is canceled',
},
],
default: [],
required: true,
},
],
};
// @ts-ignore (because of request)
webhookMethods = {
default: {
async checkExists(this: IHookFunctions): Promise<boolean> {
const webhookUrl = this.getNodeWebhookUrl('default');
const webhookData = this.getWorkflowStaticData('node');
const events = this.getNodeParameter('events') as string;
// Check all the webhooks which exist already if it is identical to the
// one that is supposed to get created.
const endpoint = '/hooks';
const { data } = await calendlyApiRequest.call(this, 'GET', endpoint, {});
for (const webhook of data) {
if (webhook.attributes.url === webhookUrl) {
for (const event of events) {
if (!webhook.attributes.events.includes(event)) {
return false;
}
}
}
// Set webhook-id to be sure that it can be deleted
webhookData.webhookId = webhook.id as string;
return true;
}
return false;
},
async create(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
const webhookUrl = this.getNodeWebhookUrl('default');
const events = this.getNodeParameter('events') as string;
const endpoint = '/hooks';
const body = {
url: webhookUrl,
events,
};
const responseData = await calendlyApiRequest.call(this, 'POST', endpoint, body);
if (responseData.id === undefined) {
// Required data is missing so was not successful
return false;
}
webhookData.webhookId = responseData.id as string;
return true;
},
async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
console.log(webhookData)
if (webhookData.webhookId !== undefined) {
const endpoint = `/hooks/${webhookData.webhookId}`;
try {
await calendlyApiRequest.call(this, 'DELETE', endpoint);
} catch (e) {
return false;
}
// Remove from the static workflow data so that it is clear
// that no webhooks are registred anymore
delete webhookData.webhookId;
}
return true;
},
},
};
async webhook(this: IWebhookFunctions): Promise<IWebhookResponseData> {
const bodyData = this.getBodyData();
return {
workflowData: [
this.helpers.returnJsonArray(bodyData),
],
};
}
}

View file

@ -0,0 +1,51 @@
import { OptionsWithUri } from 'request';
import {
IExecuteFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';
import {
IDataObject,
IHookFunctions,
IWebhookFunctions
} from 'n8n-workflow';
export async function calendlyApiRequest(this: IExecuteFunctions | IWebhookFunctions | IHookFunctions | ILoadOptionsFunctions, method: string, resource: string, body: any = {}, query: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const credentials = this.getCredentials('calendlyApi');
if (credentials === undefined) {
throw new Error('No credentials got returned!');
}
const endpoint = 'https://calendly.com/api/v1';
let options: OptionsWithUri = {
headers: {
'Content-Type': 'application/json',
'X-TOKEN': credentials.apiKey,
},
method,
body,
qs: query,
uri: uri || `${endpoint}${resource}`,
json: true
};
if (!Object.keys(body).length) {
delete options.form;
}
if (!Object.keys(query).length) {
delete options.qs;
}
options = Object.assign({}, options, option);
try {
return await this.helpers.request!(options);
} catch (error) {
if (error.response) {
const errorMessage = error.response.body.message || error.response.body.description || error.message;
throw new Error(`Calendly error response [${error.statusCode}]: ${errorMessage}`);
}
throw error;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -40,6 +40,7 @@
"dist/credentials/ClockifyApi.credentials.js",
"dist/credentials/CodaApi.credentials.js",
"dist/credentials/CopperApi.credentials.js",
"dist/credentials/CalendlyApi.credentials.js",
"dist/credentials/DisqusApi.credentials.js",
"dist/credentials/DriftApi.credentials.js",
"dist/credentials/DropboxApi.credentials.js",
@ -117,6 +118,7 @@
"dist/nodes/Aws/AwsSnsTrigger.node.js",
"dist/nodes/Bitbucket/BitbucketTrigger.node.js",
"dist/nodes/Bitly/Bitly.node.js",
"dist/nodes/Calendly/CalendlyTrigger.node.js",
"dist/nodes/Chargebee/Chargebee.node.js",
"dist/nodes/Chargebee/ChargebeeTrigger.node.js",
"dist/nodes/Clearbit/Clearbit.node.js",