first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import * as copy from './copy.operation';
|
||||
import * as createFromText from './createFromText.operation';
|
||||
import * as deleteFile from './deleteFile.operation';
|
||||
import * as download from './download.operation';
|
||||
import * as move from './move.operation';
|
||||
import * as share from './share.operation';
|
||||
import * as update from './update.operation';
|
||||
import * as upload from './upload.operation';
|
||||
|
||||
export { copy, createFromText, deleteFile, download, move, share, update, upload };
|
||||
|
||||
export const description: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
{
|
||||
name: 'Copy',
|
||||
value: 'copy',
|
||||
description: 'Create a copy of an existing file',
|
||||
action: 'Copy file',
|
||||
},
|
||||
{
|
||||
name: 'Create From Text',
|
||||
value: 'createFromText',
|
||||
description: 'Create a file from a provided text',
|
||||
action: 'Create file from text',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'deleteFile',
|
||||
description: 'Permanently delete a file',
|
||||
action: 'Delete a file',
|
||||
},
|
||||
{
|
||||
name: 'Download',
|
||||
value: 'download',
|
||||
description: 'Download a file',
|
||||
action: 'Download file',
|
||||
},
|
||||
{
|
||||
name: 'Move',
|
||||
value: 'move',
|
||||
description: 'Move a file to another folder',
|
||||
action: 'Move file',
|
||||
},
|
||||
{
|
||||
name: 'Share',
|
||||
value: 'share',
|
||||
description: 'Add sharing permissions to a file',
|
||||
action: 'Share file',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
description: 'Update a file',
|
||||
action: 'Update file',
|
||||
},
|
||||
{
|
||||
name: 'Upload',
|
||||
value: 'upload',
|
||||
description: 'Upload an existing file to Google Drive',
|
||||
action: 'Upload file',
|
||||
},
|
||||
],
|
||||
default: 'upload',
|
||||
},
|
||||
...copy.description,
|
||||
...deleteFile.description,
|
||||
...createFromText.description,
|
||||
...download.description,
|
||||
...move.description,
|
||||
...share.description,
|
||||
...update.description,
|
||||
...upload.description,
|
||||
];
|
||||
@@ -0,0 +1,137 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeParameterResourceLocator,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { setParentFolder } from '../../helpers/utils';
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { driveRLC, fileRLC, folderRLC } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
description: 'The file to copy',
|
||||
},
|
||||
{
|
||||
displayName: 'File Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. My File',
|
||||
description:
|
||||
'The name of the new file. If not set, “Copy of {original file name}” will be used.',
|
||||
},
|
||||
{
|
||||
displayName: 'Copy In The Same Folder',
|
||||
name: 'sameFolder',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether to copy the file in the same folder as the original file',
|
||||
},
|
||||
{
|
||||
...driveRLC,
|
||||
displayName: 'Parent Drive',
|
||||
description: 'The drive where to save the copied file',
|
||||
displayOptions: { show: { sameFolder: [false] } },
|
||||
},
|
||||
{
|
||||
...folderRLC,
|
||||
displayName: 'Parent Folder',
|
||||
description: 'The folder where to save the copied file',
|
||||
displayOptions: { show: { sameFolder: [false] } },
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Copy Requires Writer Permission',
|
||||
name: 'copyRequiresWriterPermission',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether the options to copy, print, or download this file, should be disabled for readers and commenters',
|
||||
},
|
||||
{
|
||||
displayName: 'Description',
|
||||
name: 'description',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'A short description of the file',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['copy'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const file = this.getNodeParameter('fileId', i) as INodeParameterResourceLocator;
|
||||
|
||||
const fileId = file.value;
|
||||
|
||||
const options = this.getNodeParameter('options', i, {});
|
||||
|
||||
let name = this.getNodeParameter('name', i) as string;
|
||||
name = name ? name : `Copy of ${file.cachedResultName}`;
|
||||
|
||||
const copyRequiresWriterPermission = options.copyRequiresWriterPermission || false;
|
||||
|
||||
const qs = {
|
||||
includeItemsFromAllDrives: true,
|
||||
supportsAllDrives: true,
|
||||
spaces: 'appDataFolder, drive',
|
||||
corpora: 'allDrives',
|
||||
};
|
||||
|
||||
const parents: string[] = [];
|
||||
const sameFolder = this.getNodeParameter('sameFolder', i) as boolean;
|
||||
|
||||
if (!sameFolder) {
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const folderId = this.getNodeParameter('folderId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
parents.push(setParentFolder(folderId, driveId));
|
||||
}
|
||||
|
||||
const body: IDataObject = { copyRequiresWriterPermission, parents, name };
|
||||
|
||||
if (options.description) {
|
||||
body.description = options.description;
|
||||
}
|
||||
|
||||
const response = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/drive/v3/files/${fileId}/copy`,
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(response as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { DRIVE } from '../../helpers/interfaces';
|
||||
import { setFileProperties, setParentFolder, setUpdateCommonParams } from '../../helpers/utils';
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { driveRLC, folderRLC, updateCommonOptions } from '../common.descriptions';
|
||||
|
||||
import FormData from 'form-data';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'File Content',
|
||||
name: 'content',
|
||||
type: 'string',
|
||||
default: '',
|
||||
typeOptions: {
|
||||
rows: 2,
|
||||
},
|
||||
description: 'The text to create the file with',
|
||||
},
|
||||
{
|
||||
displayName: 'File Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. My New File',
|
||||
description:
|
||||
"The name of the file you want to create. If not specified, 'Untitled' will be used.",
|
||||
},
|
||||
{
|
||||
...driveRLC,
|
||||
displayName: 'Parent Drive',
|
||||
required: false,
|
||||
description: 'The drive where to create the new file',
|
||||
},
|
||||
{
|
||||
...folderRLC,
|
||||
displayName: 'Parent Folder',
|
||||
required: false,
|
||||
description: 'The folder where to create the new file',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
...updateCommonOptions,
|
||||
{
|
||||
displayName: 'Convert to Google Document',
|
||||
name: 'convertToGoogleDocument',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to create a Google Document (instead of the .txt default format)',
|
||||
hint: 'Google Docs API has to be enabled in the <a href="https://console.developers.google.com/apis/library/docs.googleapis.com" target="_blank">Google API Console</a>.',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['createFromText'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const name = (this.getNodeParameter('name', i) as string) || 'Untitled';
|
||||
|
||||
const options = this.getNodeParameter('options', i, {});
|
||||
const convertToGoogleDocument = (options.convertToGoogleDocument as boolean) || false;
|
||||
const mimeType = convertToGoogleDocument ? DRIVE.DOCUMENT : 'text/plain';
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const folderId = this.getNodeParameter('folderId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const metadata = {
|
||||
name,
|
||||
parents: [setParentFolder(folderId, driveId)],
|
||||
mimeType,
|
||||
};
|
||||
|
||||
const bodyParameters = setFileProperties(metadata, options);
|
||||
|
||||
const qs = setUpdateCommonParams(
|
||||
{
|
||||
includeItemsFromAllDrives: true,
|
||||
supportsAllDrives: true,
|
||||
spaces: 'appDataFolder, drive',
|
||||
corpora: 'allDrives',
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
let response;
|
||||
if (convertToGoogleDocument) {
|
||||
const document = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/drive/v3/files',
|
||||
bodyParameters,
|
||||
qs,
|
||||
);
|
||||
|
||||
const text = this.getNodeParameter('content', i, '') as string;
|
||||
|
||||
const body = {
|
||||
requests: [
|
||||
{
|
||||
insertText: {
|
||||
text,
|
||||
endOfSegmentLocation: {
|
||||
segmentId: '', //empty segment ID signifies the document's body
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const updateResponse = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'',
|
||||
body,
|
||||
undefined,
|
||||
`https://docs.googleapis.com/v1/documents/${document.id}:batchUpdate`,
|
||||
);
|
||||
|
||||
response = { id: updateResponse.documentId };
|
||||
} else {
|
||||
const content = Buffer.from(this.getNodeParameter('content', i, '') as string, 'utf8');
|
||||
const contentLength = content.byteLength;
|
||||
|
||||
const multiPartBody = new FormData();
|
||||
multiPartBody.append('metadata', JSON.stringify(metadata), {
|
||||
contentType: 'application/json',
|
||||
});
|
||||
multiPartBody.append('data', content, {
|
||||
contentType: mimeType,
|
||||
knownLength: contentLength,
|
||||
});
|
||||
|
||||
const uploadData = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
multiPartBody.getBuffer(),
|
||||
{
|
||||
uploadType: 'multipart',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': `multipart/related; boundary=${multiPartBody.getBoundary()}`,
|
||||
'Content-Length': multiPartBody.getLengthSync(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const uploadId = uploadData.id;
|
||||
|
||||
qs.addParents = setParentFolder(folderId, driveId);
|
||||
delete bodyParameters.parents;
|
||||
|
||||
const responseData = await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/drive/v3/files/${uploadId}`,
|
||||
bodyParameters,
|
||||
qs,
|
||||
);
|
||||
|
||||
response = { id: responseData.id };
|
||||
}
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(response as IDataObject),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import type { IExecuteFunctions, INodeExecutionData, INodeProperties } from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { fileRLC } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
description: 'The file to delete',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Delete Permanently',
|
||||
name: 'deletePermanently',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description:
|
||||
'Whether to delete the file immediately. If false, the file will be moved to the trash.',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['deleteFile'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const deletePermanently = this.getNodeParameter('options.deletePermanently', i, false) as boolean;
|
||||
|
||||
const qs = {
|
||||
supportsAllDrives: true,
|
||||
};
|
||||
|
||||
if (deletePermanently) {
|
||||
await googleApiRequest.call(this, 'DELETE', `/drive/v3/files/${fileId}`, undefined, qs);
|
||||
} else {
|
||||
await googleApiRequest.call(this, 'PATCH', `/drive/v3/files/${fileId}`, { trashed: true }, qs);
|
||||
}
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray({
|
||||
id: fileId,
|
||||
success: true,
|
||||
}),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IBinaryKeyData,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { fileRLC } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
description: 'The file to download',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
{
|
||||
displayName: 'Put Output File in Field',
|
||||
name: 'binaryPropertyName',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. data',
|
||||
default: 'data',
|
||||
description: 'Use this field name in the following nodes, to use the binary file data',
|
||||
hint: 'The name of the output binary field to put the file in',
|
||||
},
|
||||
{
|
||||
displayName: 'Google File Conversion',
|
||||
name: 'googleFileConversion',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: {
|
||||
multipleValues: false,
|
||||
},
|
||||
default: {},
|
||||
placeholder: 'Add Conversion',
|
||||
options: [
|
||||
{
|
||||
displayName: 'Conversion',
|
||||
name: 'conversion',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Google Docs',
|
||||
name: 'docsToFormat',
|
||||
type: 'options',
|
||||
|
||||
options: [
|
||||
{
|
||||
name: 'HTML',
|
||||
value: 'text/html',
|
||||
},
|
||||
{
|
||||
name: 'MS Word Document',
|
||||
value:
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
},
|
||||
{
|
||||
name: 'Open Office Document',
|
||||
value: 'application/vnd.oasis.opendocument.text',
|
||||
},
|
||||
{
|
||||
name: 'PDF',
|
||||
value: 'application/pdf',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'Rich Text (rtf)',
|
||||
value: 'application/rtf',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line n8n-nodes-base/node-param-display-name-miscased
|
||||
name: 'Text (txt)',
|
||||
value: 'text/plain',
|
||||
},
|
||||
],
|
||||
default: 'text/html',
|
||||
description: 'Format used to export when downloading Google Docs files',
|
||||
},
|
||||
{
|
||||
displayName: 'Google Drawings',
|
||||
name: 'drawingsToFormat',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'JPEG',
|
||||
value: 'image/jpeg',
|
||||
},
|
||||
{
|
||||
name: 'PDF',
|
||||
value: 'application/pdf',
|
||||
},
|
||||
{
|
||||
name: 'PNG',
|
||||
value: 'image/png',
|
||||
},
|
||||
{
|
||||
name: 'SVG',
|
||||
value: 'image/svg+xml',
|
||||
},
|
||||
],
|
||||
default: 'image/jpeg',
|
||||
description: 'Format used to export when downloading Google Drawings files',
|
||||
},
|
||||
{
|
||||
displayName: 'Google Slides',
|
||||
name: 'slidesToFormat',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'MS PowerPoint',
|
||||
value:
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
},
|
||||
{
|
||||
name: 'OpenOffice Presentation',
|
||||
value: 'application/vnd.oasis.opendocument.presentation',
|
||||
},
|
||||
{
|
||||
name: 'PDF',
|
||||
value: 'application/pdf',
|
||||
},
|
||||
],
|
||||
default:
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
description: 'Format used to export when downloading Google Slides files',
|
||||
},
|
||||
{
|
||||
displayName: 'Google Sheets',
|
||||
name: 'sheetsToFormat',
|
||||
type: 'options',
|
||||
options: [
|
||||
{
|
||||
name: 'CSV',
|
||||
value: 'text/csv',
|
||||
},
|
||||
{
|
||||
name: 'MS Excel',
|
||||
value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
},
|
||||
{
|
||||
name: 'Open Office Sheet',
|
||||
value: 'application/vnd.oasis.opendocument.spreadsheet',
|
||||
},
|
||||
{
|
||||
name: 'PDF',
|
||||
value: 'application/pdf',
|
||||
},
|
||||
],
|
||||
default: 'text/csv',
|
||||
description: 'Format used to export when downloading Google Sheets files',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'File Name',
|
||||
name: 'fileName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
description: 'File name. Ex: data.pdf.',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['download'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(
|
||||
this: IExecuteFunctions,
|
||||
i: number,
|
||||
item: INodeExecutionData,
|
||||
): Promise<INodeExecutionData[]> {
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const downloadOptions = this.getNodeParameter('options', i);
|
||||
|
||||
const requestOptions = {
|
||||
useStream: true,
|
||||
returnFullResponse: true,
|
||||
encoding: 'arraybuffer',
|
||||
json: false,
|
||||
};
|
||||
|
||||
const file = await googleApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/drive/v3/files/${fileId}`,
|
||||
{},
|
||||
{ fields: 'mimeType,name', supportsTeamDrives: true, supportsAllDrives: true },
|
||||
);
|
||||
let response;
|
||||
|
||||
if (file.mimeType?.includes('vnd.google-apps')) {
|
||||
const parameterKey = 'options.googleFileConversion.conversion';
|
||||
const type = file.mimeType.split('.')[2];
|
||||
let mime;
|
||||
if (type === 'document') {
|
||||
mime = this.getNodeParameter(
|
||||
`${parameterKey}.docsToFormat`,
|
||||
i,
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
) as string;
|
||||
} else if (type === 'presentation') {
|
||||
mime = this.getNodeParameter(
|
||||
`${parameterKey}.slidesToFormat`,
|
||||
i,
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
) as string;
|
||||
} else if (type === 'spreadsheet') {
|
||||
mime = this.getNodeParameter(
|
||||
`${parameterKey}.sheetsToFormat`,
|
||||
i,
|
||||
'application/x-vnd.oasis.opendocument.spreadsheet',
|
||||
) as string;
|
||||
} else {
|
||||
mime = this.getNodeParameter(`${parameterKey}.drawingsToFormat`, i, 'image/jpeg') as string;
|
||||
}
|
||||
response = await googleApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/drive/v3/files/${fileId}/export`,
|
||||
{},
|
||||
{ mimeType: mime, supportsAllDrives: true },
|
||||
undefined,
|
||||
requestOptions,
|
||||
);
|
||||
} else {
|
||||
response = await googleApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/drive/v3/files/${fileId}`,
|
||||
{},
|
||||
{ alt: 'media', supportsAllDrives: true },
|
||||
undefined,
|
||||
requestOptions,
|
||||
);
|
||||
}
|
||||
|
||||
const mimeType =
|
||||
(response.headers as IDataObject)?.['content-type'] ?? file.mimeType ?? undefined;
|
||||
const fileName = downloadOptions.fileName ?? file.name ?? undefined;
|
||||
|
||||
const newItem: INodeExecutionData = {
|
||||
json: item.json,
|
||||
binary: {},
|
||||
};
|
||||
|
||||
if (item.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 as IBinaryKeyData, item.binary);
|
||||
}
|
||||
|
||||
item = newItem;
|
||||
|
||||
const dataPropertyNameDownload = (downloadOptions.binaryPropertyName as string) || 'data';
|
||||
|
||||
item.binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData(
|
||||
response.body as Buffer,
|
||||
fileName as string,
|
||||
mimeType as string,
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData([item], { itemData: { item: i } });
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import type {
|
||||
IExecuteFunctions,
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { setParentFolder } from '../../helpers/utils';
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { driveRLC, fileRLC, folderRLC } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
description: 'The file to move',
|
||||
},
|
||||
{
|
||||
...driveRLC,
|
||||
displayName: 'Parent Drive',
|
||||
description: 'The drive where to move the file',
|
||||
},
|
||||
{
|
||||
...folderRLC,
|
||||
displayName: 'Parent Folder',
|
||||
description: 'The folder where to move the file',
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['move'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
});
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const folderId = this.getNodeParameter('folderId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const qs = {
|
||||
includeItemsFromAllDrives: true,
|
||||
supportsAllDrives: true,
|
||||
spaces: 'appDataFolder, drive',
|
||||
corpora: 'allDrives',
|
||||
};
|
||||
|
||||
const { parents } = await googleApiRequest.call(
|
||||
this,
|
||||
'GET',
|
||||
`/drive/v3/files/${fileId}`,
|
||||
undefined,
|
||||
{
|
||||
...qs,
|
||||
fields: 'parents',
|
||||
},
|
||||
);
|
||||
|
||||
const response = await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/drive/v3/files/${fileId}`,
|
||||
undefined,
|
||||
{
|
||||
...qs,
|
||||
addParents: setParentFolder(folderId, driveId),
|
||||
removeParents: ((parents as string[]) || []).join(','),
|
||||
},
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(response as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { fileRLC, permissionsOptions, shareOptions } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
description: 'The file to share',
|
||||
},
|
||||
permissionsOptions,
|
||||
shareOptions,
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['share'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const permissions = this.getNodeParameter('permissionsUi', i) as IDataObject;
|
||||
|
||||
const shareOption = this.getNodeParameter('options', i);
|
||||
|
||||
const body: IDataObject = {};
|
||||
|
||||
const qs: IDataObject = {
|
||||
supportsAllDrives: true,
|
||||
};
|
||||
|
||||
if (permissions.permissionsValues) {
|
||||
Object.assign(body, permissions.permissionsValues);
|
||||
}
|
||||
|
||||
Object.assign(qs, shareOption);
|
||||
|
||||
const response = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
`/drive/v3/files/${fileId}/permissions`,
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(response as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
import { NodeOperationError } from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import {
|
||||
getItemBinaryData,
|
||||
prepareQueryString,
|
||||
setFileProperties,
|
||||
setUpdateCommonParams,
|
||||
} from '../../helpers/utils';
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { fileRLC, updateCommonOptions } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
...fileRLC,
|
||||
displayName: 'File to Update',
|
||||
description: 'The file to update',
|
||||
},
|
||||
{
|
||||
displayName: 'Change File Content',
|
||||
name: 'changeFileContent',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to send a new binary data to update the file',
|
||||
},
|
||||
{
|
||||
displayName: 'Input Data Field Name',
|
||||
name: 'inputDataFieldName',
|
||||
type: 'string',
|
||||
placeholder: 'e.g. data',
|
||||
default: 'data',
|
||||
hint: 'The name of the input field containing the binary file data to update the file',
|
||||
description:
|
||||
'Find the name of input field containing the binary data to update the file in the Input panel on the left, in the Binary tab',
|
||||
displayOptions: {
|
||||
show: {
|
||||
changeFileContent: [true],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'New Updated File Name',
|
||||
name: 'newUpdatedFileName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. My New File',
|
||||
description: 'If not specified, the file name will not be changed',
|
||||
},
|
||||
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
...updateCommonOptions,
|
||||
{
|
||||
displayName: 'Move to Trash',
|
||||
name: 'trashed',
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: 'Whether to move a file to the trash. Only the owner may trash a file.',
|
||||
},
|
||||
{
|
||||
displayName: 'Return Fields',
|
||||
name: 'fields',
|
||||
type: 'multiOptions',
|
||||
options: [
|
||||
{
|
||||
name: '[All]',
|
||||
value: '*',
|
||||
description: 'All fields',
|
||||
},
|
||||
{
|
||||
name: 'explicitlyTrashed',
|
||||
value: 'explicitlyTrashed',
|
||||
},
|
||||
{
|
||||
name: 'exportLinks',
|
||||
value: 'exportLinks',
|
||||
},
|
||||
{
|
||||
name: 'hasThumbnail',
|
||||
value: 'hasThumbnail',
|
||||
},
|
||||
{
|
||||
name: 'iconLink',
|
||||
value: 'iconLink',
|
||||
},
|
||||
{
|
||||
name: 'ID',
|
||||
value: 'id',
|
||||
},
|
||||
{
|
||||
name: 'Kind',
|
||||
value: 'kind',
|
||||
},
|
||||
{
|
||||
name: 'mimeType',
|
||||
value: 'mimeType',
|
||||
},
|
||||
{
|
||||
name: 'Name',
|
||||
value: 'name',
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
],
|
||||
default: [],
|
||||
description: 'The fields to return',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['update'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const fileId = this.getNodeParameter('fileId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const changeFileContent = this.getNodeParameter('changeFileContent', i, false) as boolean;
|
||||
|
||||
let mimeType;
|
||||
|
||||
// update file binary data
|
||||
if (changeFileContent) {
|
||||
const inputDataFieldName = this.getNodeParameter('inputDataFieldName', i) as string;
|
||||
|
||||
const binaryData = await getItemBinaryData.call(this, inputDataFieldName, i);
|
||||
|
||||
const { contentLength, fileContent } = binaryData;
|
||||
mimeType = binaryData.mimeType;
|
||||
|
||||
if (Buffer.isBuffer(fileContent)) {
|
||||
await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/upload/drive/v3/files/${fileId}`,
|
||||
fileContent,
|
||||
{
|
||||
uploadType: 'media',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': mimeType,
|
||||
'Content-Length': contentLength,
|
||||
},
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const resumableUpload = await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/upload/drive/v3/files/${fileId}`,
|
||||
undefined,
|
||||
{ uploadType: 'resumable', supportsAllDrives: true },
|
||||
undefined,
|
||||
{
|
||||
returnFullResponse: true,
|
||||
},
|
||||
);
|
||||
const uploadUrl = resumableUpload.headers.location;
|
||||
|
||||
let offset = 0;
|
||||
for await (const chunk of fileContent) {
|
||||
const nextOffset = offset + Number(chunk.length);
|
||||
try {
|
||||
await this.helpers.httpRequest({
|
||||
method: 'PUT',
|
||||
url: uploadUrl,
|
||||
headers: {
|
||||
'Content-Length': chunk.length,
|
||||
'Content-Range': `bytes ${offset}-${nextOffset - 1}/${contentLength}`,
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 308) {
|
||||
throw new NodeOperationError(this.getNode(), error as Error, { itemIndex: i });
|
||||
}
|
||||
}
|
||||
offset = nextOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const options = this.getNodeParameter('options', i, {});
|
||||
|
||||
const qs: IDataObject = setUpdateCommonParams(
|
||||
{
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
if (options.fields) {
|
||||
const queryFields = prepareQueryString(options.fields as string[]);
|
||||
qs.fields = queryFields;
|
||||
}
|
||||
|
||||
if (options.trashed) {
|
||||
qs.trashed = options.trashed;
|
||||
}
|
||||
|
||||
const body: IDataObject = setFileProperties({}, options);
|
||||
|
||||
const newUpdatedFileName = this.getNodeParameter('newUpdatedFileName', i, '') as string;
|
||||
if (newUpdatedFileName) {
|
||||
body.name = newUpdatedFileName;
|
||||
}
|
||||
|
||||
if (mimeType) {
|
||||
body.mimeType = mimeType;
|
||||
}
|
||||
|
||||
// update file metadata
|
||||
const responseData = await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/drive/v3/files/${fileId}`,
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(responseData as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
|
||||
return executionData;
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
import FormData from 'form-data';
|
||||
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
INodeExecutionData,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { updateDisplayOptions } from '@utils/utilities';
|
||||
|
||||
import {
|
||||
getItemBinaryData,
|
||||
setFileProperties,
|
||||
setUpdateCommonParams,
|
||||
setParentFolder,
|
||||
processInChunks,
|
||||
} from '../../helpers/utils';
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { driveRLC, folderRLC, updateCommonOptions } from '../common.descriptions';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'Input Data Field Name',
|
||||
name: 'inputDataFieldName',
|
||||
type: 'string',
|
||||
placeholder: '“e.g. data',
|
||||
default: 'data',
|
||||
required: true,
|
||||
hint: 'The name of the input field containing the binary file data to update the file',
|
||||
description:
|
||||
'Find the name of input field containing the binary data to update the file in the Input panel on the left, in the Binary tab',
|
||||
},
|
||||
{
|
||||
displayName: 'File Name',
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
default: '',
|
||||
placeholder: 'e.g. My New File',
|
||||
description: 'If not specified, the original file name will be used',
|
||||
},
|
||||
{
|
||||
...driveRLC,
|
||||
displayName: 'Parent Drive',
|
||||
description: 'The drive where to upload the file',
|
||||
},
|
||||
{
|
||||
...folderRLC,
|
||||
displayName: 'Parent Folder',
|
||||
description: 'The folder where to upload the file',
|
||||
},
|
||||
{
|
||||
displayName: 'Options',
|
||||
name: 'options',
|
||||
type: 'collection',
|
||||
placeholder: 'Add option',
|
||||
default: {},
|
||||
options: [
|
||||
...updateCommonOptions,
|
||||
{
|
||||
displayName: 'Simplify Output',
|
||||
name: 'simplifyOutput',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether to return a simplified version of the response instead of all fields',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const displayOptions = {
|
||||
show: {
|
||||
resource: ['file'],
|
||||
operation: ['upload'],
|
||||
},
|
||||
};
|
||||
|
||||
export const description = updateDisplayOptions(displayOptions, properties);
|
||||
|
||||
export async function execute(this: IExecuteFunctions, i: number): Promise<INodeExecutionData[]> {
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
|
||||
const inputDataFieldName = this.getNodeParameter('inputDataFieldName', i) as string;
|
||||
|
||||
const { contentLength, fileContent, originalFilename, mimeType } = await getItemBinaryData.call(
|
||||
this,
|
||||
inputDataFieldName,
|
||||
i,
|
||||
);
|
||||
|
||||
const name = (this.getNodeParameter('name', i) as string) || originalFilename;
|
||||
|
||||
const driveId = this.getNodeParameter('driveId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const folderId = this.getNodeParameter('folderId', i, undefined, {
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
let uploadId;
|
||||
const metadata = {
|
||||
name,
|
||||
parents: [setParentFolder(folderId, driveId)],
|
||||
};
|
||||
if (Buffer.isBuffer(fileContent)) {
|
||||
const multiPartBody = new FormData();
|
||||
multiPartBody.append('metadata', JSON.stringify(metadata), {
|
||||
contentType: 'application/json',
|
||||
});
|
||||
multiPartBody.append('data', fileContent, {
|
||||
contentType: mimeType,
|
||||
knownLength: contentLength,
|
||||
});
|
||||
|
||||
const response = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
multiPartBody.getBuffer(),
|
||||
{
|
||||
uploadType: 'multipart',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': `multipart/related; boundary=${multiPartBody.getBoundary()}`,
|
||||
'Content-Length': multiPartBody.getLengthSync(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
uploadId = response.id;
|
||||
} else {
|
||||
const resumableUpload = await googleApiRequest.call(
|
||||
this,
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
metadata,
|
||||
{
|
||||
uploadType: 'resumable',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
returnFullResponse: true,
|
||||
headers: {
|
||||
'X-Upload-Content-Type': mimeType,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const uploadUrl = resumableUpload.headers.location;
|
||||
|
||||
// 2MB chunks, needs to be a multiple of 256kB for Google Drive API
|
||||
const chunkSizeBytes = 2048 * 1024;
|
||||
|
||||
await processInChunks(fileContent, chunkSizeBytes, async (chunk, offset) => {
|
||||
try {
|
||||
const response = await this.helpers.httpRequest({
|
||||
method: 'PUT',
|
||||
url: uploadUrl,
|
||||
headers: {
|
||||
'Content-Length': chunk.length,
|
||||
'Content-Range': `bytes ${offset}-${offset + chunk.byteLength - 1}/${contentLength}`,
|
||||
},
|
||||
body: chunk,
|
||||
});
|
||||
uploadId = response?.id;
|
||||
} catch (error) {
|
||||
if (error.response?.status !== 308) throw error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const options = this.getNodeParameter('options', i, {});
|
||||
|
||||
const qs = setUpdateCommonParams(
|
||||
{
|
||||
addParents: setParentFolder(folderId, driveId),
|
||||
includeItemsFromAllDrives: true,
|
||||
supportsAllDrives: true,
|
||||
spaces: 'appDataFolder, drive',
|
||||
corpora: 'allDrives',
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
if (!options.simplifyOutput) {
|
||||
qs.fields = '*';
|
||||
}
|
||||
|
||||
const body = setFileProperties(
|
||||
{
|
||||
mimeType,
|
||||
name,
|
||||
originalFilename,
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
const response = await googleApiRequest.call(
|
||||
this,
|
||||
'PATCH',
|
||||
`/drive/v3/files/${uploadId}`,
|
||||
body,
|
||||
qs,
|
||||
);
|
||||
|
||||
const executionData = this.helpers.constructExecutionMetaData(
|
||||
this.helpers.returnJsonArray(response as IDataObject[]),
|
||||
{ itemData: { item: i } },
|
||||
);
|
||||
returnData.push(...executionData);
|
||||
|
||||
return returnData;
|
||||
}
|
||||
Reference in New Issue
Block a user