diff --git a/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts b/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts index 20a600c399..badffefba3 100644 --- a/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts +++ b/packages/nodes-base/nodes/Microsoft/OneDrive/MicrosoftOneDrive.node.ts @@ -1,3 +1,4 @@ +import { IncomingMessage } from 'http'; import type { IDataObject, IExecuteFunctions, @@ -105,6 +106,7 @@ export class MicrosoftOneDrive implements INodeType { responseData = await microsoftApiRequest.call(this, 'GET', `/drive/items/${fileId}`); const fileName = responseData.name; + const downloadUrl = responseData['@microsoft.graph.downloadUrl']; if (responseData.file === undefined) { throw new NodeApiError(this.getNode(), responseData as JsonObject, { @@ -117,16 +119,28 @@ export class MicrosoftOneDrive implements INodeType { mimeType = responseData.file.mimeType; } - responseData = await microsoftApiRequest.call( - this, - 'GET', - `/drive/items/${fileId}/content`, - {}, - {}, - undefined, - {}, - { encoding: null, resolveWithFullResponse: true }, - ); + try { + responseData = await microsoftApiRequest.call( + this, + 'GET', + `/drive/items/${fileId}/content`, + {}, + {}, + undefined, + {}, + { encoding: null, resolveWithFullResponse: true }, + ); + } catch (error) { + if (downloadUrl) { + responseData = await this.helpers.httpRequest({ + method: 'GET', + url: downloadUrl, + returnFullResponse: true, + encoding: 'arraybuffer', + json: false, + }); + } + } const newItem: INodeExecutionData = { json: items[i].json, @@ -146,10 +160,15 @@ export class MicrosoftOneDrive implements INodeType { items[i] = newItem; - const data = Buffer.from(responseData.body as Buffer); + let data; + if (responseData?.body instanceof IncomingMessage) { + data = responseData.body; + } else { + data = Buffer.from(responseData.body as Buffer); + } items[i].binary![dataPropertyNameDownload] = await this.helpers.prepareBinaryData( - data as unknown as Buffer, + data, fileName as string, mimeType, ); diff --git a/packages/nodes-base/nodes/Microsoft/OneDrive/test/node/file.download.test.ts b/packages/nodes-base/nodes/Microsoft/OneDrive/test/node/file.download.test.ts new file mode 100644 index 0000000000..6d9e573efa --- /dev/null +++ b/packages/nodes-base/nodes/Microsoft/OneDrive/test/node/file.download.test.ts @@ -0,0 +1,75 @@ +import type { IncomingMessage } from 'http'; +import type { MockProxy } from 'jest-mock-extended'; +import { mock } from 'jest-mock-extended'; +import { type IHttpRequestMethods, type IExecuteFunctions, ApplicationError } from 'n8n-workflow'; + +import * as genericFunctions from '../../GenericFunctions'; +import { MicrosoftOneDrive } from '../../MicrosoftOneDrive.node'; + +jest.mock('../../GenericFunctions', () => ({ + ...jest.requireActual('../../GenericFunctions'), + microsoftApiRequest: jest.fn(async function (_: IHttpRequestMethods, resource: string) { + if (resource === '/drive/items/fileID') { + return { + name: 'MyFile', + '@microsoft.graph.downloadUrl': 'https://test.com/file', + file: { + mimeType: 'image/png', + }, + }; + } + if (resource === '/drive/items/fileID/content') { + throw new ApplicationError('Error'); + } + }), +})); + +describe('Test MicrosoftOneDrive, file > download', () => { + let mockExecuteFunctions: MockProxy; + let microsoftOneDrive: MicrosoftOneDrive; + const httpRequest = jest.fn(async () => ({ body: mock() })); + const prepareBinaryData = jest.fn(async () => ({ data: 'testBinary' })); + + beforeEach(() => { + mockExecuteFunctions = mock(); + microsoftOneDrive = new MicrosoftOneDrive(); + + mockExecuteFunctions.helpers = { + httpRequest, + prepareBinaryData, + returnJsonArray: jest.fn((data) => [data]), + constructExecutionMetaData: jest.fn((data) => data), + } as any; + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should call helpers.httpRequest when request to /drive/items/{fileId}/content fails', async () => { + const items = [{ json: { data: 'test' } }]; + mockExecuteFunctions.getInputData.mockReturnValue(items); + mockExecuteFunctions.getNodeParameter.mockImplementation((key: string) => { + if (key === 'resource') return 'file'; + if (key === 'operation') return 'download'; + if (key === 'fileId') return 'fileID'; + if (key === 'binaryPropertyName') return 'data'; + }); + + const result = await microsoftOneDrive.execute.call(mockExecuteFunctions); + + expect(genericFunctions.microsoftApiRequest).toHaveBeenCalledTimes(2); + expect(httpRequest).toHaveBeenCalledTimes(1); + expect(httpRequest).toHaveBeenCalledWith({ + encoding: 'arraybuffer', + json: false, + method: 'GET', + returnFullResponse: true, + url: 'https://test.com/file', + }); + expect(prepareBinaryData).toHaveBeenCalledTimes(1); + expect(result).toEqual([ + [{ binary: { data: { data: 'testBinary' } }, json: { data: 'test' } }], + ]); + }); +});