From 266112a8cb5bfe3009033c495c5e320fa0e6b0a2 Mon Sep 17 00:00:00 2001 From: Rupenieks <32895755+Rupenieks@users.noreply.github.com> Date: Wed, 16 Sep 2020 09:16:06 +0200 Subject: [PATCH] :zap: Clickup OAuth2 support (#649) * OAuth2 credentials, genericFunctions needed config, UI options for oauth2 support * :zap: Added options to decide when to to send the bearer * Fixed "undefined property split" issue * :zap: Small fix * :zap: Improvements to ClickUp-Node * :zap: Improvements Co-authored-by: Rupenieks Co-authored-by: ricardo Co-authored-by: Ricardo Espinoza --- packages/core/src/NodeExecuteFunctions.ts | 6 +++ .../ClickUpOAuth2Api.credentials.ts | 47 +++++++++++++++++++ .../nodes-base/nodes/ClickUp/ClickUp.node.ts | 34 ++++++++++++++ .../nodes/ClickUp/ClickUpTrigger.node.ts | 38 ++++++++++++++- .../nodes/ClickUp/GenericFunctions.ts | 35 ++++++++++---- packages/nodes-base/package.json | 1 + packages/workflow/src/Interfaces.ts | 1 + 7 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 5cf38f6a9..03e8ffb94 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -152,6 +152,12 @@ export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: strin // on the token-type used. const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject); + // If keep bearer is false remove the it from the authorization header + if (oAuth2Options?.keepBearer === false) { + //@ts-ignore + newRequestOptions?.headers?.Authorization = newRequestOptions?.headers?.Authorization.split(' ')[1]; + } + return this.helpers.request!(newRequestOptions) .catch(async (error: IResponseError) => { // TODO: Check if also other codes are possible diff --git a/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts b/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts new file mode 100644 index 000000000..3ce6d6c3f --- /dev/null +++ b/packages/nodes-base/credentials/ClickUpOAuth2Api.credentials.ts @@ -0,0 +1,47 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + +export class ClickUpOAuth2Api implements ICredentialType { + name = 'clickUpOAuth2Api'; + extends = [ + 'oAuth2Api', + ]; + displayName = 'ClickUp OAuth2 API'; + properties = [ + { + displayName: 'Authorization URL', + name: 'authUrl', + type: 'hidden' as NodePropertyTypes, + default: 'https://app.clickup.com/api', + required: true, + }, + { + displayName: 'Access Token URL', + name: 'accessTokenUrl', + type: 'hidden' as NodePropertyTypes, + default: 'https://api.clickup.com/api/v2/oauth/token', + required: true, + }, + { + displayName: 'Scope', + name: 'scope', + type: 'hidden' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Auth URI Query Parameters', + name: 'authQueryParameters', + type: 'hidden' as NodePropertyTypes, + default: '', + }, + { + displayName: 'Authentication', + name: 'authentication', + type: 'hidden' as NodePropertyTypes, + default: 'body', + description: 'Resource to consume.', + }, + ]; +} diff --git a/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts b/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts index ad1fcd119..170b1c1e5 100644 --- a/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts +++ b/packages/nodes-base/nodes/ClickUp/ClickUp.node.ts @@ -99,9 +99,43 @@ export class ClickUp implements INodeType { { name: 'clickUpApi', required: true, + displayOptions: { + show: { + authentication: [ + 'accessToken', + ], + }, + }, + }, + { + name: 'clickUpOAuth2Api', + required: true, + displayOptions: { + show: { + authentication: [ + 'oAuth2', + ], + }, + }, }, ], properties: [ + { + displayName: 'Authentication', + name: 'authentication', + type: 'options', + options: [ + { + name: 'Access Token', + value: 'accessToken', + }, + { + name: 'OAuth2', + value: 'oAuth2', + }, + ], + default: 'accessToken', + }, { displayName: 'Resource', name: 'resource', diff --git a/packages/nodes-base/nodes/ClickUp/ClickUpTrigger.node.ts b/packages/nodes-base/nodes/ClickUp/ClickUpTrigger.node.ts index 36d523313..7a844f707 100644 --- a/packages/nodes-base/nodes/ClickUp/ClickUpTrigger.node.ts +++ b/packages/nodes-base/nodes/ClickUp/ClickUpTrigger.node.ts @@ -34,9 +34,27 @@ export class ClickUpTrigger implements INodeType { outputs: ['main'], credentials: [ { - name: 'clickUpApi', + name: 'clickupApi', required: true, - } + displayOptions: { + show: { + authentication: [ + 'accessToken', + ], + }, + }, + }, + { + name: 'clickUpOAuth2Api', + required: true, + displayOptions: { + show: { + authentication: [ + 'oAuth2', + ], + }, + }, + }, ], webhooks: [ { @@ -47,6 +65,22 @@ export class ClickUpTrigger implements INodeType { }, ], properties: [ + { + displayName: 'Authentication', + name: 'authentication', + type: 'options', + options: [ + { + name: 'Access Token', + value: 'accessToken', + }, + { + name: 'OAuth2', + value: 'oAuth2', + }, + ], + default: 'accessToken', + }, { displayName: 'Team', name: 'team', diff --git a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts index d836f7798..0adbe15c4 100644 --- a/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts +++ b/packages/nodes-base/nodes/ClickUp/GenericFunctions.ts @@ -12,17 +12,12 @@ import { import { IDataObject, + IOAuth2Options, } from 'n8n-workflow'; export async function clickupApiRequest(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('clickUpApi'); - if (credentials === undefined) { - throw new Error('No credentials got returned!'); - } - const options: OptionsWithUri = { headers: { - Authorization: credentials.accessToken, 'Content-Type': 'application/json', }, method, @@ -31,15 +26,39 @@ export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions uri: uri ||`https://api.clickup.com/api/v2${resource}`, json: true }; + try { - return await this.helpers.request!(options); - } catch (error) { + const authenticationMethod = this.getNodeParameter('authentication', 0) as string; + + if (authenticationMethod === 'accessToken') { + + const credentials = this.getCredentials('clickUpApi'); + + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + options.headers!['Authorization'] = credentials.accessToken; + return await this.helpers.request!(options); + + } else { + + const oAuth2Options: IOAuth2Options = { + keepBearer: false, + tokenType: 'Bearer', + }; + // @ts-ignore + return await this.helpers.requestOAuth2!.call(this, 'clickUpOAuth2Api', options, oAuth2Options); + } + + } catch(error) { let errorMessage = error; if (error.err) { errorMessage = error.err; } throw new Error('ClickUp Error: ' + errorMessage); } + } export async function clickupApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string ,method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 28b45b122..762c7e042 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -44,6 +44,7 @@ "dist/credentials/CircleCiApi.credentials.js", "dist/credentials/ClearbitApi.credentials.js", "dist/credentials/ClickUpApi.credentials.js", + "dist/credentials/ClickUpOAuth2Api.credentials.js", "dist/credentials/ClockifyApi.credentials.js", "dist/credentials/CockpitApi.credentials.js", "dist/credentials/CodaApi.credentials.js", diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index af62220d8..7f1deea37 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -16,6 +16,7 @@ export interface IOAuth2Options { includeCredentialsOnRefreshOnBody?: boolean; property?: string; tokenType?: string; + keepBearer?: boolean; } export interface IConnection {