Files
n8n-enterprise-unlocked/packages/nodes-base/nodes/Google/Drive/v2/actions/file/update.operation.ts
2023-06-27 11:51:41 +03:00

275 lines
5.9 KiB
TypeScript

import type { IExecuteFunctions } from 'n8n-core';
import type { IDataObject, 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',
},
undefined,
{
headers: {
'Content-Type': mimeType,
'Content-Length': contentLength,
},
},
);
} else {
const resumableUpload = await googleApiRequest.call(
this,
'PATCH',
`/upload/drive/v3/files/${fileId}`,
undefined,
{ uploadType: 'resumable' },
undefined,
{
resolveWithFullResponse: 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;
}