n8n/packages/nodes-base/nodes/Google/Drive/GoogleDrive.node.ts

2311 lines
54 KiB
TypeScript
Raw Normal View History

2019-10-27 13:44:21 -07:00
import {
BINARY_ENCODING,
IExecuteFunctions,
} from 'n8n-core';
2020-06-06 11:57:42 -07:00
2019-10-27 13:44:21 -07:00
import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
NodeOperationError,
2019-10-27 13:44:21 -07:00
} from 'n8n-workflow';
2020-06-06 11:57:42 -07:00
import {
googleApiRequest,
googleApiRequestAllItems,
2020-06-06 11:57:42 -07:00
} from './GenericFunctions';
2019-10-27 13:44:21 -07:00
import uuid = require('uuid');
2019-10-27 13:44:21 -07:00
export class GoogleDrive implements INodeType {
description: INodeTypeDescription = {
displayName: 'Google Drive',
name: 'googleDrive',
icon: 'file:googleDrive.svg',
2019-10-27 13:44:21 -07:00
group: ['input'],
version: 1,
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
description: 'Access data on Google Drive',
defaults: {
name: 'Google Drive',
color: '#4285F4',
2019-10-27 13:44:21 -07:00
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'googleApi',
required: true,
2020-06-06 11:57:42 -07:00
displayOptions: {
show: {
authentication: [
'serviceAccount',
],
},
},
},
{
name: 'googleDriveOAuth2Api',
required: true,
displayOptions: {
show: {
authentication: [
'oAuth2',
],
},
},
},
2019-10-27 13:44:21 -07:00
],
properties: [
2020-06-06 11:57:42 -07:00
{
displayName: 'Authentication',
name: 'authentication',
type: 'options',
options: [
{
name: 'Service Account',
value: 'serviceAccount',
},
{
name: 'OAuth2',
value: 'oAuth2',
},
],
default: 'serviceAccount',
},
2019-10-27 13:44:21 -07:00
{
displayName: 'Resource',
name: 'resource',
type: 'options',
options: [
{
name: 'Drive',
value: 'drive',
},
2019-10-27 13:44:21 -07:00
{
name: 'File',
value: 'file',
},
{
name: 'Folder',
value: 'folder',
},
],
default: 'file',
description: 'The resource to operate on.',
},
// ----------------------------------
// operations
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'file',
],
},
},
options: [
{
name: 'Copy',
value: 'copy',
description: 'Copy a file',
},
2019-10-27 13:44:21 -07:00
{
name: 'Delete',
value: 'delete',
description: 'Delete a file',
},
{
name: 'Download',
value: 'download',
description: 'Download a file',
},
{
name: 'List',
value: 'list',
description: 'List files and folders',
2019-10-27 13:44:21 -07:00
},
{
name: 'Share',
value: 'share',
description: 'Share a file',
},
{
name: 'Update',
value: 'update',
description: 'Update a file',
},
2019-10-27 13:44:21 -07:00
{
name: 'Upload',
value: 'upload',
description: 'Upload a file',
},
],
default: 'upload',
description: 'The operation to perform.',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'folder',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a folder',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a folder',
},
{
name: 'Share',
value: 'share',
description: 'Share a folder',
},
2019-10-27 13:44:21 -07:00
],
default: 'create',
description: 'The operation to perform.',
},
// ----------------------------------
// file
// ----------------------------------
// ----------------------------------
// file:copy
// ----------------------------------
{
displayName: 'ID',
name: 'fileId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'copy',
],
resource: [
'file',
],
},
},
description: 'The ID of the file to copy.',
},
2019-10-27 13:44:21 -07:00
// ----------------------------------
// file/folder:delete
// ----------------------------------
{
displayName: 'ID',
name: 'fileId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'delete',
2019-10-27 13:44:21 -07:00
],
resource: [
'file',
'folder',
],
},
},
description: 'The ID of the file/folder to delete.',
},
// ----------------------------------
// file:download
// ----------------------------------
{
displayName: 'File Id',
name: 'fileId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'download',
2019-10-27 13:44:21 -07:00
],
resource: [
'file',
],
},
},
description: 'The ID of the file to download.',
},
{
displayName: 'Binary Property',
name: 'binaryPropertyName',
type: 'string',
required: true,
default: 'data',
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'download',
2019-10-27 13:44:21 -07:00
],
resource: [
'file',
],
},
},
description: 'Name of the binary property to which to<br />write the data of the read file.',
},
// ----------------------------------
// file:list
// ----------------------------------
{
displayName: 'Use Query String',
name: 'useQueryString',
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'list',
2019-10-27 13:44:21 -07:00
],
resource: [
'file',
],
},
},
description: 'If a query string should be used to filter results.',
},
{
displayName: 'Query String',
name: 'queryString',
type: 'string',
default: '',
displayOptions: {
show: {
operation: [
'list',
],
useQueryString: [
true,
],
resource: [
'file',
],
},
},
placeholder: 'name contains \'invoice\'',
description: 'Query to use to return only specific files.',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
operation: [
'list',
],
resource: [
'file',
],
},
},
typeOptions: {
minValue: 1,
maxValue: 1000,
},
default: 100,
description: 'How many files to return.',
},
{
displayName: 'Filters',
name: 'queryFilters',
placeholder: 'Add Filter',
description: 'Filters to use to return only specific files.',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
displayOptions: {
show: {
operation: [
'list',
],
useQueryString: [
false,
],
resource: [
'file',
],
},
},
options: [
{
name: 'name',
displayName: 'Name',
values: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
options: [
{
name: 'Contains',
2020-10-22 06:46:03 -07:00
value: 'contains',
2019-10-27 13:44:21 -07:00
},
{
name: 'Is',
2020-10-22 06:46:03 -07:00
value: 'is',
2019-10-27 13:44:21 -07:00
},
{
name: 'Is Not',
2020-10-22 06:46:03 -07:00
value: 'isNot',
2019-10-27 13:44:21 -07:00
},
],
default: 'contains',
description: 'Operation to perform.',
},
{
displayName: 'Value',
name: 'value',
type: 'string',
default: '',
description: 'The value for operation.',
},
2020-10-22 06:46:03 -07:00
],
2019-10-27 13:44:21 -07:00
},
{
name: 'mimeType',
displayName: 'Mime Type',
values: [
{
displayName: 'Mime Type',
name: 'mimeType',
type: 'options',
options: [
{
name: 'Custom Mime Type',
value: 'custom',
},
{
name: ' 3rd party shortcut',
value: 'application/vnd.google-apps.drive-sdk',
},
{
name: 'Audio',
value: 'application/vnd.google-apps.audio',
},
{
name: 'Google Apps Scripts',
value: 'application/vnd.google-apps.script',
},
{
name: 'Google Docs',
value: 'application/vnd.google-apps.document',
},
{
name: 'Google Drawing',
value: 'application/vnd.google-apps.drawing',
},
{
name: 'Google Drive file',
value: 'application/vnd.google-apps.file',
},
{
name: 'Google Drive folder',
value: 'application/vnd.google-apps.folder',
},
{
name: 'Google Forms',
value: 'application/vnd.google-apps.form',
},
{
name: 'Google Fusion Tables',
value: 'application/vnd.google-apps.fusiontable',
},
{
name: 'Google My Maps',
value: 'application/vnd.google-apps.map',
},
{
name: 'Google Sheets',
value: 'application/vnd.google-apps.spreadsheet',
},
{
name: 'Google Sites',
value: 'application/vnd.google-apps.site',
},
{
name: 'Google Slides',
value: 'application/vnd.google-apps.presentation',
},
{
name: 'Photo',
value: 'application/vnd.google-apps.photo',
},
{
name: 'Unknown',
value: 'application/vnd.google-apps.unknown',
},
{
name: 'Video',
value: 'application/vnd.google-apps.video',
},
],
default: 'application/vnd.google-apps.file',
description: 'The Mime-Type of the files to return.',
},
{
displayName: 'Custom Mime Type',
name: 'customMimeType',
type: 'string',
default: '',
displayOptions: {
show: {
mimeType: [
'custom',
],
},
},
description: 'Custom Mime Type',
},
2020-10-22 06:46:03 -07:00
],
},
2019-10-27 13:44:21 -07:00
],
},
// ----------------------------------
// file:share
// ----------------------------------
{
displayName: 'File ID',
name: 'fileId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'share',
],
resource: [
'file',
'folder',
],
},
},
description: 'The ID of the file or shared drive.',
},
{
displayName: 'Permissions',
name: 'permissionsUi',
placeholder: 'Add Permission',
type: 'fixedCollection',
default: {},
typeOptions: {
multipleValues: false,
},
displayOptions: {
show: {
resource: [
'file',
'folder',
],
operation: [
'share',
],
},
},
options: [
{
displayName: 'Permission',
name: 'permissionsValues',
values: [
{
displayName: 'Role',
name: 'role',
type: 'options',
options: [
{
name: 'Owner',
value: 'owner',
},
{
name: 'Organizer',
value: 'organizer',
},
{
name: 'File Organizer',
value: 'fileOrganizer',
},
{
name: 'Writer',
value: 'writer',
},
{
name: 'Commenter',
value: 'commenter',
},
{
name: 'Reader',
value: 'reader',
},
],
default: '',
},
{
displayName: 'Type',
name: 'type',
type: 'options',
options: [
{
name: 'User',
value: 'user',
},
{
name: 'Group',
value: 'group',
},
{
name: 'Domain',
value: 'domain',
},
{
name: 'Anyone',
value: 'anyone',
},
],
default: '',
description: 'Information about the different types can be found <a href="https://developers.google.com/drive/api/v3/ref-roles" target="_blank">here</a>.',
},
{
displayName: 'Email Address',
name: 'emailAddress',
type: 'string',
displayOptions: {
show: {
type: [
'user',
'group',
],
},
},
default: '',
description: 'The email address of the user or group to which this permission refers',
},
{
displayName: 'Domain',
name: 'domain',
type: 'string',
displayOptions: {
show: {
type: [
'domain',
],
},
},
default: '',
description: 'The domain to which this permission refers',
},
{
displayName: 'Allow File Discovery',
name: 'allowFileDiscovery',
type: 'boolean',
displayOptions: {
show: {
type: [
'domain',
'anyone',
],
},
},
default: false,
description: 'Whether the permission allows the file to be discovered through search',
},
],
},
],
},
{
displayName: 'Binary Data',
name: 'binaryData',
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'upload',
],
resource: [
'file',
],
},
},
description: 'If the data to upload should be taken from binary field.',
},
{
displayName: 'File Content',
name: 'fileContent',
type: 'string',
default: '',
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'upload',
],
resource: [
'file',
],
binaryData: [
2020-10-22 06:46:03 -07:00
false,
],
},
},
placeholder: '',
description: 'The text content of the file to upload.',
},
{
displayName: 'Binary Property',
name: 'binaryPropertyName',
type: 'string',
default: 'data',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'upload',
],
resource: [
'file',
],
binaryData: [
2020-10-22 06:46:03 -07:00
true,
],
},
},
placeholder: '',
description: 'Name of the binary property which contains<br />the data for the file to be uploaded.',
},
// ----------------------------------
// file:update
// ----------------------------------
{
displayName: 'ID',
name: 'fileId',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'file',
],
},
},
description: 'The ID of the file to update.',
},
{
displayName: 'Update Fields',
name: 'updateFields',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'file',
],
},
},
options: [
{
displayName: 'Keep Revision Forever',
name: 'keepRevisionForever',
type: 'boolean',
default: false,
description: `Whether to set the 'keepForever' field in the new head revision.</br>
his is only applicable to files with binary content in Google Drive.</br>
Only 200 revisions for the file can be kept forever. If the limit is reached, try deleting pinned revisions.`,
},
{
displayName: 'OCR Language',
name: 'ocrLanguage',
type: 'string',
default: '',
description: `A language hint for OCR processing during image import (ISO 639-1 code).`,
},
{
displayName: 'Parent ID',
name: 'parentId',
type: 'string',
default: '',
description: `The ID of the parent to set.`,
},
{
displayName: 'Use Content As Indexable Text',
name: 'useContentAsIndexableText',
type: 'boolean',
default: false,
description: `Whether to use the uploaded content as indexable text.`,
},
],
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'file',
],
},
},
options: [
{
displayName: 'Fields',
name: 'fields',
type: 'multiOptions',
options: [
{
name: '*',
value: '*',
description: 'All fields.',
},
{
name: 'explicitlyTrashed',
value: 'explicitlyTrashed',
},
{
name: 'exportLinks',
value: 'exportLinks',
},
{
name: 'iconLink',
value: 'iconLink',
},
{
name: 'hasThumbnail',
value: 'hasThumbnail',
},
{
name: 'id',
value: 'id',
},
{
name: 'kind',
value: 'kind',
},
{
name: 'name',
value: 'name',
},
{
name: 'mimeType',
value: 'mimeType',
},
{
name: 'permissions',
value: 'permissions',
},
{
name: 'shared',
value: 'shared',
},
{
name: 'spaces',
value: 'spaces',
},
{
name: 'starred',
value: 'starred',
},
{
name: 'thumbnailLink',
value: 'thumbnailLink',
},
{
name: 'trashed',
value: 'trashed',
},
{
name: 'version',
value: 'version',
},
{
name: 'webViewLink',
value: 'webViewLink',
},
],
required: true,
default: [],
description: 'The fields to return.',
},
],
},
2019-10-27 13:44:21 -07:00
// ----------------------------------
// file:upload
// ----------------------------------
{
displayName: 'File Name',
name: 'name',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'upload',
2019-10-27 13:44:21 -07:00
],
resource: [
'file',
],
},
},
placeholder: 'invoice_1.pdf',
description: 'The name the file should be saved as.',
},
// ----------------------------------
{
displayName: 'Resolve Data',
name: 'resolveData',
type: 'boolean',
default: false,
displayOptions: {
show: {
operation: [
'upload',
],
resource: [
'file',
],
},
},
description: 'By default the response only contain the ID of the file.<br />If this option gets activated it will resolve the data automatically.',
},
2019-10-27 13:44:21 -07:00
{
displayName: 'Parents',
name: 'parents',
type: 'string',
typeOptions: {
multipleValues: true,
},
default: [],
displayOptions: {
show: {
operation: [
'upload',
],
resource: [
'file',
],
},
},
description: 'The IDs of the parent folders which contain the file.',
},
// ----------------------------------
// folder
// ----------------------------------
// ----------------------------------
// folder:create
// ----------------------------------
{
displayName: 'Folder',
name: 'name',
type: 'string',
default: '',
required: true,
displayOptions: {
show: {
operation: [
2020-10-22 06:46:03 -07:00
'create',
2019-10-27 13:44:21 -07:00
],
resource: [
'folder',
],
},
},
placeholder: 'invoices',
description: 'The name of folder to create.',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
'/operation': [
'copy',
'list',
'share',
'create',
],
'/resource': [
'file',
'folder',
],
},
},
2019-10-27 13:44:21 -07:00
options: [
{
displayName: 'Email Message',
name: 'emailMessage',
type: 'string',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: '',
description: 'A plain text custom message to include in the notification email.',
},
{
displayName: 'Enforce Single Parent',
name: 'enforceSingleParent',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: false,
description: `Set to true to opt in to API behavior that aims for all items to have exactly one parent<br>
This parameter only takes effect if the item is not in a shared drive`,
},
2019-10-27 13:44:21 -07:00
{
displayName: 'Fields',
name: 'fields',
type: 'multiOptions',
displayOptions: {
show: {
'/operation': [
'list',
'copy',
],
},
},
2019-10-27 13:44:21 -07:00
options: [
{
name: '*',
value: '*',
description: 'All fields.',
},
{
name: 'explicitlyTrashed',
value: 'explicitlyTrashed',
},
{
name: 'exportLinks',
value: 'exportLinks',
},
{
name: 'iconLink',
value: 'iconLink',
},
{
name: 'hasThumbnail',
value: 'hasThumbnail',
},
{
name: 'id',
value: 'id',
},
{
name: 'kind',
value: 'kind',
},
{
name: 'name',
value: 'name',
},
{
name: 'mimeType',
value: 'mimeType',
},
{
name: 'permissions',
value: 'permissions',
},
{
name: 'shared',
value: 'shared',
},
{
name: 'spaces',
value: 'spaces',
},
{
name: 'starred',
value: 'starred',
},
{
name: 'thumbnailLink',
value: 'thumbnailLink',
},
{
name: 'trashed',
value: 'trashed',
},
{
name: 'version',
value: 'version',
},
{
name: 'webViewLink',
value: 'webViewLink',
},
],
required: true,
default: [],
description: 'The fields to return.',
},
{
displayName: 'Move To New Owners Root',
name: 'moveToNewOwnersRoot',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: '',
description: `This parameter only takes effect if the item is not in a shared drive and the request is attempting to transfer the ownership of the item.<br>
When set to true, the item is moved to the new owner's My Drive root folder and all prior parents removed`,
},
{
displayName: 'Send Notification Email',
name: 'sendNotificationEmail',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: false,
description: 'Whether to send a notification email when sharing to users or groups',
},
{
displayName: 'Supports All Drives',
name: 'supportsAllDrives',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: false,
description: 'Whether the requesting application supports both My Drives and shared drives',
},
{
displayName: 'Transfer Ownership',
name: 'transferOwnership',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: false,
description: 'Whether to transfer ownership to the specified user and downgrade the current owner to a writer.',
},
{
displayName: 'Use Domain Admin Access',
name: 'useDomainAdminAccess',
type: 'boolean',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'share',
],
'/resource': [
'file',
'folder',
],
},
},
default: false,
description: `Perform the operation as domain administrator, i.e. if you are an administrator of the domain to which the shared drive belongs, you will be granted access automatically`,
},
{
displayName: 'File Name',
name: 'name',
type: 'string',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'copy',
],
'/resource': [
'file',
],
},
},
default: '',
placeholder: 'invoice_1.pdf',
description: 'The name the file should be saved as.',
},
{
displayName: 'Parents',
name: 'parents',
type: 'string',
displayOptions: {
show: {
'/operation': [
'copy',
'create',
],
'/resource': [
'file',
'folder',
],
},
},
typeOptions: {
multipleValues: true,
},
default: [],
description: 'The IDs of the parent folders the file/folder should be saved in.',
},
2019-10-27 13:44:21 -07:00
{
displayName: 'Spaces',
name: 'spaces',
type: 'multiOptions',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'list',
2019-10-27 13:44:21 -07:00
],
'/resource': [
'file',
],
},
},
options: [
{
name: '*',
value: '*',
description: 'All spaces.',
},
{
name: 'appDataFolder',
value: 'appDataFolder',
},
{
name: 'drive',
value: 'drive',
},
{
name: 'photos',
value: 'photos',
},
],
required: true,
default: [],
description: 'The spaces to operate on.',
},
{
displayName: 'Corpora',
name: 'corpora',
type: 'options',
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'list',
],
'/resource': [
'file',
],
},
},
options: [
{
name: 'user',
value: 'user',
description: 'All files in "My Drive" and "Shared with me"',
},
{
name: 'domain',
value: 'domain',
2020-06-13 04:47:49 -07:00
description: 'All files shared to the user\'s domain that are searchable',
},
{
name: 'drive',
value: 'drive',
description: 'All files contained in a single shared drive',
},
{
name: 'allDrives',
value: 'allDrives',
description: 'All drives',
},
],
required: true,
2020-01-04 20:19:10 -08:00
default: '',
description: 'The corpora to operate on.',
},
{
displayName: 'Drive ID',
name: 'driveId',
type: 'string',
default: '',
required: false,
displayOptions: {
show: {
'/operation': [
2020-10-22 06:46:03 -07:00
'list',
],
'/resource': [
'file',
],
corpora: [
2020-10-22 06:46:03 -07:00
'drive',
],
},
},
description: 'ID of the shared drive to search. The driveId parameter must be specified if and only if corpora is set to drive.',
},
2019-10-27 13:44:21 -07:00
],
},
// ----------------------------------
// drive
// ----------------------------------
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'drive',
],
},
},
options: [
{
name: 'Create',
value: 'create',
description: 'Create a drive',
},
{
name: 'Delete',
value: 'delete',
description: 'Delete a drive',
},
{
name: 'Get',
value: 'get',
description: 'Get a drive',
},
{
name: 'List',
value: 'list',
description: 'List all drives',
},
{
name: 'Update',
value: 'update',
description: 'Update a drive',
},
],
default: 'create',
description: 'The operation to perform.',
},
// ----------------------------------
// drive:create
// ----------------------------------
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
required: false,
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'drive',
],
},
},
description: 'The name of this shared drive.',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'create',
],
resource: [
'drive',
],
},
},
options: [
{
displayName: 'Capabilities',
name: 'capabilities',
type: 'collection',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Can Add Children',
name: 'canAddChildren',
type: 'boolean',
default: false,
description: `Whether the current user can add children to folders in this shared drive.`,
},
{
displayName: 'Can Change Copy Requires Writer Permission Restriction',
name: 'canChangeCopyRequiresWriterPermissionRestriction',
type: 'boolean',
default: false,
description: `Whether the current user can change the copyRequiresWriterPermission restriction of this shared drive.`,
},
{
displayName: 'Can Change Domain Users Only Restriction',
name: 'canChangeDomainUsersOnlyRestriction',
type: 'boolean',
default: false,
description: `Whether the current user can change the domainUsersOnly restriction of this shared drive.`,
},
{
displayName: 'Can Change Drive Background',
name: 'canChangeDriveBackground',
type: 'boolean',
default: false,
description: `Whether the current user can change the background of this shared drive.`,
},
{
displayName: 'Can Change Drive Members Only Restriction',
name: 'canChangeDriveMembersOnlyRestriction',
type: 'boolean',
default: false,
description: `Whether the current user can change the driveMembersOnly restriction of this shared drive.`,
},
{
displayName: 'Can Comment',
name: 'canComment',
type: 'boolean',
default: false,
description: `Whether the current user can comment on files in this shared drive.`,
},
{
displayName: 'Can Copy',
name: 'canCopy',
type: 'boolean',
default: false,
description: `Whether the current user can copy files in this shared drive.`,
},
{
displayName: 'Can Delete Children',
name: 'canDeleteChildren',
type: 'boolean',
default: false,
description: `Whether the current user can delete children from folders in this shared drive.`,
},
{
displayName: 'Can Delete Drive',
name: 'canDeleteDrive',
type: 'boolean',
default: false,
description: `Whether the current user can delete this shared drive. Attempting to delete the shared drive may still fail if there are untrashed items inside the shared drive.`,
},
{
displayName: 'Can Download',
name: 'canDownload',
type: 'boolean',
default: false,
description: `Whether the current user can download files in this shared drive.`,
},
{
displayName: 'Can Edit',
name: 'canEdit',
type: 'boolean',
default: false,
description: `Whether the current user can edit files in this shared drive`,
},
{
displayName: 'Can List Children',
name: 'canListChildren',
type: 'boolean',
default: false,
description: `Whether the current user can list the children of folders in this shared drive.`,
},
{
displayName: 'Can Manage Members',
name: 'canManageMembers',
type: 'boolean',
default: false,
description: `Whether the current user can add members to this shared drive or remove them or change their role.`,
},
{
displayName: 'Can Read Revisions',
name: 'canReadRevisions',
type: 'boolean',
default: false,
description: `Whether the current user can read the revisions resource of files in this shared drive.`,
},
{
displayName: 'Can Rename',
name: 'canRename',
type: 'boolean',
default: false,
description: `Whether the current user can rename files or folders in this shared drive.`,
},
{
displayName: 'Can Rename Drive',
name: 'canRenameDrive',
type: 'boolean',
default: false,
description: `Whether the current user can rename this shared drive.`,
},
{
displayName: 'Can Share',
name: 'canShare',
type: 'boolean',
default: false,
description: `Whether the current user can rename this shared drive.`,
},
{
displayName: 'Can Trash Children',
name: 'canTrashChildren',
type: 'boolean',
default: false,
description: `Whether the current user can trash children from folders in this shared drive.`,
},
],
},
{
displayName: 'Color RGB',
name: 'colorRgb',
type: 'color',
default: '',
description: 'The color of this shared drive as an RGB hex string',
},
{
displayName: 'Created Time',
name: 'createdTime',
type: 'dateTime',
default: '',
description: 'The time at which the shared drive was created (RFC 3339 date-time).',
},
{
displayName: 'Hidden',
name: 'hidden',
type: 'boolean',
default: false,
description: 'Whether the shared drive is hidden from default view.',
},
{
displayName: 'Restrictions',
name: 'restrictions',
type: 'collection',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Admin Managed Restrictions',
name: 'adminManagedRestrictions',
type: 'boolean',
default: false,
description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
override the similarly named field to true for any file inside this shared drive.`,
},
{
displayName: 'Copy Requires Writer Permission',
name: 'copyRequiresWriterPermission',
type: 'boolean',
default: false,
description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
override the similarly named field to true for any file inside this shared drive.`,
},
{
displayName: 'Domain Users Only',
name: 'domainUsersOnly',
type: 'boolean',
default: false,
description: `Whether access to this shared drive and items inside this shared drive<br/>
is restricted to users of the domain to which this shared drive belongs. This restriction<br/>
may be overridden by other sharing policies controlled outside of this shared drive.`,
},
{
displayName: 'Drive Members Only',
name: 'driveMembersOnly',
type: 'boolean',
default: false,
description: `Whether access to items inside this shared drive is restricted to its members.`,
},
],
},
],
},
// ----------------------------------
// drive:delete
// ----------------------------------
{
displayName: 'Drive ID',
name: 'driveId',
type: 'string',
default: '',
required: false,
displayOptions: {
show: {
operation: [
'delete',
],
resource: [
'drive',
],
},
},
description: 'The ID of the shared drive.',
},
// ----------------------------------
// drive:get
// ----------------------------------
{
displayName: 'Drive ID',
name: 'driveId',
type: 'string',
default: '',
required: false,
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'drive',
],
},
},
description: 'The ID of the shared drive.',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'get',
],
resource: [
'drive',
],
},
},
options: [
{
displayName: 'Use Domain Admin Access',
name: 'useDomainAdminAccess',
type: 'boolean',
default: false,
description: 'Issue the request as a domain administrator; if set to true, then the requester will be granted access if they are an administrator of the domain to which the shared drive belongs. (Default: false)',
},
],
},
// ----------------------------------
// drive:list
// ----------------------------------
{
displayName: 'Return All',
name: 'returnAll',
type: 'boolean',
displayOptions: {
show: {
operation: [
'list',
],
resource: [
'drive',
],
},
},
default: false,
description: 'If all results should be returned or only up to a given limit.',
},
{
displayName: 'Limit',
name: 'limit',
type: 'number',
displayOptions: {
show: {
operation: [
'list',
],
resource: [
'drive',
],
returnAll: [
false,
],
},
},
typeOptions: {
minValue: 1,
maxValue: 200,
},
default: 100,
description: 'How many results to return.',
},
{
displayName: 'Options',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'list',
],
resource: [
'drive',
],
},
},
options: [
{
displayName: 'Query',
name: 'q',
type: 'string',
default: '',
description: 'Query string for searching shared drives. See the <a href="https://developers.google.com/drive/api/v3/search-shareddrives" target="_blank">"Search for shared drives"</a> guide for supported syntax.',
},
{
displayName: 'Use Domain Admin Access',
name: 'useDomainAdminAccess',
type: 'boolean',
default: false,
description: 'Issue the request as a domain administrator; if set to true, then the requester will be granted access if they are an administrator of the domain to which the shared drive belongs. (Default: false)',
},
],
},
// ----------------------------------
// drive:update
// ----------------------------------
{
displayName: 'Drive ID',
name: 'driveId',
type: 'string',
default: '',
required: false,
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'drive',
],
},
},
description: 'The ID of the shared drive.',
},
{
displayName: 'Update Fields',
name: 'options',
type: 'collection',
placeholder: 'Add Option',
default: {},
displayOptions: {
show: {
operation: [
'update',
],
resource: [
'drive',
],
},
},
options: [
{
displayName: 'Color RGB',
name: 'colorRgb',
type: 'color',
default: '',
description: 'The color of this shared drive as an RGB hex string',
},
{
displayName: 'Name',
name: 'name',
type: 'string',
default: '',
description: 'The name of this shared drive.',
},
{
displayName: 'Restrictions',
name: 'restrictions',
type: 'collection',
placeholder: 'Add Field',
default: {},
options: [
{
displayName: 'Admin Managed Restrictions',
name: 'adminManagedRestrictions',
type: 'boolean',
default: false,
description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
override the similarly named field to true for any file inside this shared drive.`,
},
{
displayName: 'Copy Requires Writer Permission',
name: 'copyRequiresWriterPermission',
type: 'boolean',
default: false,
description: `Whether the options to copy, print, or download files inside this shared drive,<br/>
should be disabled for readers and commenters. When this restriction is set to true, it will<br/>
override the similarly named field to true for any file inside this shared drive.`,
},
{
displayName: 'Domain Users Only',
name: 'domainUsersOnly',
type: 'boolean',
default: false,
description: `Whether access to this shared drive and items inside this shared drive<br/>
is restricted to users of the domain to which this shared drive belongs. This restriction<br/>
may be overridden by other sharing policies controlled outside of this shared drive.`,
},
{
displayName: 'Drive Members Only',
name: 'driveMembersOnly',
type: 'boolean',
default: false,
description: `Whether access to items inside this shared drive is restricted to its members.`,
},
],
},
],
},
2019-10-27 13:44:21 -07:00
],
};
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const items = this.getInputData();
const returnData: IDataObject[] = [];
const resource = this.getNodeParameter('resource', 0) as string;
const operation = this.getNodeParameter('operation', 0) as string;
for (let i = 0; i < items.length; i++) {
const options = this.getNodeParameter('options', i, {}) as IDataObject;
2019-10-27 13:44:21 -07:00
let queryFields = 'id, name';
if (options && options.fields) {
const fields = options.fields as string[];
if (fields.includes('*')) {
queryFields = '*';
} else {
queryFields = fields.join(', ');
}
}
if (resource === 'drive') {
if (operation === 'create') {
// ----------------------------------
// create
// ----------------------------------
const name = this.getNodeParameter('name', i) as string;
const body: IDataObject = {
name,
};
Object.assign(body, options);
const response = await googleApiRequest.call(this, 'POST', `/drive/v3/drives`, body, { requestId: uuid() });
returnData.push(response as IDataObject);
}
if (operation === 'delete') {
// ----------------------------------
// delete
// ----------------------------------
const driveId = this.getNodeParameter('driveId', i) as string;
await googleApiRequest.call(this, 'DELETE', `/drive/v3/drives/${driveId}`);
returnData.push({ success: true });
}
if (operation === 'get') {
// ----------------------------------
// get
// ----------------------------------
const driveId = this.getNodeParameter('driveId', i) as string;
const qs: IDataObject = {};
Object.assign(qs, options);
const response = await googleApiRequest.call(this, 'GET', `/drive/v3/drives/${driveId}`, {}, qs);
returnData.push(response as IDataObject);
}
if (operation === 'list') {
// ----------------------------------
// list
// ----------------------------------
const returnAll = this.getNodeParameter('returnAll', i) as boolean;
const qs: IDataObject = {};
let response: IDataObject[] = [];
Object.assign(qs, options);
if (returnAll === true) {
response = await googleApiRequestAllItems.call(this, 'drives', 'GET', `/drive/v3/drives`, {}, qs);
} else {
qs.pageSize = this.getNodeParameter('limit', i) as number;
const data = await googleApiRequest.call(this, 'GET', `/drive/v3/drives`, {}, qs);
response = data.drives as IDataObject[];
}
returnData.push.apply(returnData, response);
}
if (operation === 'update') {
// ----------------------------------
// update
// ----------------------------------
const driveId = this.getNodeParameter('driveId', i) as string;
const body: IDataObject = {};
Object.assign(body, options);
const response = await googleApiRequest.call(this, 'PATCH', `/drive/v3/drives/${driveId}`, body);
returnData.push(response as IDataObject);
}
} else if (resource === 'file') {
if (operation === 'copy') {
// ----------------------------------
// copy
// ----------------------------------
const fileId = this.getNodeParameter('fileId', i) as string;
2020-06-06 11:57:42 -07:00
const body: IDataObject = {
fields: queryFields,
};
const optionProperties = ['name', 'parents'];
for (const propertyName of optionProperties) {
if (options[propertyName] !== undefined) {
2020-06-06 11:57:42 -07:00
body[propertyName] = options[propertyName];
}
}
const qs = {
2021-04-02 09:18:43 -07:00
supportsAllDrives: true,
};
const response = await googleApiRequest.call(this, 'POST', `/drive/v3/files/${fileId}/copy`, body, qs);
2020-06-06 11:57:42 -07:00
returnData.push(response as IDataObject);
} else if (operation === 'download') {
2019-10-27 13:44:21 -07:00
// ----------------------------------
// download
// ----------------------------------
const fileId = this.getNodeParameter('fileId', i) as string;
2020-06-06 11:57:42 -07:00
const requestOptions = {
resolveWithFullResponse: true,
encoding: null,
json: false,
};
const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files/${fileId}`, {}, { alt: 'media' }, undefined, requestOptions);
2019-10-27 13:44:21 -07:00
let mimeType: string | undefined;
if (response.headers['content-type']) {
mimeType = response.headers['content-type'];
}
const newItem: INodeExecutionData = {
json: items[i].json,
binary: {},
};
if (items[i].binary !== undefined) {
// Create a shallow copy of the binary data so that the old
// data references which do not get changed still stay behind
// but the incoming data does not get changed.
Object.assign(newItem.binary, items[i].binary);
}
items[i] = newItem;
const dataPropertyNameDownload = this.getNodeParameter('binaryPropertyName', i) as string;
2020-06-06 11:57:42 -07:00
const data = Buffer.from(response.body as string);
2019-10-27 13:44:21 -07:00
items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(data as unknown as Buffer, undefined, mimeType);
} else if (operation === 'list') {
// ----------------------------------
// list
// ----------------------------------
let querySpaces = '';
if (options.spaces) {
const spaces = options.spaces as string[];
if (spaces.includes('*')) {
querySpaces = 'appDataFolder, drive, photos';
} else {
querySpaces = spaces.join(', ');
}
}
let queryCorpora = '';
if (options.corpora) {
queryCorpora = options.corpora as string;
}
2020-06-13 04:47:49 -07:00
let driveId: string | undefined;
driveId = options.driveId as string;
if (driveId === '') {
driveId = undefined;
}
2019-10-27 13:44:21 -07:00
let queryString = '';
const useQueryString = this.getNodeParameter('useQueryString', i) as boolean;
if (useQueryString === true) {
// Use the user defined query string
queryString = this.getNodeParameter('queryString', i) as string;
} else {
// Build query string out of parameters set by user
const queryFilters = this.getNodeParameter('queryFilters', i) as IDataObject;
const queryFilterFields: string[] = [];
if (queryFilters.name) {
(queryFilters.name as IDataObject[]).forEach(nameFilter => {
let operation = nameFilter.operation;
if (operation === 'is') {
operation = '=';
} else if (operation === 'isNot') {
operation = '!=';
}
queryFilterFields.push(`name ${operation} '${nameFilter.value}'`);
});
queryString += queryFilterFields.join(' or ');
}
queryFilterFields.length = 0;
if (queryFilters.mimeType) {
(queryFilters.mimeType as IDataObject[]).forEach(mimeTypeFilter => {
let mimeType = mimeTypeFilter.mimeType;
if (mimeTypeFilter.mimeType === 'custom') {
mimeType = mimeTypeFilter.customMimeType;
}
queryFilterFields.push(`mimeType = '${mimeType}'`);
});
if (queryFilterFields.length) {
if (queryString !== '') {
queryString += ' and ';
}
queryString += queryFilterFields.join(' or ');
}
}
}
const pageSize = this.getNodeParameter('limit', i) as number;
2020-06-06 11:57:42 -07:00
const qs = {
2019-10-27 13:44:21 -07:00
pageSize,
orderBy: 'modifiedTime',
fields: `nextPageToken, files(${queryFields})`,
spaces: querySpaces,
q: queryString,
2020-06-06 11:57:42 -07:00
includeItemsFromAllDrives: (queryCorpora !== '' || driveId !== ''),
supportsAllDrives: (queryCorpora !== '' || driveId !== ''),
};
const response = await googleApiRequest.call(this, 'GET', `/drive/v3/files`, {}, qs);
2019-10-27 13:44:21 -07:00
2020-06-06 11:57:42 -07:00
const files = response!.files;
2019-10-27 13:44:21 -07:00
return [this.helpers.returnJsonArray(files as IDataObject[])];
} else if (operation === 'upload') {
// ----------------------------------
// upload
// ----------------------------------
const resolveData = this.getNodeParameter('resolveData', 0) as boolean;
2019-10-27 13:44:21 -07:00
let mimeType = 'text/plain';
let body;
let originalFilename: string | undefined;
if (this.getNodeParameter('binaryData', i) === true) {
// Is binary file to upload
const item = items[i];
if (item.binary === undefined) {
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
throw new NodeOperationError(this.getNode(), 'No binary data exists on item!');
2019-10-27 13:44:21 -07:00
}
const propertyNameUpload = this.getNodeParameter('binaryPropertyName', i) as string;
if (item.binary[propertyNameUpload] === undefined) {
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
throw new NodeOperationError(this.getNode(), `No binary data property "${propertyNameUpload}" does not exists on item!`);
2019-10-27 13:44:21 -07:00
}
if (item.binary[propertyNameUpload].mimeType) {
mimeType = item.binary[propertyNameUpload].mimeType;
}
if (item.binary[propertyNameUpload].fileName) {
originalFilename = item.binary[propertyNameUpload].fileName;
}
body = Buffer.from(item.binary[propertyNameUpload].data, BINARY_ENCODING);
} else {
// Is text file
body = Buffer.from(this.getNodeParameter('fileContent', i) as string, 'utf8');
}
const name = this.getNodeParameter('name', i) as string;
const parents = this.getNodeParameter('parents', i) as string[];
2020-06-06 11:57:42 -07:00
let qs: IDataObject = {
2019-10-27 13:44:21 -07:00
fields: queryFields,
2020-06-06 11:57:42 -07:00
uploadType: 'media',
};
const requestOptions = {
headers: {
'Content-Type': mimeType,
'Content-Length': body.byteLength,
2019-10-27 13:44:21 -07:00
},
2020-06-06 11:57:42 -07:00
encoding: null,
json: false,
};
let response = await googleApiRequest.call(this, 'POST', `/upload/drive/v3/files`, body, qs, undefined, requestOptions);
body = {
mimeType,
name,
originalFilename,
};
qs = {
addParents: parents.join(','),
// When set to true shared drives can be used.
supportsAllDrives: true,
2020-06-06 11:57:42 -07:00
};
response = await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${JSON.parse(response).id}`, body, qs);
2019-10-27 13:44:21 -07:00
if (resolveData === true) {
response = await googleApiRequest.call(this, 'GET', `/drive/v3/files/${response.id}`, {}, { fields: '*' });
}
2020-06-06 11:57:42 -07:00
returnData.push(response as IDataObject);
} else if (operation === 'update') {
// ----------------------------------
// file:update
// ----------------------------------
const id = this.getNodeParameter('fileId', i) as string;
const updateFields = this.getNodeParameter('updateFields', i, {}) as IDataObject;
const qs: IDataObject = {
supportsAllDrives: true,
};
Object.assign(qs, options);
qs.fields = queryFields;
2021-03-12 02:51:35 -08:00
if (updateFields.parentId && updateFields.parentId !== '') {
qs.addParents = updateFields.parentId;
}
const responseData = await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${id}`, {}, qs);
returnData.push(responseData as IDataObject);
2019-10-27 13:44:21 -07:00
}
} else if (resource === 'folder') {
if (operation === 'create') {
// ----------------------------------
// folder:create
// ----------------------------------
const name = this.getNodeParameter('name', i) as string;
2020-06-06 11:57:42 -07:00
const body = {
2019-10-27 13:44:21 -07:00
name,
mimeType: 'application/vnd.google-apps.folder',
parents: options.parents || [],
2019-10-27 13:44:21 -07:00
};
2020-06-06 11:57:42 -07:00
const qs = {
2019-10-27 13:44:21 -07:00
fields: queryFields,
supportsAllDrives: true,
2020-06-06 11:57:42 -07:00
};
2019-10-27 13:44:21 -07:00
2020-06-06 11:57:42 -07:00
const response = await googleApiRequest.call(this, 'POST', '/drive/v3/files', body, qs);
returnData.push(response as IDataObject);
2019-10-27 13:44:21 -07:00
}
}
if (['file', 'folder'].includes(resource)) {
2019-10-27 13:44:21 -07:00
if (operation === 'delete') {
// ----------------------------------
// delete
// ----------------------------------
const fileId = this.getNodeParameter('fileId', i) as string;
2020-06-06 11:57:42 -07:00
const response = await googleApiRequest.call(this, 'DELETE', `/drive/v3/files/${fileId}`);
2019-10-27 13:44:21 -07:00
// If we are still here it did succeed
returnData.push({
fileId,
success: true,
});
}
if (operation === 'share') {
const fileId = this.getNodeParameter('fileId', i) as string;
const permissions = this.getNodeParameter('permissionsUi', i) as IDataObject;
const options = this.getNodeParameter('options', i) as IDataObject;
const body: IDataObject = {};
const qs: IDataObject = {};
if (permissions.permissionsValues) {
Object.assign(body, permissions.permissionsValues);
}
Object.assign(qs, options);
const response = await googleApiRequest.call(this, 'POST', `/drive/v3/files/${fileId}/permissions`, body, qs);
returnData.push(response as IDataObject);
}
2019-10-27 13:44:21 -07:00
} else {
:sparkles: Improve node error handling (#1309) * Add path mapping and response error interfaces * Add error handling and throwing functionality * Refactor error handling into a single function * Re-implement error handling in Hacker News node * Fix linting details * Re-implement error handling in Spotify node * Re-implement error handling in G Suite Admin node * :construction: create basic setup NodeError * :construction: add httpCodes * :construction: add path priolist * :construction: handle statusCode in error, adjust interfaces * :construction: fixing type issues w/Ivan * :construction: add error exploration * 👔 fix linter issues * :wrench: improve object check * :construction: remove path passing from NodeApiError * :construction: add multi error + refactor findProperty method * 👔 allow any * :wrench: handle multi error message callback * :zap: change return type of callback * :zap: add customCallback to MultiError * :construction: refactor to use INode * :hammer: handle arrays, continue search after first null property found * 🚫 refactor method access * :construction: setup NodeErrorView * :zap: change timestamp to Date.now * :books: Add documentation for methods and constants * :construction: change message setting * 🚚 move NodeErrors to workflow * :sparkles: add new ErrorView for Nodes * :art: improve error notification * :art: refactor interfaces * :zap: add WorkflowOperationError, refactor error throwing * 👕 fix linter issues * :art: rename param * :bug: fix handling normal errors * :zap: add usage of NodeApiError * :art: fix throw new error instead of constructor * :art: remove unnecessary code/comments * :art: adjusted spacing + updated status messages * :art: fix tab indentation * ✨ Replace current errors with custom errors (#1576) * :zap: Introduce NodeApiError in catch blocks * :zap: Introduce NodeOperationError in nodes * :zap: Add missing errors and remove incompatible * :zap: Fix NodeOperationError in incompatible nodes * :wrench: Adjust error handling in missed nodes PayPal, FileMaker, Reddit, Taiga and Facebook Graph API nodes * :hammer: Adjust Strava Trigger node error handling * :hammer: Adjust AWS nodes error handling * :hammer: Remove duplicate instantiation of NodeApiError * :bug: fix strava trigger node error handling * Add XML parsing to NodeApiError constructor (#1633) * :bug: Remove type annotation from catch variable * :sparkles: Add XML parsing to NodeApiError * :zap: Simplify error handling in Rekognition node * :zap: Pass in XML flag in generic functions * :fire: Remove try/catch wrappers at call sites * :hammer: Refactor setting description from XML * :hammer: Refactor let to const in resource loaders * :zap: Find property in parsed XML * :zap: Change let to const * :fire: Remove unneeded try/catch block * :shirt: Fix linting issues * :bug: Fix errors from merge conflict resolution * :zap: Add custom errors to latest contributions * :shirt: Fix linting issues * :zap: Refactor MongoDB helpers for custom errors * :bug: Correct custom error type * :zap: Apply feedback to A nodes * :zap: Apply feedback to missed A node * :zap: Apply feedback to B-D nodes * :zap: Apply feedback to E-F nodes * :zap: Apply feedback to G nodes * :zap: Apply feedback to H-L nodes * :zap: Apply feedback to M nodes * :zap: Apply feedback to P nodes * :zap: Apply feedback to R nodes * :zap: Apply feedback to S nodes * :zap: Apply feedback to T nodes * :zap: Apply feedback to V-Z nodes * :zap: Add HTTP code to iterable node error * :hammer: Standardize e as error * :hammer: Standardize err as error * :zap: Fix error handling for non-standard nodes Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com> Co-authored-by: Ben Hesseldieck <1849459+BHesseldieck@users.noreply.github.com>
2021-04-16 09:33:36 -07:00
throw new NodeOperationError(this.getNode(), `The resource "${resource}" is not known!`);
2019-10-27 13:44:21 -07:00
}
}
if (resource === 'file' && operation === 'download') {
// For file downloads the files get attached to the existing items
return this.prepareOutputData(items);
} else {
// For all other ones does the output items get replaced
return [this.helpers.returnJsonArray(returnData)];
}
}
}