fix: correctly fetches externally stored files when passing uploadEdits (#4505)
This commit is contained in:
@@ -17,7 +17,7 @@ import { FileUploadError, MissingFile } from '../errors'
|
|||||||
import canResizeImage from './canResizeImage'
|
import canResizeImage from './canResizeImage'
|
||||||
import cropImage from './cropImage'
|
import cropImage from './cropImage'
|
||||||
import getFileByPath from './getFileByPath'
|
import getFileByPath from './getFileByPath'
|
||||||
import getFileByURL from './getFileByURL'
|
import { getExternalFile } from './getExternalFile'
|
||||||
import getImageSize from './getImageSize'
|
import getImageSize from './getImageSize'
|
||||||
import getSafeFileName from './getSafeFilename'
|
import getSafeFileName from './getSafeFilename'
|
||||||
import resizeAndTransformImageSizes from './imageResizer'
|
import resizeAndTransformImageSizes from './imageResizer'
|
||||||
@@ -72,9 +72,8 @@ export const generateFileData = async <T>({
|
|||||||
const response = await getFileByPath(filePath)
|
const response = await getFileByPath(filePath)
|
||||||
file = response as UploadedFile
|
file = response as UploadedFile
|
||||||
overwriteExistingFiles = true
|
overwriteExistingFiles = true
|
||||||
} else {
|
} else if (filename && url) {
|
||||||
const response = await getFileByURL(url)
|
file = (await getExternalFile({ req, data: data as FileData })) as UploadedFile
|
||||||
file = response as UploadedFile
|
|
||||||
overwriteExistingFiles = true
|
overwriteExistingFiles = true
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
38
packages/payload/src/uploads/getExternalFile.ts
Normal file
38
packages/payload/src/uploads/getExternalFile.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import type { File, FileData } from './types'
|
||||||
|
import { Request } from 'express'
|
||||||
|
import { APIError } from '../errors'
|
||||||
|
|
||||||
|
type Args = {
|
||||||
|
req: Request
|
||||||
|
data: FileData
|
||||||
|
}
|
||||||
|
export const getExternalFile = async ({ req, data }: Args): Promise<File> => {
|
||||||
|
const baseUrl = req.get('origin') || `${req.protocol}://${req.get('host')}`
|
||||||
|
const { url, filename } = data
|
||||||
|
|
||||||
|
if (typeof url === 'string') {
|
||||||
|
const fileURL = `${baseUrl}${url}`
|
||||||
|
const { default: fetch } = (await import('node-fetch')) as any
|
||||||
|
|
||||||
|
const res = await fetch(fileURL, {
|
||||||
|
credentials: 'include',
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
...req.headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!res.ok) throw new APIError(`Failed to fetch file from ${fileURL}`, res.status)
|
||||||
|
|
||||||
|
const data = await res.buffer()
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: filename,
|
||||||
|
data,
|
||||||
|
mimetype: res.headers.get('content-type') || undefined,
|
||||||
|
size: Number(res.headers.get('content-length')) || 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new APIError('Invalid file url', 400)
|
||||||
|
}
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import path from 'path'
|
|
||||||
|
|
||||||
import type { File } from './types'
|
|
||||||
|
|
||||||
const getFileByURL = async (url: string): Promise<File> => {
|
|
||||||
if (typeof url === 'string') {
|
|
||||||
const { default: fetch } = (await import('node-fetch')) as any
|
|
||||||
|
|
||||||
const res = await fetch(url, {
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'GET',
|
|
||||||
})
|
|
||||||
const data = await res.buffer()
|
|
||||||
const name = path.basename(url)
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
data,
|
|
||||||
mimetype: res.headers.get('content-type') || undefined,
|
|
||||||
size: Number(res.headers.get('content-length')) || 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getFileByURL
|
|
||||||
@@ -20,4 +20,11 @@ GCS_ENDPOINT=http://localhost:4443
|
|||||||
GCS_PROJECT_ID=test
|
GCS_PROJECT_ID=test
|
||||||
GCS_BUCKET=payload-bucket
|
GCS_BUCKET=payload-bucket
|
||||||
|
|
||||||
|
R2_ENDPOINT=https://cloudflare-generated-domain.r2.cloudflarestorage.com
|
||||||
|
R2_REGION=auto
|
||||||
|
R2_ACCESS_KEY_ID=access-key-id
|
||||||
|
R2_SECRET_ACCESS_KEY=secret-access-key
|
||||||
|
R2_BUCKET=payload-bucket
|
||||||
|
R2_FORCE_PATH_STYLE=
|
||||||
|
|
||||||
PAYLOAD_DROP_DATABASE=true
|
PAYLOAD_DROP_DATABASE=true
|
||||||
|
|||||||
@@ -51,6 +51,21 @@ if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 's3') {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 'r2') {
|
||||||
|
adapter = s3Adapter({
|
||||||
|
config: {
|
||||||
|
endpoint: process.env.R2_ENDPOINT,
|
||||||
|
forcePathStyle: process.env.R2_FORCE_PATH_STYLE === 'true',
|
||||||
|
region: process.env.R2_REGION,
|
||||||
|
credentials: {
|
||||||
|
accessKeyId: process.env.R2_ACCESS_KEY_ID,
|
||||||
|
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bucket: process.env.R2_BUCKET,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 'gcs') {
|
if (process.env.PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER === 'gcs') {
|
||||||
adapter = gcsAdapter({
|
adapter = gcsAdapter({
|
||||||
options: {
|
options: {
|
||||||
|
|||||||
Reference in New Issue
Block a user