chore: moves file handler into catch all GET rest handler
This commit is contained in:
@@ -1,6 +0,0 @@
|
|||||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
|
||||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
|
||||||
import config from '@payload-config'
|
|
||||||
import { GET_STATIC_FILE } from '@payloadcms/next/routes/index.js'
|
|
||||||
|
|
||||||
export const GET = GET_STATIC_FILE(config)
|
|
||||||
@@ -6,5 +6,3 @@ export {
|
|||||||
PATCH as REST_PATCH,
|
PATCH as REST_PATCH,
|
||||||
POST as REST_POST,
|
POST as REST_POST,
|
||||||
} from './rest/index.js'
|
} from './rest/index.js'
|
||||||
|
|
||||||
export { GET as GET_STATIC_FILE } from './rest/[collection]/file/[filename]/route.js'
|
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
import type { Collection, PayloadRequest, SanitizedConfig, Where } from 'payload/types'
|
|
||||||
|
|
||||||
import fsPromises from 'fs/promises'
|
|
||||||
import httpStatus from 'http-status'
|
|
||||||
import path from 'path'
|
|
||||||
import { executeAccess } from 'payload/auth'
|
|
||||||
import { APIError, Forbidden } from 'payload/errors'
|
|
||||||
|
|
||||||
import { streamFile } from '../../../../../next-stream-file/index.js'
|
|
||||||
import { createPayloadRequest } from '../../../../../utilities/createPayloadRequest.js'
|
|
||||||
import { RouteError } from '../../../RouteError.js'
|
|
||||||
import { endpointsAreDisabled } from '../../../checkEndpoints.js'
|
|
||||||
|
|
||||||
async function checkFileAccess({
|
|
||||||
collection,
|
|
||||||
filename,
|
|
||||||
req,
|
|
||||||
}: {
|
|
||||||
collection: Collection
|
|
||||||
filename: string
|
|
||||||
req: PayloadRequest
|
|
||||||
}) {
|
|
||||||
const { config } = collection
|
|
||||||
const disableEndpoints = endpointsAreDisabled({ endpoints: config.endpoints, request: req })
|
|
||||||
if (disableEndpoints) return disableEndpoints
|
|
||||||
|
|
||||||
const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read)
|
|
||||||
|
|
||||||
if (typeof accessResult === 'object') {
|
|
||||||
const queryToBuild: Where = {
|
|
||||||
and: [
|
|
||||||
{
|
|
||||||
or: [
|
|
||||||
{
|
|
||||||
filename: {
|
|
||||||
equals: filename,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
accessResult,
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.upload.imageSizes) {
|
|
||||||
config.upload.imageSizes.forEach(({ name }) => {
|
|
||||||
queryToBuild.and[0].or.push({
|
|
||||||
[`sizes.${name}.filename`]: {
|
|
||||||
equals: filename,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const doc = await req.payload.db.findOne({
|
|
||||||
collection: config.slug,
|
|
||||||
req,
|
|
||||||
where: queryToBuild,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!doc) {
|
|
||||||
throw new Forbidden(req.t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GET =
|
|
||||||
(config: Promise<SanitizedConfig>) =>
|
|
||||||
async (request: Request, { params }: { params: { collection: string; filename: string } }) => {
|
|
||||||
const { collection: collectionSlug, filename } = params
|
|
||||||
let req: PayloadRequest
|
|
||||||
let collection: Collection
|
|
||||||
|
|
||||||
try {
|
|
||||||
req = await createPayloadRequest({
|
|
||||||
config,
|
|
||||||
params: { collection: collectionSlug },
|
|
||||||
request,
|
|
||||||
})
|
|
||||||
|
|
||||||
collection = req.payload.collections?.[collectionSlug]
|
|
||||||
|
|
||||||
if (!collection) {
|
|
||||||
throw new APIError(`Media collection not found: ${collectionSlug}`, httpStatus.BAD_REQUEST)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!collection.config.upload) {
|
|
||||||
throw new APIError(
|
|
||||||
`This collection is not an upload collection: ${collectionSlug}`,
|
|
||||||
httpStatus.BAD_REQUEST,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collection.config.upload.disableLocalStorage && !collection.config.upload.handlers) {
|
|
||||||
throw new APIError(
|
|
||||||
`This collection has local storage disabled: ${collectionSlug}`,
|
|
||||||
httpStatus.BAD_REQUEST,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
await checkFileAccess({
|
|
||||||
collection,
|
|
||||||
filename,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
|
|
||||||
let response: Response = null
|
|
||||||
if (collection.config.upload.handlers?.length) {
|
|
||||||
for (const handler of collection.config.upload.handlers) {
|
|
||||||
response = await handler(req, { params })
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
|
||||||
const filePath = path.resolve(`${fileDir}/${filename}`)
|
|
||||||
|
|
||||||
const stats = await fsPromises.stat(filePath)
|
|
||||||
const data = streamFile(filePath)
|
|
||||||
|
|
||||||
return new Response(data, {
|
|
||||||
headers: new Headers({
|
|
||||||
'content-length': stats.size + '',
|
|
||||||
}),
|
|
||||||
status: httpStatus.OK,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return RouteError({
|
|
||||||
collection,
|
|
||||||
err: error,
|
|
||||||
req,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
59
packages/next/src/routes/rest/files/checkFileAccess.ts
Normal file
59
packages/next/src/routes/rest/files/checkFileAccess.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import type { Collection, PayloadRequest, Where } from 'payload/types'
|
||||||
|
|
||||||
|
import { executeAccess } from 'payload/auth'
|
||||||
|
import { Forbidden } from 'payload/errors'
|
||||||
|
|
||||||
|
import { endpointsAreDisabled } from '../checkEndpoints.js'
|
||||||
|
|
||||||
|
export async function checkFileAccess({
|
||||||
|
collection,
|
||||||
|
filename,
|
||||||
|
req,
|
||||||
|
}: {
|
||||||
|
collection: Collection
|
||||||
|
filename: string
|
||||||
|
req: PayloadRequest
|
||||||
|
}) {
|
||||||
|
const { config } = collection
|
||||||
|
const disableEndpoints = endpointsAreDisabled({ endpoints: config.endpoints, request: req })
|
||||||
|
if (disableEndpoints) return disableEndpoints
|
||||||
|
|
||||||
|
const accessResult = await executeAccess({ isReadingStaticFile: true, req }, config.access.read)
|
||||||
|
|
||||||
|
if (typeof accessResult === 'object') {
|
||||||
|
const queryToBuild: Where = {
|
||||||
|
and: [
|
||||||
|
{
|
||||||
|
or: [
|
||||||
|
{
|
||||||
|
filename: {
|
||||||
|
equals: filename,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
accessResult,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.upload.imageSizes) {
|
||||||
|
config.upload.imageSizes.forEach(({ name }) => {
|
||||||
|
queryToBuild.and[0].or.push({
|
||||||
|
[`sizes.${name}.filename`]: {
|
||||||
|
equals: filename,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = await req.payload.db.findOne({
|
||||||
|
collection: config.slug,
|
||||||
|
req,
|
||||||
|
where: queryToBuild,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!doc) {
|
||||||
|
throw new Forbidden(req.t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
packages/next/src/routes/rest/files/getFile.ts
Normal file
73
packages/next/src/routes/rest/files/getFile.ts
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import type { Collection, PayloadRequest } from 'payload/types'
|
||||||
|
|
||||||
|
import fsPromises from 'fs/promises'
|
||||||
|
import httpStatus from 'http-status'
|
||||||
|
import path from 'path'
|
||||||
|
import { APIError } from 'payload/errors'
|
||||||
|
|
||||||
|
import { streamFile } from '../../../next-stream-file/index.js'
|
||||||
|
import { RouteError } from '../RouteError.js'
|
||||||
|
import { checkFileAccess } from './checkFileAccess.js'
|
||||||
|
|
||||||
|
// /:collectionSlug/file/:filename
|
||||||
|
type Args = {
|
||||||
|
collection: Collection
|
||||||
|
filename: string
|
||||||
|
req: PayloadRequest
|
||||||
|
}
|
||||||
|
export const getFile = async ({ collection, filename, req }: Args): Promise<Response> => {
|
||||||
|
try {
|
||||||
|
if (!collection.config.upload) {
|
||||||
|
throw new APIError(
|
||||||
|
`This collection is not an upload collection: ${collection.config.slug}`,
|
||||||
|
httpStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (collection.config.upload.disableLocalStorage && !collection.config.upload.handlers) {
|
||||||
|
throw new APIError(
|
||||||
|
`This collection has local storage disabled: ${collection.config.slug}`,
|
||||||
|
httpStatus.BAD_REQUEST,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
await checkFileAccess({
|
||||||
|
collection,
|
||||||
|
filename,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
|
||||||
|
let response: Response = null
|
||||||
|
if (collection.config.upload.handlers?.length) {
|
||||||
|
for (const handler of collection.config.upload.handlers) {
|
||||||
|
response = await handler(req, {
|
||||||
|
params: {
|
||||||
|
collection: collection.config.slug,
|
||||||
|
filename,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileDir = collection.config.upload?.staticDir || collection.config.slug
|
||||||
|
const filePath = path.resolve(`${fileDir}/${filename}`)
|
||||||
|
|
||||||
|
const stats = await fsPromises.stat(filePath)
|
||||||
|
const data = streamFile(filePath)
|
||||||
|
|
||||||
|
return new Response(data, {
|
||||||
|
headers: new Headers({
|
||||||
|
'content-length': stats.size + '',
|
||||||
|
}),
|
||||||
|
status: httpStatus.OK,
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
return RouteError({
|
||||||
|
collection,
|
||||||
|
err: error,
|
||||||
|
req,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ import { findVersions } from './collections/findVersions.js'
|
|||||||
import { restoreVersion } from './collections/restoreVersion.js'
|
import { restoreVersion } from './collections/restoreVersion.js'
|
||||||
import { update } from './collections/update.js'
|
import { update } from './collections/update.js'
|
||||||
import { updateByID } from './collections/updateByID.js'
|
import { updateByID } from './collections/updateByID.js'
|
||||||
|
import { getFile } from './files/getFile.js'
|
||||||
import { docAccess as docAccessGlobal } from './globals/docAccess.js'
|
import { docAccess as docAccessGlobal } from './globals/docAccess.js'
|
||||||
import { findOne } from './globals/findOne.js'
|
import { findOne } from './globals/findOne.js'
|
||||||
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID.js'
|
import { findVersionByID as findVersionByIdGlobal } from './globals/findVersionByID.js'
|
||||||
@@ -55,6 +56,7 @@ const endpoints = {
|
|||||||
'doc-versions-by-id': findVersionByID,
|
'doc-versions-by-id': findVersionByID,
|
||||||
find,
|
find,
|
||||||
findByID,
|
findByID,
|
||||||
|
getFile,
|
||||||
init,
|
init,
|
||||||
me,
|
me,
|
||||||
versions: findVersions,
|
versions: findVersions,
|
||||||
@@ -205,7 +207,10 @@ export const GET =
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
case 3:
|
case 3:
|
||||||
if (`doc-${slug2}-by-id` in endpoints.collection.GET) {
|
if (slug2 === 'file') {
|
||||||
|
// /:collection/file/:filename
|
||||||
|
res = await endpoints.collection.GET.getFile({ collection, filename: slug3, req })
|
||||||
|
} else if (`doc-${slug2}-by-id` in endpoints.collection.GET) {
|
||||||
// /:collection/access/:id
|
// /:collection/access/:id
|
||||||
// /:collection/versions/:id
|
// /:collection/versions/:id
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user