mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 09:36:44 +00:00
fix(GoogleDrive Node): Fix google service accounts uploading to shared drives (#18952)
This commit is contained in:
@@ -61,9 +61,14 @@ describe('test GoogleDriveV2: file createFromText', () => {
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
expect.anything(), // Buffer of content goes here
|
||||
{ uploadType: 'media' },
|
||||
{ uploadType: 'multipart', supportsAllDrives: true },
|
||||
undefined,
|
||||
{ headers: { 'Content-Length': 12, 'Content-Type': 'text/plain' } },
|
||||
{
|
||||
headers: {
|
||||
'Content-Length': 503,
|
||||
'Content-Type': expect.stringMatching(/^multipart\/related; boundary=(\\S)*/),
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(transport.googleApiRequest).toHaveBeenCalledWith(
|
||||
'PATCH',
|
||||
|
||||
@@ -5,6 +5,11 @@ import * as utils from '../../../../v2/helpers/utils';
|
||||
import * as transport from '../../../../v2/transport';
|
||||
import { createMockExecuteFunction, createTestStream, driveNode } from '../helpers';
|
||||
|
||||
const fileContent = Buffer.from('Hello Drive!');
|
||||
const originalFilename = 'original.txt';
|
||||
const contentLength = 123;
|
||||
const mimeType = 'text/plain';
|
||||
|
||||
jest.mock('../../../../v2/transport', () => {
|
||||
const originalModule = jest.requireActual('../../../../v2/transport');
|
||||
return {
|
||||
@@ -26,10 +31,10 @@ jest.mock('../../../../v2/helpers/utils', () => {
|
||||
...originalModule,
|
||||
getItemBinaryData: jest.fn(async function () {
|
||||
return {
|
||||
contentLength: '123',
|
||||
fileContent: Buffer.from('Hello Drive!'),
|
||||
originalFilename: 'original.txt',
|
||||
mimeType: 'text/plain',
|
||||
contentLength,
|
||||
fileContent,
|
||||
originalFilename,
|
||||
mimeType,
|
||||
};
|
||||
}),
|
||||
};
|
||||
@@ -41,11 +46,13 @@ describe('test GoogleDriveV2: file upload', () => {
|
||||
});
|
||||
|
||||
it('should upload buffers', async () => {
|
||||
const name = 'newFile.txt';
|
||||
const parent = 'folderIDxxxxxx';
|
||||
const nodeParameters = {
|
||||
name: 'newFile.txt',
|
||||
name,
|
||||
folderId: {
|
||||
__rl: true,
|
||||
value: 'folderIDxxxxxx',
|
||||
value: parent,
|
||||
mode: 'list',
|
||||
cachedResultName: 'testFolder 3',
|
||||
cachedResultUrl: 'https://drive.google.com/drive/folders/folderIDxxxxxx',
|
||||
@@ -65,16 +72,21 @@ describe('test GoogleDriveV2: file upload', () => {
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
expect.any(Buffer),
|
||||
{ uploadType: 'media' },
|
||||
{ uploadType: 'multipart', supportsAllDrives: true },
|
||||
undefined,
|
||||
{ headers: { 'Content-Length': '123', 'Content-Type': 'text/plain' } },
|
||||
{
|
||||
headers: {
|
||||
'Content-Length': 498,
|
||||
'Content-Type': expect.stringMatching(/^multipart\/related; boundary=(\\S)*/),
|
||||
},
|
||||
},
|
||||
);
|
||||
expect(transport.googleApiRequest).toHaveBeenCalledWith(
|
||||
'PATCH',
|
||||
'/drive/v3/files/undefined',
|
||||
{ mimeType: 'text/plain', name: 'newFile.txt', originalFilename: 'original.txt' },
|
||||
{ mimeType, name, originalFilename },
|
||||
{
|
||||
addParents: 'folderIDxxxxxx',
|
||||
addParents: parent,
|
||||
supportsAllDrives: true,
|
||||
corpora: 'allDrives',
|
||||
includeItemsFromAllDrives: true,
|
||||
@@ -87,11 +99,15 @@ describe('test GoogleDriveV2: file upload', () => {
|
||||
});
|
||||
|
||||
it('should stream large files in 2MB chunks', async () => {
|
||||
const name = 'newFile.jpg';
|
||||
const parent = 'folderIDxxxxxx';
|
||||
const originalFilename = 'test.jpg';
|
||||
const mimeType = 'image/jpg';
|
||||
const nodeParameters = {
|
||||
name: 'newFile.jpg',
|
||||
name,
|
||||
folderId: {
|
||||
__rl: true,
|
||||
value: 'folderIDxxxxxx',
|
||||
value: parent,
|
||||
mode: 'list',
|
||||
cachedResultName: 'testFolder 3',
|
||||
cachedResultUrl: 'https://drive.google.com/drive/folders/folderIDxxxxxx',
|
||||
@@ -106,8 +122,8 @@ describe('test GoogleDriveV2: file upload', () => {
|
||||
|
||||
const fileSize = 7 * 1024 * 1024; // 7MB
|
||||
jest.mocked(utils.getItemBinaryData).mockResolvedValue({
|
||||
mimeType: 'image/jpg',
|
||||
originalFilename: 'test.jpg',
|
||||
mimeType,
|
||||
originalFilename,
|
||||
contentLength: fileSize,
|
||||
fileContent: createTestStream(fileSize),
|
||||
});
|
||||
@@ -123,17 +139,17 @@ describe('test GoogleDriveV2: file upload', () => {
|
||||
expect(transport.googleApiRequest).toHaveBeenCalledWith(
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
undefined,
|
||||
{ uploadType: 'resumable' },
|
||||
{ name, parents: [parent] },
|
||||
{ uploadType: 'resumable', supportsAllDrives: true },
|
||||
undefined,
|
||||
{ returnFullResponse: true, headers: { 'X-Upload-Content-Type': 'image/jpg' } },
|
||||
);
|
||||
expect(transport.googleApiRequest).toHaveBeenCalledWith(
|
||||
'PATCH',
|
||||
'/drive/v3/files/undefined',
|
||||
{ mimeType: 'image/jpg', name: 'newFile.jpg', originalFilename: 'test.jpg' },
|
||||
{ mimeType, name, originalFilename },
|
||||
{
|
||||
addParents: 'folderIDxxxxxx',
|
||||
addParents: parent,
|
||||
supportsAllDrives: true,
|
||||
corpora: 'allDrives',
|
||||
includeItemsFromAllDrives: true,
|
||||
|
||||
@@ -12,6 +12,8 @@ import { setFileProperties, setParentFolder, setUpdateCommonParams } from '../..
|
||||
import { googleApiRequest } from '../../transport';
|
||||
import { driveRLC, folderRLC, updateCommonOptions } from '../common.descriptions';
|
||||
|
||||
import FormData from 'form-data';
|
||||
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'File Content',
|
||||
@@ -88,14 +90,13 @@ export async function execute(this: IExecuteFunctions, i: number): Promise<INode
|
||||
extractValue: true,
|
||||
}) as string;
|
||||
|
||||
const bodyParameters = setFileProperties(
|
||||
{
|
||||
name,
|
||||
parents: [setParentFolder(folderId, driveId)],
|
||||
mimeType,
|
||||
},
|
||||
options,
|
||||
);
|
||||
const metadata = {
|
||||
name,
|
||||
parents: [setParentFolder(folderId, driveId)],
|
||||
mimeType,
|
||||
};
|
||||
|
||||
const bodyParameters = setFileProperties(metadata, options);
|
||||
|
||||
const qs = setUpdateCommonParams(
|
||||
{
|
||||
@@ -146,19 +147,29 @@ export async function execute(this: IExecuteFunctions, i: number): Promise<INode
|
||||
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',
|
||||
content,
|
||||
multiPartBody.getBuffer(),
|
||||
{
|
||||
uploadType: 'media',
|
||||
uploadType: 'multipart',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': mimeType,
|
||||
'Content-Length': contentLength,
|
||||
'Content-Type': `multipart/related; boundary=${multiPartBody.getBoundary()}`,
|
||||
'Content-Length': multiPartBody.getLengthSync(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import FormData from 'form-data';
|
||||
|
||||
import type {
|
||||
IDataObject,
|
||||
IExecuteFunctions,
|
||||
@@ -97,20 +99,34 @@ export async function execute(this: IExecuteFunctions, i: number): Promise<INode
|
||||
}) 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',
|
||||
fileContent,
|
||||
multiPartBody.getBuffer(),
|
||||
{
|
||||
uploadType: 'media',
|
||||
uploadType: 'multipart',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': mimeType,
|
||||
'Content-Length': contentLength,
|
||||
'Content-Type': `multipart/related; boundary=${multiPartBody.getBoundary()}`,
|
||||
'Content-Length': multiPartBody.getLengthSync(),
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -121,8 +137,11 @@ export async function execute(this: IExecuteFunctions, i: number): Promise<INode
|
||||
this,
|
||||
'POST',
|
||||
'/upload/drive/v3/files',
|
||||
undefined,
|
||||
{ uploadType: 'resumable' },
|
||||
metadata,
|
||||
{
|
||||
uploadType: 'resumable',
|
||||
supportsAllDrives: true,
|
||||
},
|
||||
undefined,
|
||||
{
|
||||
returnFullResponse: true,
|
||||
|
||||
Reference in New Issue
Block a user