import type { IHookFunctions, IWebhookFunctions, IDataObject, ILoadOptionsFunctions, INodePropertyOptions, INodeType, INodeTypeDescription, IWebhookResponseData, } from 'n8n-workflow'; import { NodeConnectionType } from 'n8n-workflow'; import { snakeCase } from 'change-case'; import { workableApiRequest } from './GenericFunctions'; export class WorkableTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Workable Trigger', name: 'workableTrigger', // eslint-disable-next-line n8n-nodes-base/node-class-description-icon-not-svg icon: 'file:workable.png', group: ['trigger'], version: 1, subtitle: '={{$parameter["triggerOn"]}}', description: 'Starts the workflow when Workable events occur', defaults: { name: 'Workable Trigger', }, inputs: [], outputs: [NodeConnectionType.Main], credentials: [ { name: 'workableApi', required: true, }, ], webhooks: [ { name: 'default', httpMethod: 'POST', responseMode: 'onReceived', path: 'webhook', }, ], properties: [ { displayName: 'Trigger On', name: 'triggerOn', type: 'options', options: [ { name: 'Candidate Created', value: 'candidateCreated', }, { name: 'Candidate Moved', value: 'candidateMoved', }, ], default: '', required: true, }, { displayName: 'Filters', name: 'filters', type: 'collection', placeholder: 'Add Filter', default: {}, options: [ { displayName: 'Job Name or ID', name: 'job', type: 'options', typeOptions: { loadOptionsMethod: 'getJobs', }, default: '', description: 'Get notifications only for one job. Choose from the list, or specify an ID using an expression.', }, { displayName: 'Stage Name or ID', name: 'stage', type: 'options', typeOptions: { loadOptionsMethod: 'getStages', }, default: '', description: 'Get notifications for specific stages. e.g. \'hired\'. Choose from the list, or specify an ID using an expression.', }, ], }, ], }; methods = { loadOptions: { async getJobs(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const { jobs } = await workableApiRequest.call(this, 'GET', '/jobs'); for (const job of jobs) { returnData.push({ name: job.full_title, value: job.shortcode, }); } return returnData; }, async getStages(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const { stages } = await workableApiRequest.call(this, 'GET', '/stages'); for (const stage of stages) { returnData.push({ name: stage.name, value: stage.slug, }); } return returnData; }, }, }; webhookMethods = { default: { async checkExists(this: IHookFunctions): Promise { const webhookUrl = this.getNodeWebhookUrl('default'); const webhookData = this.getWorkflowStaticData('node'); // Check all the webhooks which exist already if it is identical to the // one that is supposed to get created. const { subscriptions } = await workableApiRequest.call(this, 'GET', '/subscriptions'); for (const subscription of subscriptions) { if (subscription.target === webhookUrl) { webhookData.webhookId = subscription.id as string; return true; } } return false; }, async create(this: IHookFunctions): Promise { const credentials = await this.getCredentials<{ accessToken: string; subdomain: string; }>('workableApi'); const webhookData = this.getWorkflowStaticData('node'); const webhookUrl = this.getNodeWebhookUrl('default'); const triggerOn = this.getNodeParameter('triggerOn') as string; const { stage, job } = this.getNodeParameter('filters') as IDataObject; const endpoint = '/subscriptions'; const body: IDataObject = { event: snakeCase(triggerOn).toLowerCase(), args: { account_id: credentials.subdomain, ...(job && { job_shortcode: job }), ...(stage && { stage_slug: stage }), }, target: webhookUrl, }; const responseData = await workableApiRequest.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 { const webhookData = this.getWorkflowStaticData('node'); if (webhookData.webhookId !== undefined) { const endpoint = `/subscriptions/${webhookData.webhookId}`; try { await workableApiRequest.call(this, 'DELETE', endpoint); } catch (error) { return false; } // Remove from the static workflow data so that it is clear // that no webhooks are registered anymore delete webhookData.webhookId; } return true; }, }, }; async webhook(this: IWebhookFunctions): Promise { const bodyData = this.getBodyData(); return { workflowData: [this.helpers.returnJsonArray(bodyData)], }; } }