Implement file replace

Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com>
This commit is contained in:
Alexandre Bodin 2020-03-05 13:51:15 +01:00
parent 7cd34b725a
commit c722b0db00
4 changed files with 86 additions and 78 deletions

View File

@ -29,15 +29,6 @@
} }
} }
}, },
{
"method": "POST",
"path": "/files/replace/:id",
"handler": "Upload.replaceFile",
"config": {
"policies": [],
"description": "Replace a file"
}
},
{ {
"method": "GET", "method": "GET",
"path": "/files/count", "path": "/files/count",

View File

@ -23,7 +23,9 @@ module.exports = {
resolver: async (obj, { file: upload, ...fields }) => { resolver: async (obj, { file: upload, ...fields }) => {
const file = await formatFile(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 response.
return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles; return uploadedFiles.length === 1 ? uploadedFiles[0] : uploadedFiles;
@ -35,10 +37,9 @@ module.exports = {
resolver: async (obj, { files: uploads, ...fields }) => { resolver: async (obj, { files: uploads, ...fields }) => {
const files = await Promise.all(uploads.map(upload => formatFile(upload, 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 Promise.all(files.map(file => uploadService.uploadFileAndPersist(file)));
return uploadedFiles;
}, },
}, },
}, },
@ -55,8 +56,8 @@ const formatFile = async (upload, metas) => {
const buffer = Buffer.concat(buffers); const buffer = Buffer.concat(buffers);
const { formatFileInfo } = strapi.plugins.upload.services.upload; const uploadService = strapi.plugins.upload.services.upload;
const fileInfo = formatFileInfo( const fileInfo = uploadService.formatFileInfo(
{ {
filename, filename,
type: mimetype, type: mimetype,

View File

@ -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 = { module.exports = {
async upload(ctx) { async upload(ctx) {
const uploadService = strapi.plugins.upload.services.upload; if (isUploadDisabled()) {
throw disabledPluginError();
// 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' }],
});
} }
const files = _.get(ctx.request.files, 'files'); const files = _.get(ctx.request.files, 'files');
if (_.isEmpty(files)) { if (_.isEmpty(files)) {
throw strapi.errors.badRequest(null, { throw emptyFileError();
errors: [{ id: 'Upload.status.empty', message: 'Files are empty' }],
});
} }
let data; const { id } = ctx.query;
if (Array.isArray(files)) {
data = await validateUploadBody(multiUploadSchema, ctx.request.body); 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 { } 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) { async getSettings(ctx) {

View File

@ -58,7 +58,7 @@ module.exports = {
return entity; return entity;
}, },
async enhanceFile(file, fileInfo, metas) { async enhanceFile(file, fileInfo = {}, metas = {}) {
const parts = await toArray(fs.createReadStream(file.path)); const parts = await toArray(fs.createReadStream(file.path));
const buffers = parts.map(part => (_.isBuffer(part) ? part : Buffer.from(part))); const buffers = parts.map(part => (_.isBuffer(part) ? part : Buffer.from(part)));
@ -79,31 +79,52 @@ module.exports = {
}); });
}, },
async upload(files) { async upload({ data, files }) {
const config = strapi.plugins.upload.config; const { fileInfo, ...metas } = data;
// upload a single file const fileArray = Array.isArray(files) ? files : [files];
const uploadFile = async file => { const fileInfoArray = Array.isArray(fileInfo) ? fileInfo : [fileInfo];
await strapi.plugins.upload.provider.upload(file);
delete file.buffer; const doUpload = async (file, fileInfo) => {
file.provider = config.provider; const fileData = await this.enhanceFile(file, fileInfo, metas);
const res = await this.add(file); return this.uploadFileAndPersist(fileData);
strapi.eventHub.emit('media.create', { media: res });
return res;
}; };
// Execute upload function of the provider for all files. return await Promise.all(
return Promise.all(files.map(file => uploadFile(file))); 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 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 // keep a constant hash
_.assign(file, { _.assign(fileData, {
hash: dbFile.hash, hash: dbFile.hash,
ext: dbFile.ext, ext: dbFile.ext,
}); });
@ -113,19 +134,19 @@ module.exports = {
await strapi.plugins.upload.provider.delete(dbFile); await strapi.plugins.upload.provider.delete(dbFile);
} }
await strapi.plugins.upload.provider.upload(file); await strapi.plugins.upload.provider.upload(fileData);
delete file.buffer; delete fileData.buffer;
file.provider = config.provider; 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 }); strapi.eventHub.emit('media.update', { media: res });
return res; return res;
}, },
update(id, values) { update(params, values) {
return strapi.query('file', 'upload').update({ id }, values); return strapi.query('file', 'upload').update(params, values);
}, },
add(values) { add(values) {
@ -133,9 +154,7 @@ module.exports = {
}, },
fetch(params) { fetch(params) {
return strapi.query('file', 'upload').findOne({ return strapi.query('file', 'upload').findOne(params);
id: params.id,
});
}, },
fetchAll(params) { fetchAll(params) {
@ -180,7 +199,7 @@ module.exports = {
} }
); );
}) })
).then(files => this.upload(files)); ).then(files => this.uploadFileAndPersist(files));
}, },
async getConfig() { async getConfig() {