Clickup OAuth2 support (#649)

* OAuth2 credentials, genericFunctions needed config, UI options for oauth2 support

*  Added options to decide when to to send the bearer

* Fixed "undefined property split" issue

*  Small fix

*  Improvements to ClickUp-Node

*  Improvements

Co-authored-by: Rupenieks <ru@myos,co>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
Co-authored-by: Ricardo Espinoza <ricardo@n8n.io>
This commit is contained in:
Rupenieks 2020-09-16 09:16:06 +02:00 committed by GitHub
parent 7c54cf6ac2
commit 266112a8cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 152 additions and 10 deletions

View file

@ -152,6 +152,12 @@ export function requestOAuth2(this: IAllExecuteFunctions, credentialsType: strin
// on the token-type used. // on the token-type used.
const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject); 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) return this.helpers.request!(newRequestOptions)
.catch(async (error: IResponseError) => { .catch(async (error: IResponseError) => {
// TODO: Check if also other codes are possible // TODO: Check if also other codes are possible

View file

@ -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.',
},
];
}

View file

@ -99,9 +99,43 @@ export class ClickUp implements INodeType {
{ {
name: 'clickUpApi', name: 'clickUpApi',
required: true, required: true,
displayOptions: {
show: {
authentication: [
'accessToken',
],
},
},
},
{
name: 'clickUpOAuth2Api',
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
},
},
}, },
], ],
properties: [ properties: [
{
displayName: 'Authentication',
name: 'authentication',
type: 'options',
options: [
{
name: 'Access Token',
value: 'accessToken',
},
{
name: 'OAuth2',
value: 'oAuth2',
},
],
default: 'accessToken',
},
{ {
displayName: 'Resource', displayName: 'Resource',
name: 'resource', name: 'resource',

View file

@ -34,9 +34,27 @@ export class ClickUpTrigger implements INodeType {
outputs: ['main'], outputs: ['main'],
credentials: [ credentials: [
{ {
name: 'clickUpApi', name: 'clickupApi',
required: true, required: true,
} displayOptions: {
show: {
authentication: [
'accessToken',
],
},
},
},
{
name: 'clickUpOAuth2Api',
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
},
},
},
], ],
webhooks: [ webhooks: [
{ {
@ -47,6 +65,22 @@ export class ClickUpTrigger implements INodeType {
}, },
], ],
properties: [ properties: [
{
displayName: 'Authentication',
name: 'authentication',
type: 'options',
options: [
{
name: 'Access Token',
value: 'accessToken',
},
{
name: 'OAuth2',
value: 'oAuth2',
},
],
default: 'accessToken',
},
{ {
displayName: 'Team', displayName: 'Team',
name: 'team', name: 'team',

View file

@ -12,17 +12,12 @@ import {
import { import {
IDataObject, IDataObject,
IOAuth2Options,
} from 'n8n-workflow'; } 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<any> { // tslint:disable-line:no-any export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions | IWebhookFunctions, method: string, resource: string, body: any = {}, qs: IDataObject = {}, uri?: string, option: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any
const credentials = this.getCredentials('clickUpApi');
if (credentials === undefined) {
throw new Error('No credentials got returned!');
}
const options: OptionsWithUri = { const options: OptionsWithUri = {
headers: { headers: {
Authorization: credentials.accessToken,
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
method, method,
@ -31,15 +26,39 @@ export async function clickupApiRequest(this: IHookFunctions | IExecuteFunctions
uri: uri ||`https://api.clickup.com/api/v2${resource}`, uri: uri ||`https://api.clickup.com/api/v2${resource}`,
json: true json: true
}; };
try { try {
return await this.helpers.request!(options); const authenticationMethod = this.getNodeParameter('authentication', 0) as string;
} catch (error) {
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; let errorMessage = error;
if (error.err) { if (error.err) {
errorMessage = error.err; errorMessage = error.err;
} }
throw new Error('ClickUp Error: ' + errorMessage); 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<any> { // tslint:disable-line:no-any export async function clickupApiRequestAllItems(this: IHookFunctions | IExecuteFunctions| ILoadOptionsFunctions, propertyName: string ,method: string, resource: string, body: any = {}, query: IDataObject = {}): Promise<any> { // tslint:disable-line:no-any

View file

@ -44,6 +44,7 @@
"dist/credentials/CircleCiApi.credentials.js", "dist/credentials/CircleCiApi.credentials.js",
"dist/credentials/ClearbitApi.credentials.js", "dist/credentials/ClearbitApi.credentials.js",
"dist/credentials/ClickUpApi.credentials.js", "dist/credentials/ClickUpApi.credentials.js",
"dist/credentials/ClickUpOAuth2Api.credentials.js",
"dist/credentials/ClockifyApi.credentials.js", "dist/credentials/ClockifyApi.credentials.js",
"dist/credentials/CockpitApi.credentials.js", "dist/credentials/CockpitApi.credentials.js",
"dist/credentials/CodaApi.credentials.js", "dist/credentials/CodaApi.credentials.js",

View file

@ -16,6 +16,7 @@ export interface IOAuth2Options {
includeCredentialsOnRefreshOnBody?: boolean; includeCredentialsOnRefreshOnBody?: boolean;
property?: string; property?: string;
tokenType?: string; tokenType?: string;
keepBearer?: boolean;
} }
export interface IConnection { export interface IConnection {