diff --git a/demo/payload.config.js b/demo/payload.config.js index 1aab41a46e..7907424ae8 100644 --- a/demo/payload.config.js +++ b/demo/payload.config.js @@ -122,5 +122,10 @@ module.exports = { console.error('global error config handler', err); }, }, + upload: { + limits: { + fileSize: 10000000, // 10MB + }, + }, webpack: (config) => config, }; diff --git a/src/client/components/forms/Form/errorMessages.js b/src/client/components/forms/Form/errorMessages.js new file mode 100644 index 0000000000..0f692e880e --- /dev/null +++ b/src/client/components/forms/Form/errorMessages.js @@ -0,0 +1,3 @@ +export default { + 413: 'Your request was too large to submit successfully.', +}; diff --git a/src/client/components/forms/Form/index.js b/src/client/components/forms/Form/index.js index b25ddda4aa..ba7a674bc5 100644 --- a/src/client/components/forms/Form/index.js +++ b/src/client/components/forms/Form/index.js @@ -16,6 +16,7 @@ import getSiblingDataFunc from './getSiblingData'; import getDataByPathFunc from './getDataByPath'; import wait from '../../../../utilities/wait'; import buildInitialState from './buildInitialState'; +import errorMessages from './errorMessages'; import { SubmittedContext, ProcessingContext, ModifiedContext, FormContext, FieldContext } from './context'; @@ -148,11 +149,16 @@ const Form = (props) => { if (typeof handleResponse === 'function') return handleResponse(res); - const json = await res.json(); setProcessing(false); clearStatus(); + const contentType = res.headers.get('content-type'); + const isJSON = contentType && contentType.indexOf('application/json') !== -1; + + let json = {}; + if (isJSON) json = await res.json(); + if (res.status < 400) { setSubmitted(false); @@ -177,7 +183,7 @@ const Form = (props) => { history.push(destination); } else if (!disableSuccessStatus) { replaceStatus([{ - message: json.message, + message: json.message || 'Submission successful.', type: 'success', disappear: 3000, }]); @@ -223,8 +229,10 @@ const Form = (props) => { return json; } + const message = errorMessages[res.status] || 'An unknown error occurrred.'; + addStatus({ - message: 'An unknown error occurred.', + message, type: 'error', }); } diff --git a/src/collections/operations/create.js b/src/collections/operations/create.js index dc10a42347..630847b2f9 100644 --- a/src/collections/operations/create.js +++ b/src/collections/operations/create.js @@ -4,7 +4,7 @@ const crypto = require('crypto'); const executeAccess = require('../../auth/executeAccess'); -const { MissingFile } = require('../../errors'); +const { MissingFile, FileUploadError } = require('../../errors'); const resizeAndSave = require('../../uploads/imageResizer'); const getSafeFilename = require('../../uploads/getSafeFilename'); const getImageSize = require('../../uploads/getImageSize'); @@ -116,18 +116,23 @@ async function create(args) { const fsSafeName = await getSafeFilename(staticPath, file.name); - await file.mv(`${staticPath}/${fsSafeName}`); + try { + await file.mv(`${staticPath}/${fsSafeName}`); - if (imageMIMETypes.indexOf(file.mimetype) > -1) { - const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`); - fileData.width = dimensions.width; - fileData.height = dimensions.height; + if (imageMIMETypes.indexOf(file.mimetype) > -1) { + const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`); + fileData.width = dimensions.width; + fileData.height = dimensions.height; - if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') { - fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType); + if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') { + fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType); + } } + } catch (err) { + throw new FileUploadError(err); } + fileData.filename = fsSafeName; fileData.filesize = file.size; fileData.mimeType = file.mimetype; diff --git a/src/collections/operations/update.js b/src/collections/operations/update.js index b8852f6b32..9241d04fb5 100644 --- a/src/collections/operations/update.js +++ b/src/collections/operations/update.js @@ -4,7 +4,7 @@ const path = require('path'); const overwriteMerge = require('../../utilities/overwriteMerge'); const executeAccess = require('../../auth/executeAccess'); -const { NotFound, Forbidden, APIError } = require('../../errors'); +const { NotFound, Forbidden, APIError, FileUploadError } = require('../../errors'); const imageMIMETypes = require('../../uploads/imageMIMETypes'); const getImageSize = require('../../uploads/getImageSize'); const getSafeFilename = require('../../uploads/getSafeFilename'); @@ -160,22 +160,27 @@ async function update(args) { if (file) { const fsSafeName = await getSafeFilename(staticPath, file.name); - await file.mv(`${staticPath}/${fsSafeName}`); + try { + await file.mv(`${staticPath}/${fsSafeName}`); - fileData.filename = fsSafeName; - fileData.filesize = file.size; - fileData.mimeType = file.mimetype; + fileData.filename = fsSafeName; + fileData.filesize = file.size; + fileData.mimeType = file.mimetype; - if (imageMIMETypes.indexOf(file.mimetype) > -1) { - const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`); - fileData.width = dimensions.width; - fileData.height = dimensions.height; + if (imageMIMETypes.indexOf(file.mimetype) > -1) { + const dimensions = await getImageSize(`${staticPath}/${fsSafeName}`); + fileData.width = dimensions.width; + fileData.height = dimensions.height; - if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') { - fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType); + if (Array.isArray(imageSizes) && file.mimetype !== 'image/svg+xml') { + fileData.sizes = await resizeAndSave(staticPath, collectionConfig, fsSafeName, fileData.mimeType); + } } + } catch (err) { + throw new FileUploadError(err); } + data = { ...data, ...fileData, diff --git a/src/errors/FileUploadError.js b/src/errors/FileUploadError.js new file mode 100644 index 0000000000..ad9429f70f --- /dev/null +++ b/src/errors/FileUploadError.js @@ -0,0 +1,10 @@ +const httpStatus = require('http-status'); +const APIError = require('./APIError'); + +class FileUploadError extends APIError { + constructor() { + super('There was a problem while uploading the file.', httpStatus.BAD_REQUEST); + } +} + +module.exports = FileUploadError; diff --git a/src/errors/index.js b/src/errors/index.js index 9b74a13124..2fec4955df 100644 --- a/src/errors/index.js +++ b/src/errors/index.js @@ -4,6 +4,7 @@ const DuplicateCollection = require('./DuplicateCollection'); const DuplicateGlobal = require('./DuplicateGlobal'); const ErrorDeletingFile = require('./ErrorDeletingFile'); const errorHandler = require('../express/middleware/errorHandler'); +const FileUploadError = require('./FileUploadError'); const Forbidden = require('./Forbidden'); const InvalidFieldRelationship = require('./InvalidFieldRelationship'); const MissingCollectionLabel = require('./MissingCollectionLabel'); @@ -21,6 +22,7 @@ module.exports = { DuplicateGlobal, ErrorDeletingFile, errorHandler, + FileUploadError, Forbidden, InvalidFieldRelationship, MissingCollectionLabel, diff --git a/src/express/middleware/index.js b/src/express/middleware/index.js index fb8b03208e..eb05d32c9b 100644 --- a/src/express/middleware/index.js +++ b/src/express/middleware/index.js @@ -31,6 +31,7 @@ const middleware = (payload) => { localizationMiddleware(payload.config.localization), fileUpload({ parseNested: true, + ...payload.config.upload, }), (req, _, next) => { req.payload = payload; diff --git a/src/utilities/sanitizeConfig.js b/src/utilities/sanitizeConfig.js index e1a79bb1e4..dfbd11da25 100644 --- a/src/utilities/sanitizeConfig.js +++ b/src/utilities/sanitizeConfig.js @@ -27,6 +27,8 @@ const sanitizeConfig = (config) => { sanitizedConfig.admin = config.admin || {}; + sanitizedConfig.upload = config.upload || {}; + if (!sanitizedConfig.admin.user) { sanitizedConfig.admin.user = 'users'; sanitizedConfig.collections.push(defaultUser);