fix(storage-s3, storage-azure, storage-gcs): client uploads when a collection has prefix configured (#11436)
### What? Fixes client uploads when storage collection config has the `prefix` property configured. Previously, it failed with "Object key was not found". ### Why? This is expected to work. ### How? The client upload handler now receives to its props `prefix`. Then it threads it to the server-side `staticHandler` through `clientUploadContext` and then to `getFilePrefix`, which checks for `clientUploadContext.prefix` and returns if there is. Previously, `staticHandler` tried to load the file without including prefix consideration. This changes only these adapters: * S3 * Azure * GCS With the Vercel Blob adapter, `prefix` works correctly.
This commit is contained in:
@@ -10,6 +10,7 @@ type ClientUploadHandlerProps<T extends Record<string, unknown>> = {
|
|||||||
collectionSlug: UploadCollectionSlug
|
collectionSlug: UploadCollectionSlug
|
||||||
enabled?: boolean
|
enabled?: boolean
|
||||||
extra: T
|
extra: T
|
||||||
|
prefix?: string
|
||||||
serverHandlerPath: string
|
serverHandlerPath: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ export const createClientUploadHandler = <T extends Record<string, unknown>>({
|
|||||||
collectionSlug: UploadCollectionSlug
|
collectionSlug: UploadCollectionSlug
|
||||||
extra: T
|
extra: T
|
||||||
file: File
|
file: File
|
||||||
|
prefix?: string
|
||||||
serverHandlerPath: string
|
serverHandlerPath: string
|
||||||
serverURL: string
|
serverURL: string
|
||||||
updateFilename: (value: string) => void
|
updateFilename: (value: string) => void
|
||||||
@@ -31,6 +33,7 @@ export const createClientUploadHandler = <T extends Record<string, unknown>>({
|
|||||||
collectionSlug,
|
collectionSlug,
|
||||||
enabled,
|
enabled,
|
||||||
extra,
|
extra,
|
||||||
|
prefix,
|
||||||
serverHandlerPath,
|
serverHandlerPath,
|
||||||
}: ClientUploadHandlerProps<T>) {
|
}: ClientUploadHandlerProps<T>) {
|
||||||
const { setUploadHandler } = useUploadHandlers()
|
const { setUploadHandler } = useUploadHandlers()
|
||||||
@@ -51,6 +54,7 @@ export const createClientUploadHandler = <T extends Record<string, unknown>>({
|
|||||||
collectionSlug,
|
collectionSlug,
|
||||||
extra,
|
extra,
|
||||||
file,
|
file,
|
||||||
|
prefix,
|
||||||
serverHandlerPath,
|
serverHandlerPath,
|
||||||
serverURL,
|
serverURL,
|
||||||
updateFilename,
|
updateFilename,
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
import type { CollectionConfig, PayloadRequest, UploadConfig } from 'payload'
|
import type { CollectionConfig, PayloadRequest, UploadConfig } from 'payload'
|
||||||
|
|
||||||
export async function getFilePrefix({
|
export async function getFilePrefix({
|
||||||
|
clientUploadContext,
|
||||||
collection,
|
collection,
|
||||||
filename,
|
filename,
|
||||||
req,
|
req,
|
||||||
}: {
|
}: {
|
||||||
|
clientUploadContext?: unknown
|
||||||
collection: CollectionConfig
|
collection: CollectionConfig
|
||||||
filename: string
|
filename: string
|
||||||
req: PayloadRequest
|
req: PayloadRequest
|
||||||
}): Promise<string> {
|
}): Promise<string> {
|
||||||
|
// Prioritize from clientUploadContext if there is:
|
||||||
|
if (
|
||||||
|
clientUploadContext &&
|
||||||
|
typeof clientUploadContext === 'object' &&
|
||||||
|
'prefix' in clientUploadContext &&
|
||||||
|
typeof clientUploadContext.prefix === 'string'
|
||||||
|
) {
|
||||||
|
return clientUploadContext.prefix
|
||||||
|
}
|
||||||
|
|
||||||
const imageSizes = (collection?.upload as UploadConfig)?.imageSizes || []
|
const imageSizes = (collection?.upload as UploadConfig)?.imageSizes || []
|
||||||
|
|
||||||
const files = await req.payload.find({
|
const files = await req.payload.find({
|
||||||
|
|||||||
@@ -63,11 +63,23 @@ export const initClientUploads = <ExtraProps extends Record<string, unknown>, T>
|
|||||||
for (const collectionSlug in collections) {
|
for (const collectionSlug in collections) {
|
||||||
const collection = collections[collectionSlug]
|
const collection = collections[collectionSlug]
|
||||||
|
|
||||||
|
let prefix: string | undefined
|
||||||
|
|
||||||
|
if (
|
||||||
|
collection &&
|
||||||
|
typeof collection === 'object' &&
|
||||||
|
'prefix' in collection &&
|
||||||
|
typeof collection.prefix === 'string'
|
||||||
|
) {
|
||||||
|
prefix = collection.prefix
|
||||||
|
}
|
||||||
|
|
||||||
config.admin.components.providers.push({
|
config.admin.components.providers.push({
|
||||||
clientProps: {
|
clientProps: {
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
enabled,
|
enabled,
|
||||||
extra: extraClientHandlerProps ? extraClientHandlerProps(collection) : undefined,
|
extra: extraClientHandlerProps ? extraClientHandlerProps(collection) : undefined,
|
||||||
|
prefix,
|
||||||
serverHandlerPath,
|
serverHandlerPath,
|
||||||
},
|
},
|
||||||
path: clientHandler,
|
path: clientHandler,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
||||||
|
|
||||||
export const AzureClientUploadHandler = createClientUploadHandler({
|
export const AzureClientUploadHandler = createClientUploadHandler({
|
||||||
handler: async ({ apiRoute, collectionSlug, file, serverHandlerPath, serverURL }) => {
|
handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => {
|
||||||
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
@@ -25,5 +25,7 @@ export const AzureClientUploadHandler = createClientUploadHandler({
|
|||||||
},
|
},
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return { prefix }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ interface Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getHandler = ({ collection, getStorageClient }: Args): StaticHandler => {
|
export const getHandler = ({ collection, getStorageClient }: Args): StaticHandler => {
|
||||||
return async (req, { params: { filename } }) => {
|
return async (req, { params: { clientUploadContext, filename } }) => {
|
||||||
try {
|
try {
|
||||||
const prefix = await getFilePrefix({ collection, filename, req })
|
const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })
|
||||||
const blockBlobClient = getStorageClient().getBlockBlobClient(
|
const blockBlobClient = getStorageClient().getBlockBlobClient(
|
||||||
path.posix.join(prefix, filename),
|
path.posix.join(prefix, filename),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
||||||
|
|
||||||
export const GcsClientUploadHandler = createClientUploadHandler({
|
export const GcsClientUploadHandler = createClientUploadHandler({
|
||||||
handler: async ({ apiRoute, collectionSlug, file, serverHandlerPath, serverURL }) => {
|
handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => {
|
||||||
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
@@ -20,5 +20,9 @@ export const GcsClientUploadHandler = createClientUploadHandler({
|
|||||||
headers: { 'Content-Length': file.size.toString(), 'Content-Type': file.type },
|
headers: { 'Content-Length': file.size.toString(), 'Content-Type': file.type },
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
prefix,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ interface Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
||||||
return async (req, { params: { filename } }) => {
|
return async (req, { params: { clientUploadContext, filename } }) => {
|
||||||
try {
|
try {
|
||||||
const prefix = await getFilePrefix({ collection, filename, req })
|
const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })
|
||||||
const file = getStorageClient().bucket(bucket).file(path.posix.join(prefix, filename))
|
const file = getStorageClient().bucket(bucket).file(path.posix.join(prefix, filename))
|
||||||
|
|
||||||
const [metadata] = await file.getMetadata()
|
const [metadata] = await file.getMetadata()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
import { createClientUploadHandler } from '@payloadcms/plugin-cloud-storage/client'
|
||||||
|
|
||||||
export const S3ClientUploadHandler = createClientUploadHandler({
|
export const S3ClientUploadHandler = createClientUploadHandler({
|
||||||
handler: async ({ apiRoute, collectionSlug, file, serverHandlerPath, serverURL }) => {
|
handler: async ({ apiRoute, collectionSlug, file, prefix, serverHandlerPath, serverURL }) => {
|
||||||
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
const response = await fetch(`${serverURL}${apiRoute}${serverHandlerPath}`, {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
collectionSlug,
|
collectionSlug,
|
||||||
@@ -20,5 +20,7 @@ export const S3ClientUploadHandler = createClientUploadHandler({
|
|||||||
headers: { 'Content-Length': file.size.toString(), 'Content-Type': file.type },
|
headers: { 'Content-Length': file.size.toString(), 'Content-Type': file.type },
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return { prefix }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ const streamToBuffer = async (readableStream: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
export const getHandler = ({ bucket, collection, getStorageClient }: Args): StaticHandler => {
|
||||||
return async (req, { params: { filename } }) => {
|
return async (req, { params: { clientUploadContext, filename } }) => {
|
||||||
try {
|
try {
|
||||||
const prefix = await getFilePrefix({ collection, filename, req })
|
const prefix = await getFilePrefix({ clientUploadContext, collection, filename, req })
|
||||||
|
|
||||||
const key = path.posix.join(prefix, filename)
|
const key = path.posix.join(prefix, filename)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user