diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b4422f4b4..75a80c51f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,6 +121,7 @@ ___ - Excluding keys that have trailing edges.node when performing GraphQL resolver (Chris Bland) [#7273](https://github.com/parse-community/parse-server/pull/7273) - Added centralized feature deprecation with standardized warning logs (Manuel Trezza) [#7303](https://github.com/parse-community/parse-server/pull/7303) - Use Node.js 15.13.0 in CI (Olle Jonsson) [#7312](https://github.com/parse-community/parse-server/pull/7312) +- Fix file upload issue for S3 compatible storage (Linode, DigitalOcean) by avoiding empty tags property when creating a file (Ali Oguzhan Yildiz) [#7300](https://github.com/parse-community/parse-server/pull/7300) ___ ## 4.5.0 [Full Changelog](https://github.com/parse-community/parse-server/compare/4.4.0...4.5.0) diff --git a/spec/ParseFile.spec.js b/spec/ParseFile.spec.js index b55dd7404a..af1de35ee7 100644 --- a/spec/ParseFile.spec.js +++ b/spec/ParseFile.spec.js @@ -3,6 +3,7 @@ 'use strict'; +const { FilesController } = require('../lib/Controllers/FilesController'); const request = require('../lib/request'); const str = 'Hello World!'; @@ -205,6 +206,34 @@ describe('Parse.File testing', () => { notEqual(file.name(), 'hello.txt'); }); + it('saves the file with tags', async () => { + spyOn(FilesController.prototype, 'createFile').and.callThrough(); + const file = new Parse.File('hello.txt', data, 'text/plain'); + const tags = { hello: 'world' }; + file.setTags(tags); + expect(file.url()).toBeUndefined(); + const result = await file.save(); + expect(file.name()).toBeDefined(); + expect(file.url()).toBeDefined(); + expect(result.tags()).toEqual(tags); + expect(FilesController.prototype.createFile.calls.argsFor(0)[4]).toEqual({ + tags: tags, + metadata: {}, + }); + }); + + it('does not pass empty file tags while saving', async () => { + spyOn(FilesController.prototype, 'createFile').and.callThrough(); + const file = new Parse.File('hello.txt', data, 'text/plain'); + expect(file.url()).toBeUndefined(); + expect(file.name()).toBeDefined(); + await file.save(); + expect(file.url()).toBeDefined(); + expect(FilesController.prototype.createFile.calls.argsFor(0)[4]).toEqual({ + metadata: {}, + }); + }); + it('save file in object', async done => { const file = new Parse.File('hello.txt', data, 'text/plain'); ok(!file.url()); diff --git a/src/Routers/FilesRouter.js b/src/Routers/FilesRouter.js index df768e6d0b..c0c7e00f13 100644 --- a/src/Routers/FilesRouter.js +++ b/src/Routers/FilesRouter.js @@ -166,16 +166,22 @@ export class FilesRouter { // update fileSize const bufferData = Buffer.from(fileObject.file._data, 'base64'); fileObject.fileSize = Buffer.byteLength(bufferData); + // prepare file options + const fileOptions = { + metadata: fileObject.file._metadata, + }; + // some s3-compatible providers (DigitalOcean, Linode) do not accept tags + // so we do not include the tags option if it is empty. + const fileTags = + Object.keys(fileObject.file._tags).length > 0 ? { tags: fileObject.file._tags } : {}; + Object.assign(fileOptions, fileTags); // save file const createFileResult = await filesController.createFile( config, fileObject.file._name, bufferData, fileObject.file._source.type, - { - tags: fileObject.file._tags, - metadata: fileObject.file._metadata, - } + fileOptions ); // update file with new data fileObject.file._name = createFileResult.name;