Add file:search operation to Dropbox Node (#1494)

*  Add search resource to Dropbox Node

* 📚 Add breaking change instructions

*  Add missing credentials

*  Add "simple" parameter to the operation search:query

*  Update breaking change message

*  Improvement

Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Ricardo Espinoza
2021-03-11 03:16:05 -05:00
committed by GitHub
parent 263813a8f9
commit e1dbb72929
6 changed files with 451 additions and 16 deletions

View File

@@ -11,21 +11,24 @@ import {
} from 'n8n-workflow';
import {
dropboxApiRequest
dropboxApiRequest,
dropboxpiRequestAllItems,
getRootDirectory,
simplify,
} from './GenericFunctions';
export class Dropbox implements INodeType {
description: INodeTypeDescription = {
displayName: 'Dropbox',
name: 'dropbox',
icon: 'file:dropbox.png',
icon: 'file:dropbox.svg',
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Access data on Dropbox',
defaults: {
name: 'Dropbox',
color: '#0062ff',
color: '#007ee5',
},
inputs: ['main'],
outputs: ['main'],
@@ -84,6 +87,10 @@ export class Dropbox implements INodeType {
name: 'Folder',
value: 'folder',
},
{
name: 'Search',
value: 'search',
},
],
default: 'file',
description: 'The resource to operate on.',
@@ -176,6 +183,27 @@ export class Dropbox implements INodeType {
description: 'The operation to perform.',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'search',
],
},
},
options: [
{
name: 'Query',
value: 'query',
},
],
default: 'query',
description: 'The operation to perform.',
},
// ----------------------------------
// file
// ----------------------------------
@@ -419,7 +447,189 @@ export class Dropbox implements INodeType {
description: 'Name of the binary property which contains<br />the data for the file to be uploaded.',
},
// ----------------------------------
// search:query
// ----------------------------------
{
displayName: 'Query',
name: 'query',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
'query',
],
resource: [
'search',
],
},
},
description: ' The string to search for. May match across multiple fields based on the request arguments.',
},
{
displayName: 'File Status',
name: 'fileStatus',
type: 'options',
options: [
{
name: 'Active',
value: 'active',
},
{
name: 'Deleted',
value: 'deleted',
},
],
default: 'active',
displayOptions: {
show: {
operation: [
'query',
],
resource: [
'search',
],
},
},
description: ' The string to search for. May match across multiple fields based on the request arguments.',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
operation: [
'query',
],
resource: [
'search',
],
},
},
default: false,
description: 'If all results should be returned or only up to a given limit.',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: [
'search',
],
operation: [
'query',
],
returnAll: [
false,
],
},
},
default: 100,
description: 'How many results to return.',
},
{
displayName: 'Simple',
name: 'simple',
type: 'boolean',
displayOptions: {
show: {
operation: [
'query',
],
resource: [
'search',
],
},
},
default: true,
description: 'When set to true a simplify version of the response will be used else the raw data.',
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: [
'search',
],
operation: [
'query',
],
},
},
options: [
{
displayName: 'File Categories',
name: 'file_categories',
type: 'multiOptions',
options: [
{
name: 'Audio (mp3, wav, mid, etc.)',
value: 'audio',
},
{
name: 'Document (doc, docx, txt, etc.)',
value: 'document',
},
{
name: 'Folder',
value: 'folder',
},
{
name: 'Image (jpg, png, gif, etc.)',
value: 'image',
},
{
name: 'Other',
value: 'other',
},
{
name: 'Dropbox Paper',
value: 'paper',
},
{
name: 'PDF',
value: 'pdf',
},
{
name: 'Presentation (ppt, pptx, key, etc.)',
value: 'presentation',
},
{
name: 'Spreadsheet (xlsx, xls, csv, etc.)',
value: 'spreadsheet',
},
{
name: 'Video (avi, wmv, mp4, etc.)',
value: 'video',
},
],
default: [],
},
{
displayName: 'File Extensions',
name: 'file_extensions',
type: 'string',
default: '',
description: 'Multiple can be set separated by comma. Example: jpg,pdf',
},
{
displayName: 'Folder',
name: 'path',
type: 'string',
default: '',
description: 'If this field is not specified, this module searches the entire Dropbox',
},
],
},
// ----------------------------------
// folder
@@ -469,7 +679,97 @@ export class Dropbox implements INodeType {
placeholder: '/invoices/2019/',
description: 'The path of which to list the content.',
},
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
operation: [
'list',
],
resource: [
'folder',
],
},
},
default: false,
description: 'If all results should be returned or only up to a given limit.',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
resource: [
'folder',
],
operation: [
'list',
],
returnAll: [
false,
],
},
},
default: 100,
description: 'How many results to return.',
},
{
displayName: 'Filters',
name: 'filters',
type: 'collection',
placeholder: 'Add Filter',
default: {},
displayOptions: {
show: {
resource: [
'folder',
],
operation: [
'list',
],
},
},
options: [
{
displayName: 'Include Deleted',
name: 'include_deleted',
type: 'boolean',
default: false,
description: 'If true, the results will include entries for files and folders that used to exist but were deleted. The default for this field is False.',
},
{
displayName: 'Include Shared Members ',
name: 'include_has_explicit_shared_members',
type: 'boolean',
default: false,
description: 'If true, the results will include a flag for each file indicating whether or not that file has any explicit members. The default for this field is False.',
},
{
displayName: 'Include Mounted Folders ',
name: 'include_mounted_folders',
type: 'boolean',
default: true,
description: 'If true, the results will include entries under mounted folders which includes app folder, shared folder and team folder. The default for this field is True.',
},
{
displayName: 'Include Non Downloadable Files ',
name: 'include_non_downloadable_files',
type: 'boolean',
default: true,
description: 'If true, include files that are not downloadable, i.e. Google Docs. The default for this field is True.',
},
{
displayName: 'Recursive',
name: 'recursive',
type: 'boolean',
default: false,
description: 'If true, the list folder operation will be applied recursively to all subfolders and the response will contain contents of all subfolders. The default for this field is False.',
},
],
},
],
};
@@ -484,11 +784,24 @@ export class Dropbox implements INodeType {
let endpoint = '';
let requestMethod = '';
let returnAll = false;
let property = '';
let body: IDataObject | Buffer;
let options;
const query: IDataObject = {};
const headers: IDataObject = {};
let headers: IDataObject = {};
let simple = false;
// get the root directory to set it as the default search folder
const { root_info: { root_namespace_id } } = await getRootDirectory.call(this);
headers = {
'dropbox-api-path-root': JSON.stringify({
'.tag': 'root',
'root': root_namespace_id,
}),
};
for (let i = 0; i < items.length; i++) {
body = {};
@@ -545,7 +858,6 @@ export class Dropbox implements INodeType {
body = Buffer.from(this.getNodeParameter('fileContent', i) as string, 'utf8');
}
}
} else if (resource === 'folder') {
if (operation === 'create') {
// ----------------------------------
@@ -564,20 +876,65 @@ export class Dropbox implements INodeType {
// list
// ----------------------------------
returnAll = this.getNodeParameter('returnAll', 0) as boolean;
const filters = this.getNodeParameter('filters', i) as IDataObject;
property = 'entries';
requestMethod = 'POST';
body = {
path: this.getNodeParameter('path', i) as string,
limit: 2000,
limit: 1000,
};
// TODO: If more files than the max-amount exist it has to be possible to
// also request them.
if (returnAll === false) {
const limit = this.getNodeParameter('limit', 0) as number;
body.limit = limit;
}
Object.assign(body, filters);
endpoint = 'https://api.dropboxapi.com/2/files/list_folder';
}
} else if (resource === 'search') {
if (operation === 'query') {
// ----------------------------------
// query
// ----------------------------------
returnAll = this.getNodeParameter('returnAll', 0) as boolean;
simple = this.getNodeParameter('simple', 0) as boolean;
const filters = this.getNodeParameter('filters', i) as IDataObject;
property = 'matches';
requestMethod = 'POST';
body = {
query: this.getNodeParameter('query', i) as string,
options: {
filename_only: true,
},
};
if (filters.file_extensions) {
filters.file_extensions = (filters.file_extensions as string).split(',');
}
Object.assign(body.options, filters);
if (returnAll === false) {
const limit = this.getNodeParameter('limit', i) as number;
Object.assign(body.options, { max_results: limit });
}
endpoint = 'https://api.dropboxapi.com/2/files/search_v2';
}
}
if (['file', 'folder'].includes(resource)) {
if (['file', 'folder', 'search'].includes(resource)) {
if (operation === 'copy') {
// ----------------------------------
// copy
@@ -625,7 +982,13 @@ export class Dropbox implements INodeType {
options = { encoding: null };
}
let responseData = await dropboxApiRequest.call(this, requestMethod, endpoint, body, query, headers, options);
let responseData;
if (returnAll === true) {
responseData = await dropboxpiRequestAllItems.call(this, property, requestMethod, endpoint, body, query, headers);
} else {
responseData = await dropboxApiRequest.call(this, requestMethod, endpoint, body, query, headers, options);
}
if (resource === 'file' && operation === 'upload') {
responseData = JSON.parse(responseData);
@@ -665,7 +1028,11 @@ export class Dropbox implements INodeType {
'content_hash': 'contentHash',
};
for (const item of responseData.entries) {
if (returnAll === false) {
responseData = responseData.entries;
}
for (const item of responseData) {
const newItem: IDataObject = {};
// Get the props and save them under a proper name
@@ -677,8 +1044,14 @@ export class Dropbox implements INodeType {
returnData.push(newItem as IDataObject);
}
} else if (resource === 'search' && operation === 'query') {
if (returnAll === true) {
returnData.push.apply(returnData, (simple === true) ? simplify(responseData) : responseData);
} else {
returnData.push.apply(returnData, (simple === true) ? simplify(responseData[property]) : responseData[property]);
}
} else {
returnData.push(responseData as IDataObject);
returnData.push(responseData);
}
}