diff --git a/packages/nodes-base/credentials/GumroadApi.credentials.ts b/packages/nodes-base/credentials/GumroadApi.credentials.ts new file mode 100644 index 0000000000..668aa1a1a6 --- /dev/null +++ b/packages/nodes-base/credentials/GumroadApi.credentials.ts @@ -0,0 +1,17 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class GumroadApi implements ICredentialType { + name = 'gumroadApi'; + displayName = 'Gumroad API'; + properties = [ + { + displayName: 'Access Token', + name: 'accessToken', + type: 'string' as NodePropertyTypes, + default: '', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts new file mode 100644 index 0000000000..11e9e99872 --- /dev/null +++ b/packages/nodes-base/nodes/Gumroad/GenericFunctions.ts @@ -0,0 +1,39 @@ +import { OptionsWithUri } from 'request'; +import { + IExecuteFunctions, + IExecuteSingleFunctions, + IHookFunctions, + ILoadOptionsFunctions, + IWebhookFunctions, +} from 'n8n-core'; +import { IDataObject } from 'n8n-workflow'; + +export async function gumroadApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise { // tslint:disable-line:no-any + const credentials = this.getCredentials('gumroadApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + body = Object.assign({ access_token: credentials.accessToken }, body) + + let options: OptionsWithUri = { + method, + qs, + body, + uri: uri ||`https://api.gumroad.com/v2${resource}`, + json: true + }; + options = Object.assign({}, options, option); + if (Object.keys(options.body).length === 0) { + delete options.body; + } + + try { + return await this.helpers.request!(options); + } catch (error) { + let errorMessage = error + if (!error.success) { + errorMessage.message + } + throw new Error('Gumroad Error: ' + errorMessage); + } +} diff --git a/packages/nodes-base/nodes/Gumroad/GumroadTrigger.node.ts b/packages/nodes-base/nodes/Gumroad/GumroadTrigger.node.ts new file mode 100644 index 0000000000..bd4fa04dc1 --- /dev/null +++ b/packages/nodes-base/nodes/Gumroad/GumroadTrigger.node.ts @@ -0,0 +1,143 @@ +import { + IHookFunctions, + IWebhookFunctions, +} from 'n8n-core'; + +import { + IDataObject, + INodeTypeDescription, + INodeType, + IWebhookResponseData, +} from 'n8n-workflow'; + +import { + gumroadApiRequest, +} from './GenericFunctions'; + +export class GumroadTrigger implements INodeType { + description: INodeTypeDescription = { + displayName: 'Gumroad Trigger', + name: 'gumroad', + icon: 'file:gumroad.png', + group: ['trigger'], + version: 1, + description: 'Handle Gumroad events via webhooks', + defaults: { + name: 'Gumroad Trigger', + color: '#60c2cd', + }, + inputs: [], + outputs: ['main'], + credentials: [ + { + name: 'gumroadApi', + required: true, + } + ], + webhooks: [ + { + name: 'default', + httpMethod: 'POST', + responseMode: 'onReceived', + path: 'webhook', + }, + ], + properties: [ + { + displayName: 'Resource', + name: 'resource', + type: 'options', + required: true, + default: '', + options: [ + { + name: 'Sale', + value: 'sale', + description: `When subscribed to this resource, you will be notified of the user's sales`, + }, + { + name: 'Refund', + value: 'refund', + description: `When subscribed to this resource, you will be notified of refunds to the user's sales`, + }, + { + name: 'Dispute', + value: 'dispute', + description: `When subscribed to this resource, you will be notified of the disputes raised against user's sales`, + }, + { + name: 'Dispute Won', + value: 'dispute_won', + description: `When subscribed to this resource, you will be notified of the sale disputes won`, + }, + { + name: 'Cancellation', + value: 'cancellation', + description: `When subscribed to this resource, you will be notified of cancellations of the user's subscribers`, + }, + ], + description: 'The resource is gonna fire the event', + }, + ], + + }; + + // @ts-ignore + webhookMethods = { + default: { + async checkExists(this: IHookFunctions): Promise { + const webhookData = this.getWorkflowStaticData('node'); + if (webhookData.webhookId === undefined) { + return false; + } + const endpoint = `/resource_subscriptions`; + const { resource_subscriptions } = await gumroadApiRequest.call(this, 'GET', endpoint); + if (Array.isArray(resource_subscriptions)) { + for (const resource of resource_subscriptions) { + if (resource.id === webhookData.webhookId) { + return true + } + } + } + return false; + }, + async create(this: IHookFunctions): Promise { + const webhookUrl = this.getNodeWebhookUrl('default'); + const webhookData = this.getWorkflowStaticData('node'); + const resource = this.getNodeParameter('resource') as string; + const endpoint = '/resource_subscriptions'; + const body: IDataObject = { + post_url: webhookUrl, + resource_name: resource, + }; + const { resource_subscription } = await gumroadApiRequest.call(this, 'PUT', endpoint, body); + webhookData.webhookId = resource_subscription.id; + return true; + }, + async delete(this: IHookFunctions): Promise { + let responseData; + const webhookData = this.getWorkflowStaticData('node'); + const endpoint = `/resource_subscriptions/${webhookData.webhookId}`; + try { + responseData = await gumroadApiRequest.call(this, 'DELETE', endpoint); + } catch(error) { + return false; + } + if (!responseData.success) { + return false; + } + delete webhookData.webhookId; + return true; + }, + }, + }; + + async webhook(this: IWebhookFunctions): Promise { + const req = this.getRequestObject(); + return { + workflowData: [ + this.helpers.returnJsonArray(req.body), + ], + }; + } +} diff --git a/packages/nodes-base/nodes/Gumroad/gumroad.png b/packages/nodes-base/nodes/Gumroad/gumroad.png new file mode 100644 index 0000000000..70f23c5f19 Binary files /dev/null and b/packages/nodes-base/nodes/Gumroad/gumroad.png differ diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index f68ef4e6bb..85b2511544 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -42,6 +42,7 @@ "dist/credentials/GithubApi.credentials.js", "dist/credentials/GitlabApi.credentials.js", "dist/credentials/GoogleApi.credentials.js", + "dist/credentials/GumroadApi.credentials.js", "dist/credentials/HttpBasicAuth.credentials.js", "dist/credentials/HttpDigestAuth.credentials.js", "dist/credentials/HttpHeaderAuth.credentials.js", @@ -119,6 +120,7 @@ "dist/nodes/Google/GoogleDrive.node.js", "dist/nodes/Google/GoogleSheets.node.js", "dist/nodes/GraphQL/GraphQL.node.js", + "dist/nodes/Gumroad/GumroadTrigger.node.js", "dist/nodes/HtmlExtract/HtmlExtract.node.js", "dist/nodes/HttpRequest.node.js", "dist/nodes/Hubspot/Hubspot.node.js",