fix: correctly fetches externally stored files when passing uploadEdits (#4505)

This commit is contained in:
Jarrod Flesch
2023-12-14 09:09:37 -05:00
committed by GitHub
parent cc0ba89518
commit 228d45cf52
5 changed files with 63 additions and 31 deletions

View File

@@ -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) {

View 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)
}

View File

@@ -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

View File

@@ -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

View File

@@ -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: {