From 42032b11f552b0bfe332467dac6798f45c90fb10 Mon Sep 17 00:00:00 2001 From: James Date: Wed, 30 Oct 2024 17:11:54 -0400 Subject: [PATCH] fix: bulk upload mimetype wildcard file selection --- packages/payload/src/exports/shared.ts | 6 ++++-- packages/payload/src/uploads/mimeTypeValidator.ts | 6 ++++-- packages/payload/src/utilities/validateMimeType.ts | 4 ++++ packages/translations/src/clientKeys.ts | 1 + packages/ui/src/elements/BulkUpload/index.tsx | 14 +++++++++++--- 5 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 packages/payload/src/utilities/validateMimeType.ts diff --git a/packages/payload/src/exports/shared.ts b/packages/payload/src/exports/shared.ts index 90286ee3ae1..f8825066fb2 100644 --- a/packages/payload/src/exports/shared.ts +++ b/packages/payload/src/exports/shared.ts @@ -35,12 +35,12 @@ export { validOperators } from '../types/constants.js' export { formatFilesize } from '../uploads/formatFilesize.js' export { isImage } from '../uploads/isImage.js' + export { deepCopyObject, deepCopyObjectComplex, deepCopyObjectSimple, } from '../utilities/deepCopyObject.js' - export { deepMerge, deepMergeWithCombinedArrays, @@ -49,8 +49,8 @@ export { } from '../utilities/deepMerge.js' export { fieldSchemaToJSON } from '../utilities/fieldSchemaToJSON.js' -export { getDataByPath } from '../utilities/getDataByPath.js' +export { getDataByPath } from '../utilities/getDataByPath.js' export { getSelectMode } from '../utilities/getSelectMode.js' export { getSiblingData } from '../utilities/getSiblingData.js' @@ -72,6 +72,8 @@ export { setsAreEqual } from '../utilities/setsAreEqual.js' export { default as toKebabCase } from '../utilities/toKebabCase.js' export { unflatten } from '../utilities/unflatten.js' + +export { validateMimeType } from '../utilities/validateMimeType.js' export { wait } from '../utilities/wait.js' export { default as wordBoundariesRegex } from '../utilities/wordBoundariesRegex.js' export { versionDefaults } from '../versions/defaults.js' diff --git a/packages/payload/src/uploads/mimeTypeValidator.ts b/packages/payload/src/uploads/mimeTypeValidator.ts index bf25d100342..6dc31894794 100644 --- a/packages/payload/src/uploads/mimeTypeValidator.ts +++ b/packages/payload/src/uploads/mimeTypeValidator.ts @@ -1,5 +1,7 @@ import type { Validate } from '../fields/config/types.js' +import { validateMimeType } from '../utilities/validateMimeType.js' + export const mimeTypeValidator = (mimeTypes: string[]): Validate => (val: string, { siblingData }) => { @@ -11,6 +13,6 @@ export const mimeTypeValidator = return 'Invalid file type' } - const cleanedMimeTypes = mimeTypes.map((v) => v.replace('*', '')) - return !cleanedMimeTypes.some((v) => val.startsWith(v)) ? `Invalid file type: '${val}'` : true + const isValidMimeType = validateMimeType(val, mimeTypes) + return isValidMimeType ? true : `Invalid file type: '${val}'` } diff --git a/packages/payload/src/utilities/validateMimeType.ts b/packages/payload/src/utilities/validateMimeType.ts new file mode 100644 index 00000000000..554b8b0b109 --- /dev/null +++ b/packages/payload/src/utilities/validateMimeType.ts @@ -0,0 +1,4 @@ +export const validateMimeType = (mimeType: string, allowedMimeTypes: string[]): boolean => { + const cleanedMimeTypes = allowedMimeTypes.map((v) => v.replace('*', '')) + return cleanedMimeTypes.some((cleanedMimeType) => mimeType.startsWith(cleanedMimeType)) +} diff --git a/packages/translations/src/clientKeys.ts b/packages/translations/src/clientKeys.ts index 6901ba11cb1..2a2416d14ff 100644 --- a/packages/translations/src/clientKeys.ts +++ b/packages/translations/src/clientKeys.ts @@ -68,6 +68,7 @@ export const clientTranslationKeys = createClientTranslationKeys([ 'error:emailOrPasswordIncorrect', 'error:usernameOrPasswordIncorrect', 'error:loadingDocument', + 'error:invalidFileType', 'error:logoutFailed', 'error:noMatchedField', 'error:notAllowedToAccessPage', diff --git a/packages/ui/src/elements/BulkUpload/index.tsx b/packages/ui/src/elements/BulkUpload/index.tsx index 85bd9672323..80cab9d8b5f 100644 --- a/packages/ui/src/elements/BulkUpload/index.tsx +++ b/packages/ui/src/elements/BulkUpload/index.tsx @@ -3,10 +3,13 @@ import type { JsonObject } from 'payload' import { useModal } from '@faceless-ui/modal' +import { validateMimeType } from 'payload/shared' import React from 'react' +import { toast } from 'sonner' import { useConfig } from '../../providers/Config/index.js' import { EditDepthProvider, useEditDepth } from '../../providers/EditDepth/index.js' +import { useTranslation } from '../../providers/Translation/index.js' import { Drawer } from '../Drawer/index.js' import { AddFilesView } from './AddFilesView/index.js' import { AddingFilesView } from './AddingFilesView/index.js' @@ -19,6 +22,7 @@ function DrawerContent() { const { closeModal } = useModal() const { collectionSlug, drawerSlug } = useBulkUpload() const { config } = useConfig() + const { t } = useTranslation() const uploadCollection = config.collections.find((col) => col.slug === collectionSlug) const uploadConfig = uploadCollection.upload @@ -31,14 +35,18 @@ function DrawerContent() { if ( uploadMimeTypes === undefined || uploadMimeTypes.length === 0 || - uploadMimeTypes?.includes(candidateFile.type) + validateMimeType(candidateFile.type, uploadMimeTypes) ) { fileTransfer.items.add(candidateFile) } } - void addFiles(fileTransfer.files) + if (fileTransfer.files.length === 0) { + toast.error(t('error:invalidFileType')) + } else { + void addFiles(fileTransfer.files) + } }, - [addFiles, uploadMimeTypes], + [addFiles, t, uploadMimeTypes], ) if (!collectionSlug) {