diff --git a/packages/nodes-base/credentials/NextCloudApi.credentials.ts b/packages/nodes-base/credentials/NextCloudApi.credentials.ts index c75632df00..3081455506 100644 --- a/packages/nodes-base/credentials/NextCloudApi.credentials.ts +++ b/packages/nodes-base/credentials/NextCloudApi.credentials.ts @@ -12,7 +12,7 @@ export class NextCloudApi implements ICredentialType { displayName: 'Web DAV URL', name: 'webDavUrl', type: 'string' as NodePropertyTypes, - placeholder: 'https://nextcloud.example.com/remote.php/webdav/', + placeholder: 'https://nextcloud.example.com/remote.php/webdav', default: '', }, { diff --git a/packages/nodes-base/credentials/NextCloudOAuth2Api.credentials.ts b/packages/nodes-base/credentials/NextCloudOAuth2Api.credentials.ts new file mode 100644 index 0000000000..9379ee5203 --- /dev/null +++ b/packages/nodes-base/credentials/NextCloudOAuth2Api.credentials.ts @@ -0,0 +1,54 @@ +import { + ICredentialType, + NodePropertyTypes, +} from 'n8n-workflow'; + + +export class NextCloudOAuth2Api implements ICredentialType { + name = 'nextCloudOAuth2Api'; + extends = [ + 'oAuth2Api', + ]; + displayName = 'NextCloud OAuth2 API'; + properties = [ + { + displayName: 'Web DAV URL', + name: 'webDavUrl', + type: 'string' as NodePropertyTypes, + placeholder: 'https://nextcloud.example.com/remote.php/webdav', + default: '', + }, + { + displayName: 'Authorization URL', + name: 'authUrl', + type: 'string' as NodePropertyTypes, + default: 'https://nextcloud.example.com/apps/oauth2/authorize', + required: true, + }, + { + displayName: 'Access Token URL', + name: 'accessTokenUrl', + type: 'string' as NodePropertyTypes, + default: 'https://nextcloud.example.com/apps/oauth2/api/v1/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', + }, + ]; +} diff --git a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts new file mode 100644 index 0000000000..2198cb5513 --- /dev/null +++ b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts @@ -0,0 +1,63 @@ +import { + IExecuteFunctions, + IHookFunctions, +} from 'n8n-core'; + +import { + OptionsWithUri, +} from 'request'; + +/** + * Make an API request to NextCloud + * + * @param {IHookFunctions} this + * @param {string} method + * @param {string} url + * @param {object} body + * @returns {Promise} + */ +export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object | string | Buffer, headers?: object, encoding?: null | undefined, query?: object): Promise { // tslint:disable-line:no-any + const options : OptionsWithUri = { + headers, + method, + body, + qs: {}, + uri: '', + json: false, + }; + + if (encoding === null) { + options.encoding = null; + } + + const authenticationMethod = this.getNodeParameter('authentication', 0); + + try { + if (authenticationMethod === 'accessToken') { + const credentials = this.getCredentials('nextCloudApi'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + options.auth = { + user: credentials.user as string, + pass: credentials.password as string, + }; + + options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`; + + return await this.helpers.request(options); + } else { + const credentials = this.getCredentials('nextCloudOAuth2Api'); + if (credentials === undefined) { + throw new Error('No credentials got returned!'); + } + + options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`; + + return await this.helpers.requestOAuth2!.call(this, 'nextCloudOAuth2Api', options); + } + } catch (error) { + throw new Error(`NextCloud Error. Status Code: ${error.statusCode}. Message: ${error.message}`); + } +} diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index 309f53ceae..a5b3109c6e 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -2,6 +2,7 @@ import { BINARY_ENCODING, IExecuteFunctions, } from 'n8n-core'; + import { IDataObject, INodeTypeDescription, @@ -9,9 +10,13 @@ import { INodeType, } from 'n8n-workflow'; -import { parseString } from 'xml2js'; -import { OptionsWithUri } from 'request'; +import { + parseString, +} from 'xml2js'; +import { + nextCloudApiRequest, +} from './GenericFunctions'; export class NextCloud implements INodeType { description: INodeTypeDescription = { @@ -24,7 +29,7 @@ export class NextCloud implements INodeType { description: 'Access data on NextCloud', defaults: { name: 'NextCloud', - color: '#22BB44', + color: '#1cafff', }, inputs: ['main'], outputs: ['main'], @@ -32,9 +37,44 @@ export class NextCloud implements INodeType { { name: 'nextCloudApi', required: true, - } + displayOptions: { + show: { + authentication: [ + 'accessToken', + ], + }, + }, + }, + { + name: 'nextCloudOAuth2Api', + 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', + description: 'The resource to operate on.', + }, { displayName: 'Resource', name: 'resource', @@ -446,7 +486,14 @@ export class NextCloud implements INodeType { const items = this.getInputData().slice(); const returnData: IDataObject[] = []; - const credentials = this.getCredentials('nextCloudApi'); + const authenticationMethod = this.getNodeParameter('authentication', 0); + let credentials; + + if (authenticationMethod === 'accessToken') { + credentials = this.getCredentials('nextCloudApi'); + } else { + credentials = this.getCredentials('nextCloudOAuth2Api'); + } if (credentials === undefined) { throw new Error('No credentials got returned!'); @@ -562,26 +609,14 @@ export class NextCloud implements INodeType { webDavUrl = webDavUrl.slice(0, -1); } - const options: OptionsWithUri = { - auth: { - user: credentials.user as string, - pass: credentials.password as string, - }, - headers, - method: requestMethod, - body, - qs: {}, - uri: `${credentials.webDavUrl}/${encodeURI(endpoint)}`, - json: false, - }; - + let encoding = undefined; if (resource === 'file' && operation === 'download') { // Return the data as a buffer - options.encoding = null; + encoding = null; } try { - responseData = await this.helpers.request(options); + responseData = await nextCloudApiRequest.call(this, requestMethod, endpoint, body, headers, encoding); } catch (error) { if (this.continueOnFail() === true) { returnData.push({ error }); diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index d5e1796141..cb32786983 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -104,6 +104,7 @@ "dist/credentials/Msg91Api.credentials.js", "dist/credentials/MySql.credentials.js", "dist/credentials/NextCloudApi.credentials.js", + "dist/credentials/NextCloudOAuth2Api.credentials.js", "dist/credentials/OAuth1Api.credentials.js", "dist/credentials/OAuth2Api.credentials.js", "dist/credentials/OpenWeatherMapApi.credentials.js",