From c722b0db00b7f87404edc6ef06c1e68f79c5cf06 Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Thu, 5 Mar 2020 13:51:15 +0100 Subject: [PATCH] Implement file replace Signed-off-by: Alexandre Bodin --- .../strapi-plugin-upload/config/routes.json | 9 --- .../config/schema.graphql.js | 13 ++-- .../controllers/Upload.js | 71 +++++++++---------- .../strapi-plugin-upload/services/Upload.js | 71 ++++++++++++------- 4 files changed, 86 insertions(+), 78 deletions(-) diff --git a/packages/strapi-plugin-upload/config/routes.json b/packages/strapi-plugin-upload/config/routes.json index d47777ce26..4cd62678bd 100644 --- a/packages/strapi-plugin-upload/config/routes.json +++ b/packages/strapi-plugin-upload/config/routes.json @@ -29,15 +29,6 @@ } } }, - { - "method": "POST", - "path": "/files/replace/:id", - "handler": "Upload.replaceFile", - "config": { - "policies": [], - "description": "Replace a file" - } - }, { "method": "GET", "path": "/files/count", diff --git a/packages/strapi-plugin-upload/config/schema.graphql.js b/packages/strapi-plugin-upload/config/schema.graphql.js index 0f3216d484..279d1c033f 100644 --- a/packages/strapi-plugin-upload/config/schema.graphql.js +++ b/packages/strapi-plugin-upload/config/schema.graphql.js @@ -23,7 +23,9 @@ module.exports = { resolver: async (obj, { file: upload, ...fields }) => { const file = await formatFile(upload, fields); - const uploadedFiles = await strapi.plugins.upload.services.upload.upload([file]); + const uploadedFiles = await strapi.plugins.upload.services.upload.uploadFileAndPersist( + file + ); // Return response. return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles; @@ -35,10 +37,9 @@ module.exports = { resolver: async (obj, { files: uploads, ...fields }) => { const files = await Promise.all(uploads.map(upload => formatFile(upload, fields))); - const uploadedFiles = await strapi.plugins.upload.services.upload.upload(files); + const uploadService = strapi.plugins.upload.services.upload; - // Return response. - return uploadedFiles; + return Promise.all(files.map(file => uploadService.uploadFileAndPersist(file))); }, }, }, @@ -55,8 +56,8 @@ const formatFile = async (upload, metas) => { const buffer = Buffer.concat(buffers); - const { formatFileInfo } = strapi.plugins.upload.services.upload; - const fileInfo = formatFileInfo( + const uploadService = strapi.plugins.upload.services.upload; + const fileInfo = uploadService.formatFileInfo( { filename, type: mimetype, diff --git a/packages/strapi-plugin-upload/controllers/Upload.js b/packages/strapi-plugin-upload/controllers/Upload.js index 0c004d5115..dda40d633f 100644 --- a/packages/strapi-plugin-upload/controllers/Upload.js +++ b/packages/strapi-plugin-upload/controllers/Upload.js @@ -29,53 +29,50 @@ const validateUploadBody = (schema, data = {}) => { }); }; +const isUploadDisabled = () => _.get(strapi.plugins, 'upload.config.enabled', true) === false; + +const disabledPluginError = () => + strapi.errors.badRequest(null, { + errors: [{ id: 'Upload.status.disabled', message: 'File upload is disabled' }], + }); + +const emptyFileError = () => + strapi.errors.badRequest(null, { + errors: [{ id: 'Upload.status.empty', message: 'Files are empty' }], + }); + module.exports = { async upload(ctx) { - const uploadService = strapi.plugins.upload.services.upload; - - // Retrieve provider configuration. - const { enabled } = strapi.plugins.upload.config; - - // Verify if the file upload is enable. - if (enabled === false) { - throw strapi.errors.badRequest(null, { - errors: [{ id: 'Upload.status.disabled', message: 'File upload is disabled' }], - }); + if (isUploadDisabled()) { + throw disabledPluginError(); } const files = _.get(ctx.request.files, 'files'); - if (_.isEmpty(files)) { - throw strapi.errors.badRequest(null, { - errors: [{ id: 'Upload.status.empty', message: 'Files are empty' }], - }); + throw emptyFileError(); } - let data; - if (Array.isArray(files)) { - data = await validateUploadBody(multiUploadSchema, ctx.request.body); + const { id } = ctx.query; + + const uploadService = strapi.plugins.upload.services.upload; + + const validationSchema = Array.isArray(files) ? multiUploadSchema : uploadSchema; + const data = await validateUploadBody(validationSchema, ctx.request.body); + + if (id) { + // cannot replace with more than one file + if (Array.isArray(files)) { + throw strapi.errors.badRequest(null, { + errors: [ + { id: 'Upload.replace.single', message: 'Cannot replace a file with multiple ones' }, + ], + }); + } + + ctx.body = await uploadService.replace(id, { data, file: files }); } else { - data = await validateUploadBody(uploadSchema, ctx.request.body); + ctx.body = await uploadService.upload({ data, files }); } - - const { refId, ref, source, field, path, fileInfo } = data; - - const fileArray = Array.isArray(files) ? files : [files]; - const fileInfoArray = Array.isArray(fileInfo) ? fileInfo : [fileInfo]; - - // Transform stream files to buffer - const enhancedFiles = await Promise.all( - fileArray.map((file, idx) => { - const fileInfo = fileInfoArray[idx] || {}; - - return uploadService.enhanceFile(file, fileInfo, { refId, ref, source, field, path }); - }) - ); - - const uploadedFiles = await uploadService.upload(enhancedFiles); - - // Send 200 `ok` - ctx.send(uploadedFiles); }, async getSettings(ctx) { diff --git a/packages/strapi-plugin-upload/services/Upload.js b/packages/strapi-plugin-upload/services/Upload.js index 0a65b41438..30563e2feb 100644 --- a/packages/strapi-plugin-upload/services/Upload.js +++ b/packages/strapi-plugin-upload/services/Upload.js @@ -58,7 +58,7 @@ module.exports = { return entity; }, - async enhanceFile(file, fileInfo, metas) { + async enhanceFile(file, fileInfo = {}, metas = {}) { const parts = await toArray(fs.createReadStream(file.path)); const buffers = parts.map(part => (_.isBuffer(part) ? part : Buffer.from(part))); @@ -79,31 +79,52 @@ module.exports = { }); }, - async upload(files) { - const config = strapi.plugins.upload.config; + async upload({ data, files }) { + const { fileInfo, ...metas } = data; - // upload a single file - const uploadFile = async file => { - await strapi.plugins.upload.provider.upload(file); + const fileArray = Array.isArray(files) ? files : [files]; + const fileInfoArray = Array.isArray(fileInfo) ? fileInfo : [fileInfo]; - delete file.buffer; - file.provider = config.provider; + const doUpload = async (file, fileInfo) => { + const fileData = await this.enhanceFile(file, fileInfo, metas); - const res = await this.add(file); - - strapi.eventHub.emit('media.create', { media: res }); - return res; + return this.uploadFileAndPersist(fileData); }; - // Execute upload function of the provider for all files. - return Promise.all(files.map(file => uploadFile(file))); + return await Promise.all( + fileArray.map((file, idx) => doUpload(file, fileInfoArray[idx] || {})) + ); }, - async replace(dbFile, file) { + async uploadFileAndPersist(fileData) { + const config = strapi.plugins.upload.config; + await strapi.plugins.upload.provider.upload(fileData); + + delete fileData.buffer; + fileData.provider = config.provider; + + const res = await this.add(fileData); + + strapi.eventHub.emit('media.create', { media: res }); + return res; + }, + + async replace(id, { data, file }) { const config = strapi.plugins.upload.config; + const dbFile = await this.fetch({ id }); + + if (!dbFile) { + throw new Error('file not found'); + } + + const { fileInfo } = data; + const fileData = await this.enhanceFile(file, fileInfo); + + // TODO: maybe check if same extension ?? + // keep a constant hash - _.assign(file, { + _.assign(fileData, { hash: dbFile.hash, ext: dbFile.ext, }); @@ -113,19 +134,19 @@ module.exports = { await strapi.plugins.upload.provider.delete(dbFile); } - await strapi.plugins.upload.provider.upload(file); + await strapi.plugins.upload.provider.upload(fileData); - delete file.buffer; - file.provider = config.provider; + delete fileData.buffer; + fileData.provider = config.provider; - const res = await this.update({ id: dbFile.id }, {}); + const res = await this.update({ id }, fileData); strapi.eventHub.emit('media.update', { media: res }); return res; }, - update(id, values) { - return strapi.query('file', 'upload').update({ id }, values); + update(params, values) { + return strapi.query('file', 'upload').update(params, values); }, add(values) { @@ -133,9 +154,7 @@ module.exports = { }, fetch(params) { - return strapi.query('file', 'upload').findOne({ - id: params.id, - }); + return strapi.query('file', 'upload').findOne(params); }, fetchAll(params) { @@ -180,7 +199,7 @@ module.exports = { } ); }) - ).then(files => this.upload(files)); + ).then(files => this.uploadFileAndPersist(files)); }, async getConfig() {