From 400293b8ee7ef0341f6b1e0e07c62474d63fce02 Mon Sep 17 00:00:00 2001 From: Sasha <64744993+r1tsuu@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:46:41 +0300 Subject: [PATCH] fix: duplicate with upload collections (#8552) Fixes the duplicate operation with uploads Enables duplicate for upload collections by default --- .gitignore | 3 +++ .../src/collections/config/sanitize.ts | 5 +--- .../src/collections/operations/duplicate.ts | 24 +++++++++++++++++- .../collections/operations/local/duplicate.ts | 2 +- .../payload/src/uploads/generateFileData.ts | 15 ++++++++--- .../src/elements/DocumentControls/index.tsx | 2 +- test/uploads/config.ts | 2 +- test/uploads/int.spec.ts | 25 +++++++++++++++++++ 8 files changed, 67 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 1071eaf9f..c4e5c6d72 100644 --- a/.gitignore +++ b/.gitignore @@ -314,3 +314,6 @@ test/app/(payload)/admin/importMap.js /test/app/(payload)/admin/importMap.js test/pnpm-lock.yaml test/databaseAdapter.js +/filename-compound-index +/media-with-relation-preview +/media-without-relation-preview diff --git a/packages/payload/src/collections/config/sanitize.ts b/packages/payload/src/collections/config/sanitize.ts index 43ac04123..2ca62c29d 100644 --- a/packages/payload/src/collections/config/sanitize.ts +++ b/packages/payload/src/collections/config/sanitize.ts @@ -130,9 +130,6 @@ export const sanitizeCollection = async ( // sanitize fields for reserved names sanitizeUploadFields(sanitized.fields, sanitized) - // disable duplicate for uploads by default - sanitized.disableDuplicate = sanitized.disableDuplicate || true - sanitized.upload.bulkUpload = sanitized.upload?.bulkUpload ?? true sanitized.upload.staticDir = sanitized.upload.staticDir || sanitized.slug sanitized.admin.useAsTitle = @@ -162,7 +159,7 @@ export const sanitizeCollection = async ( } // disable duplicate for auth enabled collections by default - sanitized.disableDuplicate = sanitized.disableDuplicate || true + sanitized.disableDuplicate = sanitized.disableDuplicate ?? true if (!sanitized.auth.strategies) { sanitized.auth.strategies = [] diff --git a/packages/payload/src/collections/operations/duplicate.ts b/packages/payload/src/collections/operations/duplicate.ts index c1d0fac42..9b65fecf6 100644 --- a/packages/payload/src/collections/operations/duplicate.ts +++ b/packages/payload/src/collections/operations/duplicate.ts @@ -16,6 +16,8 @@ import { afterRead } from '../../fields/hooks/afterRead/index.js' import { beforeChange } from '../../fields/hooks/beforeChange/index.js' import { beforeDuplicate } from '../../fields/hooks/beforeDuplicate/index.js' import { beforeValidate } from '../../fields/hooks/beforeValidate/index.js' +import { generateFileData } from '../../uploads/generateFileData.js' +import { uploadFiles } from '../../uploads/uploadFiles.js' import { commitTransaction } from '../../utilities/commitTransaction.js' import { initTransaction } from '../../utilities/initTransaction.js' import { killTransaction } from '../../utilities/killTransaction.js' @@ -129,7 +131,7 @@ export const duplicateOperation = async ( let result - const originalDoc = await afterRead({ + let originalDoc = await afterRead({ collection: collectionConfig, context: req.context, depth: 0, @@ -143,6 +145,18 @@ export const duplicateOperation = async ( showHiddenFields: true, }) + const { data: newFileData, files: filesToUpload } = await generateFileData({ + collection: args.collection, + config: req.payload.config, + data: originalDoc, + operation: 'create', + overwriteExistingFiles: 'forceDisable', + req, + throwOnMissingFile: true, + }) + + originalDoc = newFileData + // ///////////////////////////////////// // Create Access // ///////////////////////////////////// @@ -231,6 +245,14 @@ export const duplicateOperation = async ( // Create / Update // ///////////////////////////////////// + // ///////////////////////////////////// + // Write files to local storage + // ///////////////////////////////////// + + if (!collectionConfig.upload.disableLocalStorage) { + await uploadFiles(payload, filesToUpload, req) + } + const versionDoc = await payload.db.create({ collection: collectionConfig.slug, data: result, diff --git a/packages/payload/src/collections/operations/local/duplicate.ts b/packages/payload/src/collections/operations/local/duplicate.ts index 74a2d7b00..fb2463400 100644 --- a/packages/payload/src/collections/operations/local/duplicate.ts +++ b/packages/payload/src/collections/operations/local/duplicate.ts @@ -44,7 +44,7 @@ export async function duplicate( ) } - if (collection.config.disableDuplicate === false) { + if (collection.config.disableDuplicate === true) { throw new APIError( `The collection with slug ${String(collectionSlug)} cannot be duplicated.`, 400, diff --git a/packages/payload/src/uploads/generateFileData.ts b/packages/payload/src/uploads/generateFileData.ts index ee2321080..7c62ddd1f 100644 --- a/packages/payload/src/uploads/generateFileData.ts +++ b/packages/payload/src/uploads/generateFileData.ts @@ -27,7 +27,8 @@ type Args = { data: T operation: 'create' | 'update' originalDoc?: T - overwriteExistingFiles?: boolean + /** pass forceDisable to not overwrite existing files even if they already exist in `data` */ + overwriteExistingFiles?: 'forceDisable' | boolean req: PayloadRequest throwOnMissingFile?: boolean } @@ -85,20 +86,28 @@ export const generateFileData = async ({ const filePath = `${staticPath}/${filename}` const response = await getFileByPath(filePath) file = response - overwriteExistingFiles = true + if (overwriteExistingFiles !== 'forceDisable') { + overwriteExistingFiles = true + } } else if (filename && url) { file = await getExternalFile({ data: data as FileData, req, uploadConfig: collectionConfig.upload, }) - overwriteExistingFiles = true + if (overwriteExistingFiles !== 'forceDisable') { + overwriteExistingFiles = true + } } } catch (err: unknown) { throw new FileRetrievalError(req.t, err instanceof Error ? err.message : undefined) } } + if (overwriteExistingFiles === 'forceDisable') { + overwriteExistingFiles = false + } + if (!file) { if (throwOnMissingFile) { throw new MissingFile(req.t) diff --git a/packages/ui/src/elements/DocumentControls/index.tsx b/packages/ui/src/elements/DocumentControls/index.tsx index b81fadff4..9a75be316 100644 --- a/packages/ui/src/elements/DocumentControls/index.tsx +++ b/packages/ui/src/elements/DocumentControls/index.tsx @@ -279,7 +279,7 @@ export const DocumentControls: React.FC<{ )} )} - {!collectionConfig.disableDuplicate && isEditing && ( + {collectionConfig.disableDuplicate !== true && isEditing && ( { ) }) }) + + describe('Duplicate', () => { + it('should duplicate upload collection doc', async () => { + const filePath = path.resolve(dirname, './image.png') + const file = await getFileByPath(filePath) + file.name = 'file-to-duplicate.png' + + const mediaDoc = await payload.create({ + collection: 'media', + data: {}, + file, + }) + + expect(mediaDoc).toBeDefined() + + const duplicatedDoc = await payload.duplicate({ + collection: 'media', + id: mediaDoc.id, + }) + + const expectedPath = path.join(dirname, './media') + + expect(await fileExists(path.join(expectedPath, duplicatedDoc.filename))).toBe(true) + }) + }) }) async function fileExists(fileName: string): Promise {