From 6c527f8e8e7fd14f45f71253ee6f9b3cb7dc18f1 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 14 Oct 2021 05:47:29 -0700 Subject: [PATCH 1/3] :sparkles: Add share functionality to NextCloud --- .../nodes/NextCloud/GenericFunctions.ts | 2 +- .../nodes/NextCloud/NextCloud.node.ts | 264 +++++++++++++++++- 2 files changed, 264 insertions(+), 2 deletions(-) diff --git a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts index ae96def71e..586dc75546 100644 --- a/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts +++ b/packages/nodes-base/nodes/NextCloud/GenericFunctions.ts @@ -50,7 +50,7 @@ export async function nextCloudApiRequest(this: IHookFunctions | IExecuteFunctio options.uri = `${credentials.webDavUrl}/${encodeURI(endpoint)}`; - if (resource === 'user') { + if (resource === 'user' || operation === 'share') { options.uri = options.uri.replace('/remote.php/webdav', ''); } return await this.helpers.request(options); diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index f27db51228..cb1cb316ac 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -11,6 +11,8 @@ import { NodeOperationError, } from 'n8n-workflow'; +import { URLSearchParams } from 'url'; + import { parseString, } from 'xml2js'; @@ -135,6 +137,11 @@ export class NextCloud implements INodeType { value: 'move', description: 'Move a file', }, + { + name: 'Share', + value: 'share', + description: 'Share a file', + }, { name: 'Upload', value: 'upload', @@ -472,7 +479,215 @@ export class NextCloud implements INodeType { description: 'Name of the binary property which contains
the data for the file to be uploaded.', }, - + // ---------------------------------- + // file:share + // ---------------------------------- + { + displayName: 'File Path', + name: 'path', + type: 'string', + default: '', + required: true, + displayOptions: { + show: { + operation: [ + 'share', + ], + resource: [ + 'file', + ], + }, + }, + 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 "/"', + }, + { + displayName: 'Share Type', + name: 'shareType', + type: 'options', + displayOptions: { + show: { + operation: [ + 'share', + ], + resource: [ + 'file', + ], + }, + }, + options: [ + { + name: 'Circle', + value: 7, + }, + { + name: 'EMail', + value: 4, + }, + { + name: 'Group', + value: 1, + }, + { + name: 'Public Link', + value: 3, + }, + { + name: 'User', + value: 0, + }, + ], + default: 0, + description: 'The share permissions to set', + }, + { + displayName: 'Circle ID', + name: 'circleId', + type: 'string', + displayOptions: { + show: { + resource: [ + 'file', + ], + operation: [ + 'share', + ], + shareType: [ + 7, + ] + }, + }, + default: '', + description: 'The ID of the circle to share with', + }, + { + displayName: 'Email', + name: 'email', + type: 'string', + displayOptions: { + show: { + resource: [ + 'file', + ], + operation: [ + 'share', + ], + shareType: [ + 4, + ] + }, + }, + default: '', + description: 'The Email address to share with', + }, + { + displayName: 'Group ID', + name: 'groupId', + type: 'string', + displayOptions: { + show: { + resource: [ + 'file', + ], + operation: [ + 'share', + ], + shareType: [ + 1, + ] + }, + }, + default: '', + description: 'The ID of the group to share with', + }, + { + displayName: 'User', + name: 'user', + type: 'string', + displayOptions: { + show: { + resource: [ + 'file', + ], + operation: [ + 'share', + ], + shareType: [ + 0, + ] + }, + }, + default: '', + description: 'The user to share with', + }, + { + displayName: 'Options', + name: 'options', + type: 'collection', + placeholder: 'Add Option', + default: {}, + displayOptions: { + show: { + resource: [ + 'file', + ], + operation: [ + 'share', + ], + }, + }, + options: [ + { + displayName: 'Password', + name: 'password', + type: 'string', + displayOptions: { + show: { + '/resource': [ + 'file', + ], + '/operation': [ + 'share', + ], + '/shareType': [ + 3, + ] + }, + }, + default: '', + description: 'Optional search string.', + }, + { + displayName: 'Permissions', + name: 'permissions', + type: 'options', + options: [ + { + name: 'All', + value: 31, + }, + { + name: 'Create', + value: 4, + }, + { + name: 'Delete', + value: 8, + }, + { + name: 'Read', + value: 1, + }, + { + name: 'Update', + value: 2, + }, + ], + default: 1, + description: 'The share permissions to set', + }, + ], + }, // ---------------------------------- // folder @@ -844,6 +1059,36 @@ export class NextCloud implements INodeType { // Is text file body = this.getNodeParameter('fileContent', i) as string; } + } else if (operation === 'share') { + // ---------------------------------- + // share + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = 'ocs/v2.php/apps/files_sharing/api/v1/shares'; + + headers['OCS-APIRequest'] = true; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + + const bodyParameters = this.getNodeParameter('options', i) as IDataObject; + + bodyParameters.path = this.getNodeParameter('path', i) as string; + bodyParameters.shareType = this.getNodeParameter('shareType', i) as number; + + if (bodyParameters.shareType === 0) { + bodyParameters.shareWith = this.getNodeParameter('user', i) as string; + } else if (bodyParameters.shareType === 7) { + bodyParameters.shareWith = this.getNodeParameter('circleId', i) as number; + } else if (bodyParameters.shareType === 4) { + bodyParameters.shareWith = this.getNodeParameter('email', i) as string; + } else if (bodyParameters.shareType === 1) { + bodyParameters.shareWith = this.getNodeParameter('groupId', i) as number; + } + + // @ts-ignore + body = new URLSearchParams(bodyParameters).toString(); + } } else if (resource === 'folder') { if (operation === 'create') { @@ -1032,6 +1277,23 @@ export class NextCloud implements INodeType { items[i].binary![binaryPropertyName] = await this.helpers.prepareBinaryData(responseData, endpoint); + } else if (resource === 'file' && operation === 'share') { + const jsonResponseData: IDataObject = await new Promise((resolve, reject) => { + parseString(responseData, { explicitArray: false }, (err, data) => { + if (err) { + return reject(err); + } + + if (data.ocs.meta.status !== 'ok') { + return reject(new Error(data.ocs.meta.message || data.ocs.meta.status)); + } + + resolve(data.ocs.data as IDataObject); + }); + }); + + returnData.push(jsonResponseData as IDataObject); + } else if (resource === 'user') { if (operation !== 'getAll') { From 0c4bb6eb5ed0e432bffc35fcad0dcf005f63fbeb Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 14 Oct 2021 05:56:05 -0700 Subject: [PATCH 2/3] :shirt: Fix lint issue --- packages/nodes-base/nodes/NextCloud/NextCloud.node.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index cb1cb316ac..3604c94fa7 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -554,7 +554,7 @@ export class NextCloud implements INodeType { ], shareType: [ 7, - ] + ], }, }, default: '', @@ -574,7 +574,7 @@ export class NextCloud implements INodeType { ], shareType: [ 4, - ] + ], }, }, default: '', @@ -594,7 +594,7 @@ export class NextCloud implements INodeType { ], shareType: [ 1, - ] + ], }, }, default: '', @@ -614,7 +614,7 @@ export class NextCloud implements INodeType { ], shareType: [ 0, - ] + ], }, }, default: '', @@ -651,7 +651,7 @@ export class NextCloud implements INodeType { ], '/shareType': [ 3, - ] + ], }, }, default: '', From a34eab5813d346e8a7a16866b8bd3d20e5eda8f7 Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Thu, 14 Oct 2021 11:15:21 -0700 Subject: [PATCH 3/3] :zap: All at share to folder resource --- .../nodes/NextCloud/NextCloud.node.ts | 76 +++++++++++-------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts index 3604c94fa7..455d724a44 100644 --- a/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts +++ b/packages/nodes-base/nodes/NextCloud/NextCloud.node.ts @@ -189,6 +189,11 @@ export class NextCloud implements INodeType { value: 'move', description: 'Move a folder', }, + { + name: 'Share', + value: 'share', + description: 'Share a folder', + }, ], default: 'create', description: 'The operation to perform.', @@ -495,6 +500,7 @@ export class NextCloud implements INodeType { ], resource: [ 'file', + 'folder', ], }, }, @@ -512,6 +518,7 @@ export class NextCloud implements INodeType { ], resource: [ 'file', + 'folder', ], }, }, @@ -521,7 +528,7 @@ export class NextCloud implements INodeType { value: 7, }, { - name: 'EMail', + name: 'Email', value: 4, }, { @@ -548,6 +555,7 @@ export class NextCloud implements INodeType { show: { resource: [ 'file', + 'folder', ], operation: [ 'share', @@ -568,6 +576,7 @@ export class NextCloud implements INodeType { show: { resource: [ 'file', + 'folder', ], operation: [ 'share', @@ -588,6 +597,7 @@ export class NextCloud implements INodeType { show: { resource: [ 'file', + 'folder', ], operation: [ 'share', @@ -608,6 +618,7 @@ export class NextCloud implements INodeType { show: { resource: [ 'file', + 'folder', ], operation: [ 'share', @@ -630,6 +641,7 @@ export class NextCloud implements INodeType { show: { resource: [ 'file', + 'folder', ], operation: [ 'share', @@ -645,6 +657,7 @@ export class NextCloud implements INodeType { show: { '/resource': [ 'file', + 'folder', ], '/operation': [ 'share', @@ -1059,36 +1072,6 @@ export class NextCloud implements INodeType { // Is text file body = this.getNodeParameter('fileContent', i) as string; } - } else if (operation === 'share') { - // ---------------------------------- - // share - // ---------------------------------- - - requestMethod = 'POST'; - - endpoint = 'ocs/v2.php/apps/files_sharing/api/v1/shares'; - - headers['OCS-APIRequest'] = true; - headers['Content-Type'] = 'application/x-www-form-urlencoded'; - - const bodyParameters = this.getNodeParameter('options', i) as IDataObject; - - bodyParameters.path = this.getNodeParameter('path', i) as string; - bodyParameters.shareType = this.getNodeParameter('shareType', i) as number; - - if (bodyParameters.shareType === 0) { - bodyParameters.shareWith = this.getNodeParameter('user', i) as string; - } else if (bodyParameters.shareType === 7) { - bodyParameters.shareWith = this.getNodeParameter('circleId', i) as number; - } else if (bodyParameters.shareType === 4) { - bodyParameters.shareWith = this.getNodeParameter('email', i) as string; - } else if (bodyParameters.shareType === 1) { - bodyParameters.shareWith = this.getNodeParameter('groupId', i) as number; - } - - // @ts-ignore - body = new URLSearchParams(bodyParameters).toString(); - } } else if (resource === 'folder') { if (operation === 'create') { @@ -1139,6 +1122,35 @@ export class NextCloud implements INodeType { const toPath = this.getNodeParameter('toPath', i) as string; headers.Destination = `${credentials.webDavUrl}/${encodeURI(toPath)}`; + } else if (operation === 'share') { + // ---------------------------------- + // share + // ---------------------------------- + + requestMethod = 'POST'; + + endpoint = 'ocs/v2.php/apps/files_sharing/api/v1/shares'; + + headers['OCS-APIRequest'] = true; + headers['Content-Type'] = 'application/x-www-form-urlencoded'; + + const bodyParameters = this.getNodeParameter('options', i) as IDataObject; + + bodyParameters.path = this.getNodeParameter('path', i) as string; + bodyParameters.shareType = this.getNodeParameter('shareType', i) as number; + + if (bodyParameters.shareType === 0) { + bodyParameters.shareWith = this.getNodeParameter('user', i) as string; + } else if (bodyParameters.shareType === 7) { + bodyParameters.shareWith = this.getNodeParameter('circleId', i) as number; + } else if (bodyParameters.shareType === 4) { + bodyParameters.shareWith = this.getNodeParameter('email', i) as string; + } else if (bodyParameters.shareType === 1) { + bodyParameters.shareWith = this.getNodeParameter('groupId', i) as number; + } + + // @ts-ignore + body = new URLSearchParams(bodyParameters).toString(); } } else if (resource === 'user') { @@ -1277,7 +1289,7 @@ export class NextCloud implements INodeType { items[i].binary![binaryPropertyName] = await this.helpers.prepareBinaryData(responseData, endpoint); - } else if (resource === 'file' && operation === 'share') { + } else if (['file', 'folder'].includes(resource) && operation === 'share') { const jsonResponseData: IDataObject = await new Promise((resolve, reject) => { parseString(responseData, { explicitArray: false }, (err, data) => { if (err) {