From 4b117e07ef0831416b39f2369370c5497adbc0f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3nas=20G=2E=20Sigur=C3=B0sson?= Date: Tue, 4 Jun 2024 13:10:28 +0000 Subject: [PATCH] feat(application-system): add total file size limit (#14892) * feat: add total file size limit * feat: add default to component * Update libs/application/ui-components/src/utilities/FileUploadController/index.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: from comments * feat: move default total max size to utils --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- libs/application/core/src/lib/constants.ts | 5 +++++ .../application/core/src/lib/fieldBuilders.ts | 12 ++++++++--- libs/application/core/src/lib/messages.ts | 6 ++++++ libs/application/types/src/lib/Fields.ts | 4 ++++ .../utilities/FileUploadController/index.tsx | 21 ++++++++++++++++++- .../utilities/FileUploadController/utils.ts | 2 ++ 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/libs/application/core/src/lib/constants.ts b/libs/application/core/src/lib/constants.ts index 6a7acdfa84e2..5770c475a8dd 100644 --- a/libs/application/core/src/lib/constants.ts +++ b/libs/application/core/src/lib/constants.ts @@ -32,3 +32,8 @@ export const hasYes = (answer: any) => { return answer === YES } + +export const DEFAULT_FILE_SIZE_LIMIT = 10000000 // 10MB +export const DEFAULT_TOTAL_FILE_SIZE_SUM = 100000000 // 100MB, too high? +export const DEFAULT_ALLOWED_FILE_TYPES = + '.pdf, .doc, .docx, .rtf, .jpg, .jpeg, .png, .heic' diff --git a/libs/application/core/src/lib/fieldBuilders.ts b/libs/application/core/src/lib/fieldBuilders.ts index 0b44c7cf6939..fe5a1bc8ec2b 100644 --- a/libs/application/core/src/lib/fieldBuilders.ts +++ b/libs/application/core/src/lib/fieldBuilders.ts @@ -46,6 +46,11 @@ import { import { Colors } from '@island.is/island-ui/theme' import { SpanType, BoxProps } from '@island.is/island-ui/core/types' import { coreDefaultFieldMessages } from './messages' +import { + DEFAULT_ALLOWED_FILE_TYPES, + DEFAULT_FILE_SIZE_LIMIT, + DEFAULT_TOTAL_FILE_SIZE_SUM, +} from './constants' const extractCommonFields = ( data: Omit, @@ -337,6 +342,7 @@ export function buildFileUploadField( uploadAccept, maxSize, maxSizeErrorText, + totalMaxSize, forImageUpload, } = data return { @@ -352,10 +358,10 @@ export function buildFileUploadField( uploadButtonLabel || coreDefaultFieldMessages.defaultFileUploadButtonLabel, uploadMultiple, - uploadAccept: - uploadAccept ?? '.pdf, .doc, .docx, .rtf, .jpg, .jpeg, .png, .heic', - maxSize: maxSize ?? 10000000, + uploadAccept: uploadAccept ?? DEFAULT_ALLOWED_FILE_TYPES, + maxSize: maxSize ?? DEFAULT_FILE_SIZE_LIMIT, maxSizeErrorText, + totalMaxSize: totalMaxSize ?? DEFAULT_TOTAL_FILE_SIZE_SUM, forImageUpload, type: FieldTypes.FILEUPLOAD, component: FieldComponents.FILEUPLOAD, diff --git a/libs/application/core/src/lib/messages.ts b/libs/application/core/src/lib/messages.ts index 74d1783a28d3..0802b9385f1d 100644 --- a/libs/application/core/src/lib/messages.ts +++ b/libs/application/core/src/lib/messages.ts @@ -354,6 +354,12 @@ export const coreErrorMessages = defineMessages({ 'Skráin er of stór. Hægt er að hlaða inn skrám sem eru {maxSizeInMb}MB eða minni.', description: 'Error message when file size exceeds max size limit', }, + fileMaxSumSizeLimitExceeded: { + id: 'application.system:core.error.file.maxSizeLimitSumExceeded', + defaultMessage: + 'Skrárnar eru samtals of stórar. Hægt er að hlaða inn skrám sem eru samtals {maxSizeInMb}MB eða minni.', + description: 'Error message when sum of file sizes exceeds max size limit', + }, fileInvalidExtension: { id: 'application.system:core.error.file.invalidExtension', defaultMessage: diff --git a/libs/application/types/src/lib/Fields.ts b/libs/application/types/src/lib/Fields.ts index 47846876397b..51eedf9ed822 100644 --- a/libs/application/types/src/lib/Fields.ts +++ b/libs/application/types/src/lib/Fields.ts @@ -351,6 +351,10 @@ export interface FileUploadField extends BaseField { */ readonly maxSize?: number readonly maxSizeErrorText?: FormText + /** + * Defaults to 100MB + */ + readonly totalMaxSize?: number readonly forImageUpload?: boolean } diff --git a/libs/application/ui-components/src/utilities/FileUploadController/index.tsx b/libs/application/ui-components/src/utilities/FileUploadController/index.tsx index 51cd5a250b1c..5d0b7f43c03a 100644 --- a/libs/application/ui-components/src/utilities/FileUploadController/index.tsx +++ b/libs/application/ui-components/src/utilities/FileUploadController/index.tsx @@ -17,9 +17,9 @@ import { DELETE_ATTACHMENT, } from '@island.is/application/graphql' -import { uploadFileToS3 } from './utils' import { Action, ActionTypes } from './types' import { InputImageUpload } from '../../components/InputImageUpload/InputImageUpload' +import { DEFAULT_TOTAL_MAX_SIZE, uploadFileToS3 } from './utils' type UploadFileAnswer = { name: string @@ -72,6 +72,7 @@ interface FileUploadControllerProps { readonly accept?: string readonly maxSize?: number readonly maxSizeErrorText?: string + readonly totalMaxSize?: number readonly forImageUpload?: boolean } @@ -88,6 +89,7 @@ export const FileUploadController: FC< accept, maxSize, maxSizeErrorText, + totalMaxSize = DEFAULT_TOTAL_MAX_SIZE, forImageUpload, }) => { const { formatMessage } = useLocale() @@ -97,6 +99,7 @@ export const FileUploadController: FC< const [createUploadUrl] = useMutation(CREATE_UPLOAD_URL) const [addAttachment] = useMutation(ADD_ATTACHMENT) const [deleteAttachment] = useMutation(DELETE_ATTACHMENT) + const [sumOfFileSizes, setSumOfFileSizes] = useState(0) const initialUploadFiles: UploadFile[] = (val && val.map((f) => answerToUploadFile(f))) || [] const [state, dispatch] = useReducer(reducer, initialUploadFiles) @@ -164,6 +167,22 @@ export const FileUploadController: FC< clearErrors(id) setUploadError(undefined) + const totalNewFileSize = addedUniqueFiles + .map((f) => f.size) + .reduce((a, b) => a + b, 0) + + // Show an error if the sum of the file sizes exceeds totalMaxSize. + if (totalMaxSize && totalNewFileSize + sumOfFileSizes > totalMaxSize) { + setUploadError( + formatMessage(coreErrorMessages.fileMaxSumSizeLimitExceeded, { + maxSizeInMb: totalMaxSize / 1000000, + }), + ) + return + } + + setSumOfFileSizes(totalNewFileSize + sumOfFileSizes) + const newUploadFiles = addedUniqueFiles.map((f) => fileToObject(f, 'uploading'), ) diff --git a/libs/application/ui-components/src/utilities/FileUploadController/utils.ts b/libs/application/ui-components/src/utilities/FileUploadController/utils.ts index 75f75d8c8903..fb384f52fffb 100644 --- a/libs/application/ui-components/src/utilities/FileUploadController/utils.ts +++ b/libs/application/ui-components/src/utilities/FileUploadController/utils.ts @@ -2,6 +2,8 @@ import { UploadFile } from '@island.is/island-ui/core' import { S3UploadResponse, ActionTypes, Action } from './types' +export const DEFAULT_TOTAL_MAX_SIZE = 100000000 + export const uploadFileToS3 = ( file: UploadFile, dispatch: React.Dispatch,