fix(NextCloud Node): Fix folder list with Nextcloud v24 (#3386)

* initial fix for v24 folder listing

* implemented new credential methods

* Nodelinter fixes
This commit is contained in:
Jonathan Bennetts 2022-05-27 16:15:12 +01:00 committed by GitHub
parent ed69c3cc18
commit 5f3bed3d4e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 59 additions and 42 deletions

View file

@ -1,9 +1,11 @@
import {
ICredentialDataDecryptedObject,
ICredentialTestRequest,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';
export class NextCloudApi implements ICredentialType {
name = 'nextCloudApi';
displayName = 'NextCloud API';
@ -29,4 +31,18 @@ export class NextCloudApi implements ICredentialType {
default: '',
},
];
async authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
requestOptions.auth = {
username: credentials.user as string,
password: credentials.password as string,
};
return requestOptions;
}
test: ICredentialTestRequest = {
request: {
baseURL: '={{$credentials.webDavUrl.replace(\'/remote.php/webdav\', \'\')}}',
url: '/ocs/v1.php/cloud/capabilities',
headers: {'OCS-APIRequest': true},
},
};
}

View file

@ -2,7 +2,11 @@ import {
IExecuteFunctions,
IHookFunctions,
} from 'n8n-core';
import { NodeApiError, NodeOperationError, } from 'n8n-workflow';
import {
JsonObject,
NodeApiError,
} from 'n8n-workflow';
import {
OptionsWithUri,
@ -20,8 +24,17 @@ import {
export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctions, method: string, endpoint: string, body: object | string | Buffer, headers?: object, encoding?: null | undefined, query?: object): Promise<any> { // tslint:disable-line:no-any
const resource = this.getNodeParameter('resource', 0);
const operation = this.getNodeParameter('operation', 0);
const authenticationMethod = this.getNodeParameter('authentication', 0);
const options: OptionsWithUri = {
let credentials;
if (authenticationMethod === 'accessToken') {
credentials = await this.getCredentials('nextCloudApi') as { webDavUrl: string };
} else {
credentials = await this.getCredentials('nextCloudOAuth2Api') as { webDavUrl: string };
}
let options: OptionsWithUri = {
headers,
method,
body,
@ -34,35 +47,16 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio
options.encoding = null;
}
const authenticationMethod = this.getNodeParameter('authentication', 0);
options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`;
if (resource === 'user' && operation === 'create') {
options.uri = options.uri.replace('/remote.php/webdav', '');
}
const credentialType = authenticationMethod === 'accessToken' ? 'nextCloudApi' : 'nextCloudOAuth2Api';
try {
if (authenticationMethod === 'accessToken') {
const credentials = await this.getCredentials('nextCloudApi');
options.auth = {
user: credentials.user as string,
pass: credentials.password as string,
};
options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`;
if (resource === 'user' || operation === 'share') {
options.uri = options.uri.replace('/remote.php/webdav', '');
}
return await this.helpers.request(options);
} else {
const credentials = await this.getCredentials('nextCloudOAuth2Api');
options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`;
if (resource === 'user' && operation === 'create') {
options.uri = options.uri.replace('/remote.php/webdav', '');
}
return await this.helpers.requestOAuth2!.call(this, 'nextCloudOAuth2Api', options);
}
} catch (error) {
throw new NodeApiError(this.getNode(), error);
return await this.helpers.requestWithAuthentication.call(this, credentialType, options);
} catch(error) {
throw new NodeApiError(this.getNode(), error as JsonObject);
}
}

View file

@ -1,4 +1,5 @@
import { IExecuteFunctions } from 'n8n-core';
import { NodeApiError } from 'n8n-workflow';
import {
IDataObject,
@ -22,7 +23,7 @@ export class NextCloud implements INodeType {
description: INodeTypeDescription = {
displayName: 'Nextcloud',
name: 'nextCloud',
icon: 'file:nextcloud.png',
icon: 'file:nextcloud.svg',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
@ -305,7 +306,7 @@ export class NextCloud implements INodeType {
},
},
placeholder: '/invoices/2019/invoice_1.pdf',
description: 'The path to delete. Can be a single file or a whole folder. The path should start with "/"',
description: 'The path to delete. Can be a single file or a whole folder. The path should start with "/".',
},
// ----------------------------------
@ -372,7 +373,7 @@ export class NextCloud implements INodeType {
},
},
placeholder: '/invoices/2019/invoice_1.pdf',
description: 'The file path of the file to download. Has to contain the full path. The path should start with "/"',
description: 'The file path of the file to download. Has to contain the full path. The path should start with "/".',
},
{
displayName: 'Binary Property',
@ -499,7 +500,7 @@ export class NextCloud implements INodeType {
},
},
placeholder: '/invoices/2019/invoice_1.pdf',
description: 'The file path of the file to share. Has to contain the full path. The path should start with "/"',
description: 'The file path of the file to share. Has to contain the full path. The path should start with "/".',
},
{
displayName: 'Share Type',
@ -720,7 +721,7 @@ export class NextCloud implements INodeType {
},
},
placeholder: '/invoices/2019',
description: 'The folder to create. The parent folder has to exist. The path should start with "/"',
description: 'The folder to create. The parent folder has to exist. The path should start with "/".',
},
// ----------------------------------
@ -808,7 +809,7 @@ export class NextCloud implements INodeType {
},
options: [
{
displayName: 'Display name',
displayName: 'Display Name',
name: 'displayName',
type: 'string',
default: '',
@ -1287,7 +1288,7 @@ export class NextCloud implements INodeType {
}
if (data.ocs.meta.status !== 'ok') {
return reject(new Error(data.ocs.meta.message || data.ocs.meta.status));
return reject(new NodeApiError(this.getNode(), data.ocs.meta.message || data.ocs.meta.status));
}
resolve(data.ocs.data as IDataObject);
@ -1307,7 +1308,7 @@ export class NextCloud implements INodeType {
}
if (data.ocs.meta.status !== 'ok') {
return reject(new Error(data.ocs.meta.message || data.ocs.meta.status));
return reject(new NodeApiError(this.getNode(), data.ocs.meta.message || data.ocs.meta.status));
}
if (operation === 'delete' || operation === 'update') {
@ -1328,7 +1329,7 @@ export class NextCloud implements INodeType {
}
if (data.ocs.meta.status !== 'ok') {
return reject(new Error(data.ocs.meta.message));
return reject(new NodeApiError(this.getNode(), data.ocs.meta.message));
}
if (typeof (data.ocs.data.users.element) === 'string') {
@ -1366,7 +1367,6 @@ export class NextCloud implements INodeType {
(jsonResponseData['d:multistatus'] as IDataObject)['d:response'] !== undefined &&
(jsonResponseData['d:multistatus'] as IDataObject)['d:response'] !== null) {
let skippedFirst = false;
// @ts-ignore
if (Array.isArray(jsonResponseData['d:multistatus']['d:response'])) {
// @ts-ignore
@ -1379,7 +1379,12 @@ export class NextCloud implements INodeType {
newItem.path = item['d:href'].slice(19);
const props = item['d:propstat'][0]['d:prop'];
let props: IDataObject = {};
if (Array.isArray(item['d:propstat'])) {
props = item['d:propstat'][0]['d:prop'] as IDataObject;
} else {
props = item['d:propstat']['d:prop'] as IDataObject;
}
// Get the props and save them under a proper name
for (const propName of Object.keys(propNames)) {
@ -1393,6 +1398,7 @@ export class NextCloud implements INodeType {
} else {
newItem.type = 'folder';
}
// @ts-ignore
newItem.eTag = props['d:getetag'].slice(1, -1);
returnData.push(newItem as IDataObject);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 76 51" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#A" x=".5" y=".5"/><symbol id="A" overflow="visible"><path d="M37.533 0c-7.77 0-14.355 5.268-16.396 12.379-1.778-3.819-5.597-6.453-10.075-6.453C5.004 5.926 0 10.931 0 17.054a11.16 11.16 0 0 0 11.128 11.128c4.412 0 8.297-2.634 10.075-6.453a16.99 16.99 0 0 0 16.33 12.379c7.704 0 14.289-5.202 16.396-12.248 1.778 3.687 5.597 6.256 9.943 6.256A11.16 11.16 0 0 0 75 16.989c0-6.124-5.004-11.062-11.128-11.062-4.346 0-8.165 2.568-9.943 6.256C51.822 5.202 45.303 0 37.533 0zm0 6.519a10.48 10.48 0 0 1 10.535 10.536A10.48 10.48 0 0 1 37.533 27.59a10.48 10.48 0 0 1-10.536-10.535A10.48 10.48 0 0 1 37.533 6.519zm-26.405 5.926a4.58 4.58 0 0 1 4.609 4.609 4.58 4.58 0 0 1-4.609 4.609 4.58 4.58 0 0 1-4.609-4.609 4.58 4.58 0 0 1 4.609-4.609zm52.744 0a4.58 4.58 0 0 1 4.609 4.609 4.609 4.609 0 1 1-9.218 0c.066-2.568 2.041-4.609 4.609-4.609zM19.176 41.957c1.827 0 2.85 1.301 2.85 3.252 0 .186-.155.341-.341.341H16.76c.031 1.734 1.239 2.726 2.633 2.726a2.89 2.89 0 0 0 1.796-.619c.186-.124.341-.093.434.093l.093.155c.093.155.062.31-.093.434a3.84 3.84 0 0 1-2.261.743c-2.013 0-3.562-1.456-3.562-3.562.031-2.23 1.518-3.562 3.376-3.562zm1.889 2.911c-.062-1.425-.929-2.137-1.92-2.137-1.146 0-2.137.743-2.354 2.137h4.274zm10.253-1.92v-.774-1.611c0-.217.124-.341.341-.341h.248c.217 0 .31.124.31.341v1.611h1.394c.217 0 .341.124.341.341v.093c0 .217-.124.31-.341.31h-1.394v3.407c0 1.58.96 1.766 1.487 1.796.279.031.372.093.372.341v.186c0 .217-.093.31-.372.31-1.487 0-2.385-.898-2.385-2.509v-3.5zm7.093-.991c1.177 0 1.92.496 2.261.774.155.124.186.279.031.465l-.093.155c-.124.186-.279.186-.465.062-.31-.217-.898-.619-1.703-.619-1.487 0-2.664 1.115-2.664 2.757 0 1.611 1.177 2.726 2.664 2.726.96 0 1.611-.434 1.92-.712.186-.124.31-.093.434.093l.093.124c.093.186.062.31-.093.465a3.81 3.81 0 0 1-2.416.867c-2.013 0-3.562-1.456-3.562-3.562.031-2.106 1.58-3.593 3.593-3.593zm4.119-2.199c0-.217-.124-.341.093-.341h.248c.217 0 .558.124.558.341v7.403c0 .867.403.96.712.991.155 0 .279.093.279.31v.217c0 .217-.093.341-.341.341-.557 0-1.549-.186-1.549-1.673v-7.589zm6.35 2.199c1.982 0 3.593 1.518 3.593 3.531 0 2.044-1.611 3.593-3.593 3.593s-3.593-1.549-3.593-3.593c0-2.013 1.611-3.531 3.593-3.531zm0 6.319c1.456 0 2.633-1.177 2.633-2.788 0-1.549-1.177-2.695-2.633-2.695a2.67 2.67 0 0 0-2.664 2.695c.031 1.58 1.208 2.788 2.664 2.788zm15.456-6.319a2.45 2.45 0 0 1 2.23 1.363h.031s-.031-.217-.031-.526v-3.066c0-.217-.093-.341.124-.341h.248c.217 0 .558.124.558.341v8.827c0 .217-.093.341-.31.341h-.217c-.217 0-.341-.093-.341-.31v-.527c0-.248.062-.434.062-.434h-.031s-.589 1.425-2.354 1.425c-1.827 0-2.973-1.456-2.973-3.562-.062-2.106 1.208-3.531 3.004-3.531h0zm.031 6.319c1.146 0 2.199-.805 2.199-2.757 0-1.394-.712-2.726-2.168-2.726-1.208 0-2.199.991-2.199 2.726.031 1.673.898 2.757 2.168 2.757zm-56.558.65h.248c.217 0 .341-.124.341-.341v-6.628c0-1.053 1.146-1.796 2.447-1.796s2.447.743 2.447 1.796v6.659c0 .217.124.341.341.341h.248c.217 0 .31-.124.31-.341v-6.721c0-1.766-1.765-2.633-3.376-2.633h0 0 0 0c-1.549 0-3.314.867-3.314 2.633v6.69c0 .217.093.341.31.341zm51.695-6.814h-.248c-.217 0-.341.124-.341.341v3.748c0 1.053-.681 2.013-2.013 2.013-1.301 0-2.013-.96-2.013-2.013v-3.748c0-.217-.124-.341-.341-.341H54.3c-.217 0-.31.124-.31.341v3.996c0 1.765 1.301 2.633 2.912 2.633h0 0 0 0c1.611 0 2.911-.867 2.911-2.633v-3.996c.031-.217-.093-.341-.31-.341h0zm-30.664-.031c-.062 0-.155.062-.217.155l-1.239 1.487-.929 1.115-1.425-1.704-.774-.929c-.062-.093-.155-.124-.217-.124s-.155.031-.248.093l-.186.155c-.155.124-.155.279-.031.465l1.239 1.487 1.053 1.239-1.518 1.827h0l-.774.929c-.124.155-.124.341.031.496l.186.155c.155.124.31.093.465-.062l1.239-1.487.929-1.115 1.425 1.704h0l.774.929c.124.155.31.186.465.031l.186-.155c.155-.124.155-.279.031-.465l-1.239-1.487-1.053-1.239 1.518-1.827h0l.774-.929c.124-.155.124-.341-.031-.495l-.186-.186c-.093-.062-.155-.093-.248-.062h0z" fill="#0082c9" fill-rule="nonzero" stroke="none"/></symbol></svg>

After

Width:  |  Height:  |  Size: 4 KiB