feat: collection, global and field props for hooks, fix request context initialization, add context to global hooks (#3780)
* feat: pass collection, global and field props to collection, global and field hooks - where applicable * fix: initial request context not set for all operations * chore: add tests which check the collection prop for collection hooks * feat: add context to props of global hooks * chore: add global tests for global and field props * chore: int tests: use JSON instead of object hashes
This commit is contained in:
@@ -62,7 +62,7 @@ All field-level hooks are formatted to accept the same arguments, although some
|
||||
Field Hooks receive one `args` argument that contains the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`data`** | The data passed to update the document within `create` and `update` operations, and the full document itself in the `afterRead` hook. |
|
||||
| **`siblingData`** | The sibling data passed to a field that the hook is running against. |
|
||||
| **`findMany`** | Boolean to denote if this hook is running against finding one, or finding many within the `afterRead` hook. |
|
||||
@@ -73,6 +73,10 @@ Field Hooks receive one `args` argument that contains the following properties:
|
||||
| **`req`** | The Express `request` object. It is mocked for Local API operations. |
|
||||
| **`value`** | The value of the field. |
|
||||
| **`previousValue`** | The previous value of the field, before changes were applied, only in `afterChange` hooks. |
|
||||
| **`context`** | Context passed to this hook. More info can be found under [Context](/docs/hooks/context) |
|
||||
| **`field`** | The field which the hook is running against. |
|
||||
| **`collection`** | The collection which the field belongs to. If the field belongs to a global, this will be null. |
|
||||
| **`global`** | The global which the field belongs to. If the field belongs to a collection, this will be null. |
|
||||
|
||||
#### Return value
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
||||
|
||||
if (typeof collection.admin.hooks?.beforeDuplicate === 'function') {
|
||||
data = await collection.admin.hooks.beforeDuplicate({
|
||||
collection,
|
||||
data,
|
||||
locale,
|
||||
})
|
||||
@@ -108,6 +109,7 @@ const Duplicate: React.FC<Props> = ({ id, collection, slug }) => {
|
||||
|
||||
if (typeof collection.admin.hooks?.beforeDuplicate === 'function') {
|
||||
localizedDoc = await collection.admin.hooks.beforeDuplicate({
|
||||
collection,
|
||||
data: localizedDoc,
|
||||
locale,
|
||||
})
|
||||
|
||||
@@ -38,6 +38,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
operation: 'forgotPassword',
|
||||
})) || args
|
||||
@@ -139,7 +140,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
||||
|
||||
await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook, hook) => {
|
||||
await priorHook
|
||||
await hook({ args, context: req.context })
|
||||
await hook({ args, collection: args.collection?.config, context: req.context })
|
||||
}, Promise.resolve())
|
||||
|
||||
// /////////////////////////////////////
|
||||
@@ -148,6 +149,7 @@ async function forgotPassword(incomingArgs: Arguments): Promise<null | string> {
|
||||
|
||||
token = await buildAfterOperation({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
operation: 'forgotPassword',
|
||||
result: token,
|
||||
})
|
||||
|
||||
@@ -30,7 +30,7 @@ async function localForgotPassword<T extends keyof GeneratedTypes['collections']
|
||||
expiration,
|
||||
req = {} as PayloadRequest,
|
||||
} = options
|
||||
setRequestContext(options.req)
|
||||
setRequestContext(req)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ async function localLogin<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
res,
|
||||
showHiddenFields,
|
||||
} = options
|
||||
setRequestContext(options.req)
|
||||
setRequestContext(req)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ async function localResetPassword<T extends keyof GeneratedTypes['collections']>
|
||||
options: Options<T>,
|
||||
): Promise<Result> {
|
||||
const { collection: collectionSlug, data, overrideAccess, req = {} as PayloadRequest } = options
|
||||
setRequestContext(options.req)
|
||||
|
||||
setRequestContext(req)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ async function localUnlock<T extends keyof GeneratedTypes['collections']>(
|
||||
overrideAccess = true,
|
||||
req = {} as PayloadRequest,
|
||||
} = options
|
||||
setRequestContext(options.req)
|
||||
setRequestContext(req)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ async function localVerifyEmail<T extends keyof GeneratedTypes['collections']>(
|
||||
options: Options<T>,
|
||||
): Promise<boolean> {
|
||||
const { collection: collectionSlug, req = {} as PayloadRequest, token } = options
|
||||
setRequestContext(options.req)
|
||||
setRequestContext(req)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
operation: 'login',
|
||||
})) || args
|
||||
@@ -138,6 +139,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
user =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
req: args.req,
|
||||
user,
|
||||
@@ -175,6 +177,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
user =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
req: args.req,
|
||||
token,
|
||||
@@ -187,10 +190,11 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
user = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: user,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -205,6 +209,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
user =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: req.context,
|
||||
doc: user,
|
||||
req,
|
||||
@@ -220,6 +225,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
user =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: req.context,
|
||||
doc: user,
|
||||
req,
|
||||
@@ -238,6 +244,7 @@ async function login<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
operation: 'login',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -46,6 +46,7 @@ async function logout(incomingArgs: Arguments): Promise<string> {
|
||||
|
||||
args =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: req.context,
|
||||
req,
|
||||
res,
|
||||
|
||||
@@ -69,6 +69,7 @@ async function me({ collection, req }: Arguments): Promise<Result> {
|
||||
|
||||
response =
|
||||
(await hook({
|
||||
collection: collection?.config,
|
||||
context: req.context,
|
||||
req,
|
||||
response,
|
||||
|
||||
@@ -39,6 +39,7 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
operation: 'refresh',
|
||||
})) || args
|
||||
@@ -112,6 +113,7 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: args.collection?.config,
|
||||
context: args.req.context,
|
||||
exp,
|
||||
req: args.req,
|
||||
@@ -126,6 +128,7 @@ async function refresh(incomingArgs: Arguments): Promise<Result> {
|
||||
|
||||
result = await buildAfterOperation({
|
||||
args,
|
||||
collection: args.collection?.config,
|
||||
operation: 'refresh',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -41,6 +41,8 @@ type CreateOrUpdateOperation = Extract<HookOperationType, 'create' | 'update'>
|
||||
|
||||
export type BeforeOperationHook = (args: {
|
||||
args?: any
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
/**
|
||||
* Hook operation being performed
|
||||
@@ -49,6 +51,8 @@ export type BeforeOperationHook = (args: {
|
||||
}) => any
|
||||
|
||||
export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
data?: Partial<T>
|
||||
/**
|
||||
@@ -65,6 +69,8 @@ export type BeforeValidateHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
data: Partial<T>
|
||||
/**
|
||||
@@ -81,6 +87,8 @@ export type BeforeChangeHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
doc: T
|
||||
/**
|
||||
@@ -92,6 +100,8 @@ export type AfterChangeHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type BeforeReadHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
doc: T
|
||||
query: { [key: string]: any }
|
||||
@@ -99,6 +109,8 @@ export type BeforeReadHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type AfterReadHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
doc: T
|
||||
findMany?: boolean
|
||||
@@ -107,12 +119,16 @@ export type AfterReadHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type BeforeDeleteHook = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
id: number | string
|
||||
req: PayloadRequest
|
||||
}) => any
|
||||
|
||||
export type AfterDeleteHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
doc: T
|
||||
id: number | string
|
||||
@@ -127,15 +143,21 @@ export type AfterErrorHook = (
|
||||
err: Error,
|
||||
res: unknown,
|
||||
context: RequestContext,
|
||||
/** The collection which this hook is being run on. This is null if the AfterError hook was be added to the payload-wide config */
|
||||
collection: SanitizedCollectionConfig | null,
|
||||
) => { response: any; status: number } | void
|
||||
|
||||
export type BeforeLoginHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
req: PayloadRequest
|
||||
user: T
|
||||
}) => any
|
||||
|
||||
export type AfterLoginHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
req: PayloadRequest
|
||||
token: string
|
||||
@@ -143,18 +165,24 @@ export type AfterLoginHook<T extends TypeWithID = any> = (args: {
|
||||
}) => any
|
||||
|
||||
export type AfterLogoutHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
req: PayloadRequest
|
||||
res: Response
|
||||
}) => any
|
||||
|
||||
export type AfterMeHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
req: PayloadRequest
|
||||
response: unknown
|
||||
}) => any
|
||||
|
||||
export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
exp: number
|
||||
req: PayloadRequest
|
||||
@@ -162,9 +190,16 @@ export type AfterRefreshHook<T extends TypeWithID = any> = (args: {
|
||||
token: string
|
||||
}) => any
|
||||
|
||||
export type AfterForgotPasswordHook = (args: { args?: any; context: RequestContext }) => any
|
||||
export type AfterForgotPasswordHook = (args: {
|
||||
args?: any
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
context: RequestContext
|
||||
}) => any
|
||||
|
||||
type BeforeDuplicateArgs<T> = {
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
data: T
|
||||
locale?: string
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'create',
|
||||
})) || args
|
||||
@@ -139,10 +140,11 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
data = await beforeValidate({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: {},
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'create',
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -158,6 +160,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'create',
|
||||
@@ -184,6 +187,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'create',
|
||||
@@ -196,11 +200,12 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
const resultWithLocales = await beforeChange<Record<string, unknown>>({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: {},
|
||||
docWithLocales: {},
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'create',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft,
|
||||
@@ -293,10 +298,11 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -311,6 +317,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -322,10 +329,11 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'create',
|
||||
previousDoc: {},
|
||||
req,
|
||||
@@ -353,6 +361,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
operation: 'create',
|
||||
@@ -369,6 +378,7 @@ async function create<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'create',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -49,6 +49,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'delete',
|
||||
})) || args
|
||||
@@ -126,6 +127,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
|
||||
return hook({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
req,
|
||||
})
|
||||
@@ -171,10 +173,11 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result || doc,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -189,6 +192,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result || doc,
|
||||
req,
|
||||
@@ -205,6 +209,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
result =
|
||||
(await hook({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -249,6 +254,7 @@ async function deleteOperation<TSlug extends keyof GeneratedTypes['collections']
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'delete',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -40,6 +40,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'delete',
|
||||
})) || args
|
||||
@@ -82,6 +83,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
return hook({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
req,
|
||||
})
|
||||
@@ -148,10 +150,11 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -166,6 +169,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -182,6 +186,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
result =
|
||||
(await hook({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -194,6 +199,7 @@ async function deleteByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'deleteByID',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -46,6 +46,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'read',
|
||||
})) || args
|
||||
@@ -166,6 +167,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
|
||||
docRef =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: docRef,
|
||||
query: fullWhere,
|
||||
@@ -187,12 +189,13 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
docs: await Promise.all(
|
||||
result.docs.map(async (doc) =>
|
||||
afterRead<T>({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
currentDepth,
|
||||
depth,
|
||||
doc,
|
||||
entityConfig: collectionConfig,
|
||||
findMany: true,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -216,6 +219,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
|
||||
docRef =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: docRef,
|
||||
findMany: true,
|
||||
@@ -235,6 +239,7 @@ async function find<T extends TypeWithID & Record<string, unknown>>(
|
||||
|
||||
result = await buildAfterOperation<T>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'find',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -39,6 +39,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'read',
|
||||
})) || args
|
||||
@@ -138,6 +139,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
query: findOneArgs.where,
|
||||
@@ -150,11 +152,12 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
currentDepth,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -169,6 +172,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
query: findOneArgs.where,
|
||||
@@ -182,6 +186,7 @@ async function findByID<T extends TypeWithID>(incomingArgs: Arguments): Promise<
|
||||
|
||||
result = await buildAfterOperation<T>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'findByID',
|
||||
result: result as any,
|
||||
}) // TODO: fix this typing
|
||||
|
||||
@@ -93,6 +93,7 @@ async function findVersionByID<T extends TypeWithID = any>(
|
||||
|
||||
result.version =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result.version,
|
||||
query: fullWhere,
|
||||
@@ -105,11 +106,12 @@ async function findVersionByID<T extends TypeWithID = any>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result.version = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
currentDepth,
|
||||
depth,
|
||||
doc: result.version,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -124,6 +126,7 @@ async function findVersionByID<T extends TypeWithID = any>(
|
||||
|
||||
result.version =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result.version,
|
||||
query: fullWhere,
|
||||
|
||||
@@ -94,6 +94,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
|
||||
docRef.version =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: docRef.version,
|
||||
query: fullWhere,
|
||||
@@ -116,11 +117,12 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
result.docs.map(async (data) => ({
|
||||
...data,
|
||||
version: await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: data.version,
|
||||
entityConfig: collectionConfig,
|
||||
findMany: true,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -144,6 +146,7 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
|
||||
docRef.version =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: doc.version,
|
||||
findMany: true,
|
||||
|
||||
@@ -56,7 +56,7 @@ export default async function findLocal<T extends keyof GeneratedTypes['collecti
|
||||
user,
|
||||
where,
|
||||
} = options
|
||||
setRequestContext(options.req, context)
|
||||
setRequestContext(req, context)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
const defaultLocale = payload?.config?.localization
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function findByIDLocal<T extends keyof GeneratedTypes['coll
|
||||
showHiddenFields,
|
||||
user,
|
||||
} = options
|
||||
setRequestContext(options.req, context)
|
||||
setRequestContext(req, context)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
const defaultLocale = payload?.config?.localization
|
||||
|
||||
@@ -44,7 +44,7 @@ export default async function findVersionByIDLocal<T extends keyof GeneratedType
|
||||
req = {} as PayloadRequest,
|
||||
showHiddenFields,
|
||||
} = options
|
||||
setRequestContext(options.req, context)
|
||||
setRequestContext(req, context)
|
||||
|
||||
const collection = payload.collections[collectionSlug]
|
||||
const defaultLocale = payload?.config?.localization
|
||||
|
||||
@@ -135,10 +135,11 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -153,6 +154,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -164,10 +166,11 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data: result,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
previousDoc: prevDocWithLocales,
|
||||
req,
|
||||
@@ -182,6 +185,7 @@ async function restoreVersion<T extends TypeWithID = any>(args: Arguments): Prom
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
operation: 'update',
|
||||
|
||||
@@ -56,6 +56,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'update',
|
||||
})) || args
|
||||
@@ -169,10 +170,11 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
try {
|
||||
const originalDoc = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth: 0,
|
||||
doc,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
showHiddenFields: true,
|
||||
@@ -193,10 +195,11 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data = await beforeValidate<DeepPartial<GeneratedTypes['collections'][TSlug]>>({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -211,6 +214,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
@@ -236,6 +240,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
@@ -250,11 +255,12 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
let result = await beforeChange<GeneratedTypes['collections'][TSlug]>({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
docWithLocales: doc,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||
@@ -297,10 +303,11 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -315,6 +322,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -326,10 +334,11 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange<GeneratedTypes['collections'][TSlug]>({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
@@ -344,6 +353,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
operation: 'update',
|
||||
@@ -385,6 +395,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'update',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -55,6 +55,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
args =
|
||||
(await hook({
|
||||
args,
|
||||
collection: args.collection.config,
|
||||
context: args.req.context,
|
||||
operation: 'update',
|
||||
})) || args
|
||||
@@ -123,10 +124,11 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
if (!docWithLocales && hasWherePolicy) throw new Forbidden(t)
|
||||
|
||||
const originalDoc = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth: 0,
|
||||
doc: docWithLocales,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
showHiddenFields: true,
|
||||
@@ -166,10 +168,11 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data = await beforeValidate<DeepPartial<GeneratedTypes['collections'][TSlug]>>({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -184,6 +187,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
@@ -209,6 +213,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
operation: 'update',
|
||||
@@ -223,11 +228,12 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
let result = await beforeChange<GeneratedTypes['collections'][TSlug]>({
|
||||
id,
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
docWithLocales,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft || data._status === 'draft',
|
||||
@@ -285,10 +291,11 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -303,6 +310,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
req,
|
||||
@@ -314,10 +322,11 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange<GeneratedTypes['collections'][TSlug]>({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: result,
|
||||
entityConfig: collectionConfig,
|
||||
global: null,
|
||||
operation: 'update',
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
@@ -332,6 +341,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
collection: collectionConfig,
|
||||
context: req.context,
|
||||
doc: result,
|
||||
operation: 'update',
|
||||
@@ -346,6 +356,7 @@ async function updateByID<TSlug extends keyof GeneratedTypes['collections']>(
|
||||
|
||||
result = await buildAfterOperation<GeneratedTypes['collections'][TSlug]>({
|
||||
args,
|
||||
collection: collectionConfig,
|
||||
operation: 'updateByID',
|
||||
result,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type forgotPassword from '../../auth/operations/forgotPassword'
|
||||
import type login from '../../auth/operations/login'
|
||||
import type refresh from '../../auth/operations/refresh'
|
||||
import type { AfterOperationHook, TypeWithID } from '../config/types'
|
||||
import type { AfterOperationHook, SanitizedCollectionConfig, TypeWithID } from '../config/types'
|
||||
import type create from './create'
|
||||
import type deleteOperation from './delete'
|
||||
import type deleteByID from './deleteByID'
|
||||
@@ -25,51 +25,71 @@ export type AfterOperationMap<T extends TypeWithID> = {
|
||||
export type AfterOperationArg<T extends TypeWithID> =
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['create']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'create'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['create']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['delete']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'delete'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['delete']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['deleteByID']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'deleteByID'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['deleteByID']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['find']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'find'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['find']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['findByID']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'findByID'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['findByID']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['forgotPassword']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'forgotPassword'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['forgotPassword']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['login']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'login'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['login']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['refresh']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'refresh'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['refresh']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['update']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'update'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['update']>>
|
||||
}
|
||||
| {
|
||||
args: Parameters<AfterOperationMap<T>['updateByID']>[0]
|
||||
/** The collection which this hook is being run on */
|
||||
collection: SanitizedCollectionConfig
|
||||
operation: 'updateByID'
|
||||
result: Awaited<ReturnType<AfterOperationMap<T>['updateByID']>>
|
||||
}
|
||||
@@ -82,7 +102,7 @@ export const buildAfterOperation = async <
|
||||
>(
|
||||
operationArgs: AfterOperationArg<T> & { operation: O },
|
||||
): Promise<Awaited<ReturnType<AfterOperationMap<T>[O]>>> => {
|
||||
const { args, operation, result } = operationArgs
|
||||
const { args, collection, operation, result } = operationArgs
|
||||
|
||||
let newResult = result
|
||||
|
||||
@@ -92,6 +112,7 @@ export const buildAfterOperation = async <
|
||||
|
||||
const hookResult = await hook({
|
||||
args,
|
||||
collection,
|
||||
operation,
|
||||
result: newResult,
|
||||
} as AfterOperationArg<T>)
|
||||
|
||||
@@ -47,11 +47,17 @@ const errorHandler =
|
||||
err,
|
||||
response,
|
||||
req.context,
|
||||
req.collection.config,
|
||||
)) || { response, status })
|
||||
}
|
||||
|
||||
if (typeof config.hooks.afterError === 'function') {
|
||||
;({ response, status } = (await config.hooks.afterError(err, response, req.context)) || {
|
||||
;({ response, status } = (await config.hooks.afterError(
|
||||
err,
|
||||
response,
|
||||
req.context,
|
||||
req.collection.config,
|
||||
)) || {
|
||||
response,
|
||||
status,
|
||||
})
|
||||
|
||||
@@ -9,18 +9,25 @@ import type { Description } from '../../admin/components/forms/FieldDescription/
|
||||
import type { RowLabel } from '../../admin/components/forms/RowLabel/types'
|
||||
import type { RichTextAdapter } from '../../admin/components/forms/field-types/RichText/types'
|
||||
import type { User } from '../../auth'
|
||||
import type { TypeWithID } from '../../collections/config/types'
|
||||
import type { SanitizedCollectionConfig, TypeWithID } from '../../collections/config/types'
|
||||
import type { SanitizedConfig } from '../../config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../globals/config/types'
|
||||
import type { Payload } from '../../payload'
|
||||
import type { Operation, Where } from '../../types'
|
||||
|
||||
export type FieldHookArgs<T extends TypeWithID = any, P = any, S = any> = {
|
||||
/** The collection which the field belongs to. If the field belongs to a global, this will be null. */
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
/** The data passed to update the document within create and update operations, and the full document itself in the afterRead hook. */
|
||||
data?: Partial<T>
|
||||
/** The field which the hook is running against. */
|
||||
field: FieldAffectingData
|
||||
/** Boolean to denote if this hook is running against finding one, or finding many within the afterRead hook. */
|
||||
findMany?: boolean
|
||||
/** The global which the field belongs to. If the field belongs to a collection, this will be null. */
|
||||
global: SanitizedGlobalConfig | null
|
||||
/** A string relating to which operation the field type is currently executing within. Useful within beforeValidate, beforeChange, and afterChange hooks to differentiate between create and update operations. */
|
||||
operation?: 'create' | 'delete' | 'read' | 'update'
|
||||
/** The full original document in `update` operations. In the `afterChange` hook, this is the resulting document of the operation. */
|
||||
|
||||
@@ -6,20 +6,23 @@ import { deepCopyObject } from '../../../utilities/deepCopyObject'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args<T> = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown> | T
|
||||
doc: Record<string, unknown> | T
|
||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
global: SanitizedGlobalConfig | null
|
||||
operation: 'create' | 'update'
|
||||
previousDoc: Record<string, unknown> | T
|
||||
req: PayloadRequest
|
||||
}
|
||||
|
||||
export const afterChange = async <T extends Record<string, unknown>>({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
|
||||
doc: incomingDoc,
|
||||
entityConfig,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
req,
|
||||
@@ -27,10 +30,12 @@ export const afterChange = async <T extends Record<string, unknown>>({
|
||||
const doc = deepCopyObject(incomingDoc)
|
||||
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: entityConfig.fields,
|
||||
fields: collection?.fields || global?.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: previousDoc,
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { fieldAffectsData, tabHasName } from '../../config/types'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown>
|
||||
doc: Record<string, unknown>
|
||||
field: Field | TabAsField
|
||||
global: SanitizedGlobalConfig | null
|
||||
operation: 'create' | 'update'
|
||||
previousDoc: Record<string, unknown>
|
||||
previousSiblingDoc: Record<string, unknown>
|
||||
@@ -22,10 +26,12 @@ type Args = {
|
||||
// - Execute field hooks
|
||||
|
||||
export const promise = async ({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc,
|
||||
@@ -40,8 +46,11 @@ export const promise = async ({
|
||||
await priorHook
|
||||
|
||||
const hookedValue = await currentHook({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
originalDoc: doc,
|
||||
previousDoc,
|
||||
@@ -63,10 +72,12 @@ export const promise = async ({
|
||||
switch (field.type) {
|
||||
case 'group': {
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: previousDoc[field.name] as Record<string, unknown>,
|
||||
@@ -86,10 +97,12 @@ export const promise = async ({
|
||||
rows.forEach((row, i) => {
|
||||
promises.push(
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: previousDoc?.[field.name]?.[i] || ({} as Record<string, unknown>),
|
||||
@@ -115,10 +128,12 @@ export const promise = async ({
|
||||
if (block) {
|
||||
promises.push(
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: block.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc:
|
||||
@@ -139,10 +154,12 @@ export const promise = async ({
|
||||
case 'row':
|
||||
case 'collapsible': {
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: { ...previousSiblingDoc },
|
||||
@@ -166,10 +183,12 @@ export const promise = async ({
|
||||
}
|
||||
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: tabPreviousSiblingDoc,
|
||||
@@ -183,10 +202,12 @@ export const promise = async ({
|
||||
|
||||
case 'tabs': {
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc: { ...previousSiblingDoc },
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { promise } from './promise'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown>
|
||||
doc: Record<string, unknown>
|
||||
fields: (Field | TabAsField)[]
|
||||
global: SanitizedGlobalConfig | null
|
||||
operation: 'create' | 'update'
|
||||
previousDoc: Record<string, unknown>
|
||||
previousSiblingDoc: Record<string, unknown>
|
||||
@@ -17,10 +21,12 @@ type Args = {
|
||||
}
|
||||
|
||||
export const traverseFields = async ({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc,
|
||||
@@ -33,10 +39,12 @@ export const traverseFields = async ({
|
||||
fields.forEach((field) => {
|
||||
promises.push(
|
||||
promise({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
previousDoc,
|
||||
previousSiblingDoc,
|
||||
|
||||
@@ -6,13 +6,14 @@ import { deepCopyObject } from '../../../utilities/deepCopyObject'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
currentDepth?: number
|
||||
depth: number
|
||||
doc: Record<string, unknown>
|
||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
findMany?: boolean
|
||||
flattenLocales?: boolean
|
||||
global: SanitizedGlobalConfig | null
|
||||
overrideAccess: boolean
|
||||
req: PayloadRequest
|
||||
showHiddenFields: boolean
|
||||
@@ -20,13 +21,14 @@ type Args = {
|
||||
|
||||
export async function afterRead<T = any>(args: Args): Promise<T> {
|
||||
const {
|
||||
collection,
|
||||
context,
|
||||
currentDepth: incomingCurrentDepth,
|
||||
depth: incomingDepth,
|
||||
doc: incomingDoc,
|
||||
entityConfig,
|
||||
findMany,
|
||||
flattenLocales = true,
|
||||
global,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -45,14 +47,16 @@ export async function afterRead<T = any>(args: Args): Promise<T> {
|
||||
const currentDepth = incomingCurrentDepth || 1
|
||||
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
doc,
|
||||
fieldPromises,
|
||||
fields: entityConfig.fields,
|
||||
fields: collection?.fields || global?.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { RichTextAdapter } from '../../../admin/components/forms/field-types/RichText/types'
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { fieldAffectsData, tabHasName } from '../../config/types'
|
||||
@@ -8,6 +10,7 @@ import relationshipPopulationPromise from './relationshipPopulationPromise'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
currentDepth: number
|
||||
depth: number
|
||||
@@ -16,6 +19,7 @@ type Args = {
|
||||
fieldPromises: Promise<void>[]
|
||||
findMany: boolean
|
||||
flattenLocales: boolean
|
||||
global: SanitizedGlobalConfig | null
|
||||
overrideAccess: boolean
|
||||
populationPromises: Promise<void>[]
|
||||
req: PayloadRequest
|
||||
@@ -32,6 +36,7 @@ type Args = {
|
||||
// - Populate relationships
|
||||
|
||||
export const promise = async ({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -40,6 +45,7 @@ export const promise = async ({
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -179,8 +185,11 @@ export const promise = async ({
|
||||
const hookPromises = Object.entries(siblingDoc[field.name]).map(([locale, value]) =>
|
||||
(async () => {
|
||||
const hookedValue = await currentHook({
|
||||
collection,
|
||||
context,
|
||||
data: doc,
|
||||
field,
|
||||
global,
|
||||
operation: 'read',
|
||||
originalDoc: doc,
|
||||
req,
|
||||
@@ -197,9 +206,12 @@ export const promise = async ({
|
||||
await Promise.all(hookPromises)
|
||||
} else {
|
||||
const hookedValue = await currentHook({
|
||||
collection,
|
||||
context,
|
||||
data: doc,
|
||||
field,
|
||||
findMany,
|
||||
global,
|
||||
operation: 'read',
|
||||
originalDoc: doc,
|
||||
req,
|
||||
@@ -252,6 +264,7 @@ export const promise = async ({
|
||||
if (typeof siblingDoc[field.name] !== 'object') groupDoc = {}
|
||||
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -260,6 +273,7 @@ export const promise = async ({
|
||||
fields: field.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -276,6 +290,7 @@ export const promise = async ({
|
||||
if (Array.isArray(rows)) {
|
||||
rows.forEach((row) => {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -284,6 +299,7 @@ export const promise = async ({
|
||||
fields: field.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -296,6 +312,7 @@ export const promise = async ({
|
||||
if (Array.isArray(localeRows)) {
|
||||
localeRows.forEach((row) => {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -304,6 +321,7 @@ export const promise = async ({
|
||||
fields: field.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -328,6 +346,7 @@ export const promise = async ({
|
||||
|
||||
if (block) {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -336,6 +355,7 @@ export const promise = async ({
|
||||
fields: block.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -352,6 +372,7 @@ export const promise = async ({
|
||||
|
||||
if (block) {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -360,6 +381,7 @@ export const promise = async ({
|
||||
fields: block.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -380,6 +402,7 @@ export const promise = async ({
|
||||
case 'row':
|
||||
case 'collapsible': {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -388,6 +411,7 @@ export const promise = async ({
|
||||
fields: field.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -406,6 +430,7 @@ export const promise = async ({
|
||||
}
|
||||
|
||||
await traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -414,6 +439,7 @@ export const promise = async ({
|
||||
fields: field.fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -426,6 +452,7 @@ export const promise = async ({
|
||||
|
||||
case 'tabs': {
|
||||
traverseFields({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -434,6 +461,7 @@ export const promise = async ({
|
||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { promise } from './promise'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
currentDepth: number
|
||||
depth: number
|
||||
@@ -12,6 +15,7 @@ type Args = {
|
||||
fields: (Field | TabAsField)[]
|
||||
findMany: boolean
|
||||
flattenLocales: boolean
|
||||
global: SanitizedGlobalConfig | null
|
||||
overrideAccess: boolean
|
||||
populationPromises: Promise<void>[]
|
||||
req: PayloadRequest
|
||||
@@ -20,6 +24,7 @@ type Args = {
|
||||
}
|
||||
|
||||
export const traverseFields = ({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -28,6 +33,7 @@ export const traverseFields = ({
|
||||
fields,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
@@ -37,6 +43,7 @@ export const traverseFields = ({
|
||||
fields.forEach((field) => {
|
||||
fieldPromises.push(
|
||||
promise({
|
||||
collection,
|
||||
context,
|
||||
currentDepth,
|
||||
depth,
|
||||
@@ -45,6 +52,7 @@ export const traverseFields = ({
|
||||
fieldPromises,
|
||||
findMany,
|
||||
flattenLocales,
|
||||
global,
|
||||
overrideAccess,
|
||||
populationPromises,
|
||||
req,
|
||||
|
||||
@@ -8,11 +8,12 @@ import { deepCopyObject } from '../../../utilities/deepCopyObject'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args<T> = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown> | T
|
||||
doc: Record<string, unknown> | T
|
||||
docWithLocales: Record<string, unknown>
|
||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
operation: Operation
|
||||
req: PayloadRequest
|
||||
@@ -21,11 +22,12 @@ type Args<T> = {
|
||||
|
||||
export const beforeChange = async <T extends Record<string, unknown>>({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data: incomingData,
|
||||
doc,
|
||||
docWithLocales,
|
||||
entityConfig,
|
||||
global,
|
||||
operation,
|
||||
req,
|
||||
skipValidation,
|
||||
@@ -36,12 +38,14 @@ export const beforeChange = async <T extends Record<string, unknown>>({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: entityConfig.fields,
|
||||
fields: collection?.fields || global?.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path: '',
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import merge from 'deepmerge'
|
||||
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Operation } from '../../../types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
@@ -10,12 +12,14 @@ import { getExistingRowDoc } from './getExistingRowDoc'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown>
|
||||
doc: Record<string, unknown>
|
||||
docWithLocales: Record<string, unknown>
|
||||
errors: { field: string; message: string }[]
|
||||
field: Field | TabAsField
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
mergeLocaleActions: (() => void)[]
|
||||
operation: Operation
|
||||
@@ -36,12 +40,14 @@ type Args = {
|
||||
|
||||
export const promise = async ({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
field,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path,
|
||||
@@ -75,8 +81,11 @@ export const promise = async ({
|
||||
await priorHook
|
||||
|
||||
const hookedValue = await currentHook({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
originalDoc: doc,
|
||||
req,
|
||||
@@ -183,12 +192,14 @@ export const promise = async ({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: field.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path: `${path}${field.name}.`,
|
||||
@@ -211,12 +222,14 @@ export const promise = async ({
|
||||
promises.push(
|
||||
traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: field.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path: `${path}${field.name}.${i}.`,
|
||||
@@ -251,12 +264,14 @@ export const promise = async ({
|
||||
promises.push(
|
||||
traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: block.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path: `${path}${field.name}.${i}.`,
|
||||
@@ -280,12 +295,14 @@ export const promise = async ({
|
||||
case 'collapsible': {
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: field.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path,
|
||||
@@ -319,12 +336,14 @@ export const promise = async ({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: field.fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path: tabPath,
|
||||
@@ -341,12 +360,14 @@ export const promise = async ({
|
||||
case 'tabs': {
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path,
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Operation } from '../../../types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { promise } from './promise'
|
||||
|
||||
type Args = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown>
|
||||
doc: Record<string, unknown>
|
||||
docWithLocales: Record<string, unknown>
|
||||
errors: { field: string; message: string }[]
|
||||
fields: (Field | TabAsField)[]
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
mergeLocaleActions: (() => void)[]
|
||||
operation: Operation
|
||||
@@ -24,12 +28,14 @@ type Args = {
|
||||
|
||||
export const traverseFields = async ({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
fields,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path,
|
||||
@@ -45,12 +51,14 @@ export const traverseFields = async ({
|
||||
promises.push(
|
||||
promise({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
docWithLocales,
|
||||
errors,
|
||||
field,
|
||||
global,
|
||||
mergeLocaleActions,
|
||||
operation,
|
||||
path,
|
||||
|
||||
@@ -6,10 +6,11 @@ import { deepCopyObject } from '../../../utilities/deepCopyObject'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args<T> = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: Record<string, unknown> | T
|
||||
doc?: Record<string, unknown> | T
|
||||
entityConfig: SanitizedCollectionConfig | SanitizedGlobalConfig
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
operation: 'create' | 'update'
|
||||
overrideAccess: boolean
|
||||
@@ -18,10 +19,11 @@ type Args<T> = {
|
||||
|
||||
export const beforeValidate = async <T extends Record<string, unknown>>({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data: incomingData,
|
||||
doc,
|
||||
entityConfig,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -30,10 +32,12 @@ export const beforeValidate = async <T extends Record<string, unknown>>({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: entityConfig.fields,
|
||||
fields: collection?.fields || global?.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { fieldAffectsData, tabHasName, valueIsValueWithRelation } from '../../config/types'
|
||||
@@ -9,10 +11,12 @@ import { getExistingRowDoc } from '../beforeChange/getExistingRowDoc'
|
||||
import { traverseFields } from './traverseFields'
|
||||
|
||||
type Args<T> = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: T
|
||||
doc: T
|
||||
field: Field | TabAsField
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
operation: 'create' | 'update'
|
||||
overrideAccess: boolean
|
||||
@@ -30,10 +34,12 @@ type Args<T> = {
|
||||
|
||||
export const promise = async <T>({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -209,8 +215,11 @@ export const promise = async <T>({
|
||||
await priorHook
|
||||
|
||||
const hookedValue = await currentHook({
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
originalDoc: doc,
|
||||
req,
|
||||
@@ -263,10 +272,12 @@ export const promise = async <T>({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -282,14 +293,16 @@ export const promise = async <T>({
|
||||
|
||||
if (Array.isArray(rows)) {
|
||||
const promises = []
|
||||
rows.forEach((row, i) => {
|
||||
rows.forEach((row) => {
|
||||
promises.push(
|
||||
traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -308,7 +321,7 @@ export const promise = async <T>({
|
||||
|
||||
if (Array.isArray(rows)) {
|
||||
const promises = []
|
||||
rows.forEach((row, i) => {
|
||||
rows.forEach((row) => {
|
||||
const rowSiblingDoc = getExistingRowDoc(row, siblingDoc[field.name])
|
||||
const blockTypeToMatch = row.blockType || rowSiblingDoc.blockType
|
||||
const block = field.blocks.find((blockType) => blockType.slug === blockTypeToMatch)
|
||||
@@ -319,10 +332,12 @@ export const promise = async <T>({
|
||||
promises.push(
|
||||
traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: block.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -342,10 +357,12 @@ export const promise = async <T>({
|
||||
case 'collapsible': {
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -372,10 +389,12 @@ export const promise = async <T>({
|
||||
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -389,10 +408,12 @@ export const promise = async <T>({
|
||||
case 'tabs': {
|
||||
await traverseFields({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import type { SanitizedCollectionConfig } from '../../../collections/config/types'
|
||||
import type { PayloadRequest, RequestContext } from '../../../express/types'
|
||||
import type { SanitizedGlobalConfig } from '../../../globals/config/types'
|
||||
import type { Field, TabAsField } from '../../config/types'
|
||||
|
||||
import { promise } from './promise'
|
||||
|
||||
type Args<T> = {
|
||||
collection: SanitizedCollectionConfig | null
|
||||
context: RequestContext
|
||||
data: T
|
||||
doc: T
|
||||
fields: (Field | TabAsField)[]
|
||||
global: SanitizedGlobalConfig | null
|
||||
id?: number | string
|
||||
operation: 'create' | 'update'
|
||||
overrideAccess: boolean
|
||||
@@ -18,10 +22,12 @@ type Args<T> = {
|
||||
|
||||
export const traverseFields = async <T>({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
fields,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -33,10 +39,12 @@ export const traverseFields = async <T>({
|
||||
promises.push(
|
||||
promise({
|
||||
id,
|
||||
collection,
|
||||
context,
|
||||
data,
|
||||
doc,
|
||||
field,
|
||||
global,
|
||||
operation,
|
||||
overrideAccess,
|
||||
req,
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {
|
||||
LivePreviewConfig,
|
||||
} from '../../config/types'
|
||||
import type { PayloadRequest } from '../../express/types'
|
||||
import type { RequestContext } from '../../express/types'
|
||||
import type { Field } from '../../fields/config/types'
|
||||
import type { Where } from '../../types'
|
||||
import type { IncomingGlobalVersions, SanitizedGlobalVersions } from '../../versions/types'
|
||||
@@ -27,20 +28,46 @@ export type TypeWithID = {
|
||||
}
|
||||
|
||||
export type BeforeValidateHook = (args: {
|
||||
context: RequestContext
|
||||
data?: any
|
||||
/** The global which this hook is being run on */
|
||||
global: SanitizedGlobalConfig
|
||||
originalDoc?: any
|
||||
req?: PayloadRequest
|
||||
}) => any
|
||||
|
||||
export type BeforeChangeHook = (args: { data: any; originalDoc?: any; req: PayloadRequest }) => any
|
||||
export type BeforeChangeHook = (args: {
|
||||
context: RequestContext
|
||||
data: any
|
||||
/** The global which this hook is being run on */
|
||||
global: SanitizedGlobalConfig
|
||||
originalDoc?: any
|
||||
req: PayloadRequest
|
||||
}) => any
|
||||
|
||||
export type AfterChangeHook = (args: { doc: any; previousDoc: any; req: PayloadRequest }) => any
|
||||
export type AfterChangeHook = (args: {
|
||||
context: RequestContext
|
||||
doc: any
|
||||
/** The global which this hook is being run on */
|
||||
global: SanitizedGlobalConfig
|
||||
previousDoc: any
|
||||
req: PayloadRequest
|
||||
}) => any
|
||||
|
||||
export type BeforeReadHook = (args: { doc: any; req: PayloadRequest }) => any
|
||||
export type BeforeReadHook = (args: {
|
||||
context: RequestContext
|
||||
doc: any
|
||||
/** The global which this hook is being run on */
|
||||
global: SanitizedGlobalConfig
|
||||
req: PayloadRequest
|
||||
}) => any
|
||||
|
||||
export type AfterReadHook = (args: {
|
||||
context: RequestContext
|
||||
doc: any
|
||||
findMany?: boolean
|
||||
/** The global which this hook is being run on */
|
||||
global: SanitizedGlobalConfig
|
||||
query?: Where
|
||||
req: PayloadRequest
|
||||
}) => any
|
||||
|
||||
@@ -83,7 +83,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
||||
|
||||
doc =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc,
|
||||
global: globalConfig,
|
||||
req,
|
||||
})) || doc
|
||||
}, Promise.resolve())
|
||||
@@ -93,10 +95,11 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
||||
// /////////////////////////////////////
|
||||
|
||||
doc = await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -111,7 +114,9 @@ async function findOne<T extends Record<string, unknown>>(args: Args): Promise<T
|
||||
|
||||
doc =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc,
|
||||
global: globalConfig,
|
||||
req,
|
||||
})) || doc
|
||||
}, Promise.resolve())
|
||||
|
||||
@@ -87,7 +87,9 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result.version,
|
||||
global: globalConfig,
|
||||
req,
|
||||
})) || result.version
|
||||
}, Promise.resolve())
|
||||
@@ -97,11 +99,12 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
// /////////////////////////////////////
|
||||
|
||||
result.version = await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
currentDepth,
|
||||
depth,
|
||||
doc: result.version,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -116,7 +119,9 @@ async function findVersionByID<T extends TypeWithVersion<T> = any>(args: Argumen
|
||||
|
||||
result.version =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result.version,
|
||||
global: globalConfig,
|
||||
query: findGlobalVersionsArgs.where,
|
||||
req,
|
||||
})) || result.version
|
||||
|
||||
@@ -88,11 +88,12 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
paginatedDocs.docs.map(async (data) => ({
|
||||
...data,
|
||||
version: await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: data.version,
|
||||
entityConfig: globalConfig,
|
||||
findMany: true,
|
||||
global: globalConfig,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -115,8 +116,14 @@ async function findVersions<T extends TypeWithVersion<T>>(
|
||||
await priorHook
|
||||
|
||||
docRef.version =
|
||||
(await hook({ doc: doc.version, findMany: true, query: fullWhere, req })) ||
|
||||
doc.version
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: doc.version,
|
||||
findMany: true,
|
||||
global: globalConfig,
|
||||
query: fullWhere,
|
||||
req,
|
||||
})) || doc.version
|
||||
}, Promise.resolve())
|
||||
|
||||
return docRef
|
||||
|
||||
@@ -97,10 +97,11 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -115,7 +116,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result,
|
||||
global: globalConfig,
|
||||
req,
|
||||
})) || result
|
||||
}, Promise.resolve())
|
||||
@@ -125,10 +128,11 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
data: result,
|
||||
doc: result,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
operation: 'update',
|
||||
previousDoc,
|
||||
req,
|
||||
@@ -143,7 +147,9 @@ async function restoreVersion<T extends TypeWithVersion<T> = any>(args: Argument
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result,
|
||||
global: globalConfig,
|
||||
previousDoc,
|
||||
req,
|
||||
})) || result
|
||||
|
||||
@@ -92,10 +92,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
}
|
||||
|
||||
const originalDoc = await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
depth: 0,
|
||||
doc: globalJSON,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
overrideAccess: true,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -106,10 +107,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
data = await beforeValidate({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
operation: 'update',
|
||||
overrideAccess,
|
||||
req,
|
||||
@@ -124,7 +126,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
data,
|
||||
global: globalConfig,
|
||||
originalDoc,
|
||||
req,
|
||||
})) || data
|
||||
@@ -139,7 +143,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
|
||||
data =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
data,
|
||||
global: globalConfig,
|
||||
originalDoc,
|
||||
req,
|
||||
})) || data
|
||||
@@ -150,11 +156,12 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
let result = await beforeChange({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: originalDoc,
|
||||
docWithLocales: globalJSON,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
operation: 'update',
|
||||
req,
|
||||
skipValidation: shouldSaveDraft,
|
||||
@@ -204,10 +211,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterRead({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
depth,
|
||||
doc: result,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
overrideAccess,
|
||||
req,
|
||||
showHiddenFields,
|
||||
@@ -222,7 +230,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result,
|
||||
global: globalConfig,
|
||||
req,
|
||||
})) || result
|
||||
}, Promise.resolve())
|
||||
@@ -232,10 +242,11 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
// /////////////////////////////////////
|
||||
|
||||
result = await afterChange({
|
||||
collection: null,
|
||||
context: req.context,
|
||||
data,
|
||||
doc: result,
|
||||
entityConfig: globalConfig,
|
||||
global: globalConfig,
|
||||
operation: 'update',
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
@@ -250,7 +261,9 @@ async function update<TSlug extends keyof GeneratedTypes['globals']>(
|
||||
|
||||
result =
|
||||
(await hook({
|
||||
context: req.context,
|
||||
doc: result,
|
||||
global: globalConfig,
|
||||
previousDoc: originalDoc,
|
||||
req,
|
||||
})) || result
|
||||
|
||||
@@ -35,7 +35,7 @@ const errorHandler = async (
|
||||
}
|
||||
|
||||
if (afterErrorHook) {
|
||||
;({ response } = (await afterErrorHook(err, response, null)) || { response })
|
||||
;({ response } = (await afterErrorHook(err, response, null, null)) || { response })
|
||||
}
|
||||
|
||||
return response
|
||||
|
||||
111
test/hooks/collections/Data/index.ts
Normal file
111
test/hooks/collections/Data/index.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
import type { CollectionConfig } from '../../../../packages/payload/src/collections/config/types'
|
||||
|
||||
export const dataHooksSlug = 'data-hooks'
|
||||
|
||||
export const DataHooks: CollectionConfig = {
|
||||
slug: dataHooksSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
create: () => true,
|
||||
delete: () => true,
|
||||
update: () => true,
|
||||
},
|
||||
hooks: {
|
||||
beforeOperation: [
|
||||
async ({ context, collection, args }) => {
|
||||
context['collection_beforeOperation_collection'] = JSON.stringify(collection)
|
||||
|
||||
return args
|
||||
},
|
||||
],
|
||||
|
||||
beforeChange: [
|
||||
({ context, data, collection }) => {
|
||||
context['collection_beforeChange_collection'] = JSON.stringify(collection)
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
async ({ context, collection }) => {
|
||||
context['collection_afterChange_collection'] = JSON.stringify(collection)
|
||||
},
|
||||
],
|
||||
beforeRead: [
|
||||
async ({ context, collection }) => {
|
||||
context['collection_beforeRead_collection'] = JSON.stringify(collection)
|
||||
},
|
||||
],
|
||||
afterRead: [
|
||||
({ context, collection, doc }) => {
|
||||
context['collection_afterRead_collection'] = JSON.stringify(collection)
|
||||
|
||||
return doc
|
||||
},
|
||||
],
|
||||
afterOperation: [
|
||||
({ args, result, collection }) => {
|
||||
args.req.context['collection_afterOperation_collection'] = JSON.stringify(collection)
|
||||
|
||||
for (const contextKey in args.req.context) {
|
||||
if (contextKey.startsWith('collection_')) {
|
||||
result[contextKey] = args.req.context[contextKey]
|
||||
}
|
||||
}
|
||||
return result
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'field_collectionAndField',
|
||||
type: 'text',
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ collection, field, context, value }) => {
|
||||
context['field_beforeChange_CollectionAndField'] =
|
||||
JSON.stringify(collection) + JSON.stringify(field)
|
||||
|
||||
return value
|
||||
},
|
||||
],
|
||||
|
||||
afterRead: [
|
||||
({ collection, field, context }) => {
|
||||
return (
|
||||
(context['field_beforeChange_CollectionAndField'] as string) +
|
||||
JSON.stringify(collection) +
|
||||
JSON.stringify(field)
|
||||
)
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'collection_beforeOperation_collection',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'collection_beforeChange_collection',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'collection_afterChange_collection',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'collection_beforeRead_collection',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'collection_afterRead_collection',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'collection_afterOperation_collection',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
import type { SanitizedConfig } from '../../packages/payload/src/config/types'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
||||
import AfterOperation from './collections/AfterOperation'
|
||||
import ChainingHooks from './collections/ChainingHooks'
|
||||
import ContextHooks from './collections/ContextHooks'
|
||||
import { DataHooks } from './collections/Data'
|
||||
import Hooks, { hooksSlug } from './collections/Hook'
|
||||
import NestedAfterReadHooks from './collections/NestedAfterReadHooks'
|
||||
import Relations from './collections/Relations'
|
||||
import TransformHooks from './collections/Transform'
|
||||
import Users, { seedHooksUsers } from './collections/Users'
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
import { DataHooksGlobal } from './globals/Data'
|
||||
export const HooksConfig: Promise<SanitizedConfig> = buildConfigWithDefaults({
|
||||
collections: [
|
||||
AfterOperation,
|
||||
ContextHooks,
|
||||
@@ -18,7 +21,9 @@ export default buildConfigWithDefaults({
|
||||
ChainingHooks,
|
||||
Relations,
|
||||
Users,
|
||||
DataHooks,
|
||||
],
|
||||
globals: [DataHooksGlobal],
|
||||
onInit: async (payload) => {
|
||||
await seedHooksUsers(payload)
|
||||
await payload.create({
|
||||
@@ -38,3 +43,5 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
export default HooksConfig
|
||||
|
||||
97
test/hooks/globals/Data/index.ts
Normal file
97
test/hooks/globals/Data/index.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
import type { GlobalConfig } from '../../../../packages/payload/src/globals/config/types'
|
||||
|
||||
export const dataHooksGlobalSlug = 'data-hooks-global'
|
||||
|
||||
export const DataHooksGlobal: GlobalConfig = {
|
||||
slug: dataHooksGlobalSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
update: () => true,
|
||||
},
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ data, global, context }) => {
|
||||
context['global_beforeChange_global'] = JSON.stringify(global)
|
||||
|
||||
return data
|
||||
},
|
||||
],
|
||||
beforeRead: [
|
||||
async ({ context, global }) => {
|
||||
context['global_beforeRead_global'] = JSON.stringify(global)
|
||||
},
|
||||
],
|
||||
afterRead: [
|
||||
({ context, global, doc }) => {
|
||||
context['global_afterRead_global'] = JSON.stringify(global)
|
||||
|
||||
// Needs to be done for both afterRead (for findOne test) and afterChange (for update test)
|
||||
for (const contextKey in context) {
|
||||
if (contextKey.startsWith('global_')) {
|
||||
doc[contextKey] = context[contextKey]
|
||||
}
|
||||
}
|
||||
return doc
|
||||
},
|
||||
],
|
||||
afterChange: [
|
||||
async ({ context, global, doc }) => {
|
||||
context['global_afterChange_global'] = JSON.stringify(global)
|
||||
|
||||
// Needs to be done for both afterRead (for findOne test) and afterChange (for update test), as afterChange is called after afterRead
|
||||
for (const contextKey in context) {
|
||||
if (contextKey.startsWith('global_')) {
|
||||
doc[contextKey] = context[contextKey]
|
||||
}
|
||||
}
|
||||
|
||||
return doc
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'field_globalAndField',
|
||||
type: 'text',
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
({ global, field, context, value }) => {
|
||||
context['field_beforeChange_GlobalAndField'] =
|
||||
JSON.stringify(global) + JSON.stringify(field)
|
||||
|
||||
return value
|
||||
},
|
||||
],
|
||||
|
||||
afterRead: [
|
||||
({ global, field, context }) => {
|
||||
return (
|
||||
(context['field_beforeChange_GlobalAndField'] as string) +
|
||||
JSON.stringify(global) +
|
||||
JSON.stringify(field)
|
||||
)
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: 'global_beforeChange_global',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'global_afterChange_global',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'global_beforeRead_global',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'global_afterRead_global',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { RESTClient } from '../helpers/rest'
|
||||
import { afterOperationSlug } from './collections/AfterOperation'
|
||||
import { chainingHooksSlug } from './collections/ChainingHooks'
|
||||
import { contextHooksSlug } from './collections/ContextHooks'
|
||||
import { dataHooksSlug } from './collections/Data'
|
||||
import { hooksSlug } from './collections/Hook'
|
||||
import {
|
||||
generatedAfterReadText,
|
||||
@@ -16,7 +17,8 @@ import {
|
||||
import { relationsSlug } from './collections/Relations'
|
||||
import { transformSlug } from './collections/Transform'
|
||||
import { hooksUsersSlug } from './collections/Users'
|
||||
import configPromise from './config'
|
||||
import configPromise, { HooksConfig } from './config'
|
||||
import { dataHooksGlobalSlug } from './globals/Data'
|
||||
|
||||
let client: RESTClient
|
||||
let apiUrl
|
||||
@@ -293,4 +295,111 @@ describe('Hooks', () => {
|
||||
).rejects.toThrow(AuthenticationError)
|
||||
})
|
||||
})
|
||||
|
||||
describe('hook parameter data', () => {
|
||||
it('should pass collection prop to collection hooks', async () => {
|
||||
const sanitizedConfig = await HooksConfig
|
||||
const sanitizedHooksCollection = JSON.parse(
|
||||
JSON.stringify(sanitizedConfig.collections.find(({ slug }) => slug === dataHooksSlug)),
|
||||
)
|
||||
|
||||
const doc = await payload.create({
|
||||
collection: dataHooksSlug,
|
||||
data: {},
|
||||
})
|
||||
|
||||
expect(JSON.parse(doc.collection_beforeOperation_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
expect(JSON.parse(doc.collection_beforeChange_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
expect(JSON.parse(doc.collection_afterChange_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
expect(JSON.parse(doc.collection_afterRead_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
expect(JSON.parse(doc.collection_afterOperation_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
|
||||
// BeforeRead is only run for find operations
|
||||
const foundDoc = await payload.findByID({
|
||||
collection: dataHooksSlug,
|
||||
id: doc.id,
|
||||
})
|
||||
|
||||
expect(JSON.parse(foundDoc.collection_beforeRead_collection)).toStrictEqual(
|
||||
sanitizedHooksCollection,
|
||||
)
|
||||
})
|
||||
|
||||
it('should pass collection and field props to field hooks', async () => {
|
||||
const sanitizedConfig = await HooksConfig
|
||||
const sanitizedHooksCollection = sanitizedConfig.collections.find(
|
||||
({ slug }) => slug === dataHooksSlug,
|
||||
)
|
||||
|
||||
const field = sanitizedHooksCollection.fields.find(
|
||||
(field) => 'name' in field && field.name === 'field_collectionAndField',
|
||||
)
|
||||
|
||||
const doc = await payload.create({
|
||||
collection: dataHooksSlug,
|
||||
data: {},
|
||||
})
|
||||
|
||||
const collectionAndField = JSON.stringify(sanitizedHooksCollection) + JSON.stringify(field)
|
||||
|
||||
expect(doc.field_collectionAndField).toStrictEqual(collectionAndField + collectionAndField)
|
||||
})
|
||||
|
||||
it('should pass global prop to global hooks', async () => {
|
||||
const sanitizedConfig = await HooksConfig
|
||||
const sanitizedHooksGlobal = JSON.parse(
|
||||
JSON.stringify(sanitizedConfig.globals.find(({ slug }) => slug === dataHooksGlobalSlug)),
|
||||
)
|
||||
|
||||
const doc = await payload.updateGlobal({
|
||||
slug: dataHooksGlobalSlug,
|
||||
data: {},
|
||||
})
|
||||
|
||||
expect(JSON.parse(doc.global_beforeChange_global)).toStrictEqual(sanitizedHooksGlobal)
|
||||
expect(JSON.parse(doc.global_afterRead_global)).toStrictEqual(sanitizedHooksGlobal)
|
||||
expect(JSON.parse(doc.global_afterChange_global)).toStrictEqual(sanitizedHooksGlobal)
|
||||
|
||||
// beforeRead is only run for findOne operations
|
||||
const foundDoc = await payload.findGlobal({
|
||||
slug: dataHooksGlobalSlug,
|
||||
})
|
||||
|
||||
expect(JSON.parse(foundDoc.global_beforeRead_global)).toStrictEqual(sanitizedHooksGlobal)
|
||||
})
|
||||
|
||||
it('should pass global and field props to global hooks', async () => {
|
||||
const sanitizedConfig = await HooksConfig
|
||||
const sanitizedHooksGlobal = sanitizedConfig.globals.find(
|
||||
({ slug }) => slug === dataHooksGlobalSlug,
|
||||
)
|
||||
|
||||
const globalString = JSON.stringify(sanitizedHooksGlobal)
|
||||
|
||||
const fieldString = JSON.stringify(
|
||||
sanitizedHooksGlobal.fields.find(
|
||||
(field) => 'name' in field && field.name === 'field_globalAndField',
|
||||
),
|
||||
)
|
||||
|
||||
const doc = await payload.updateGlobal({
|
||||
slug: dataHooksGlobalSlug,
|
||||
data: {},
|
||||
})
|
||||
|
||||
const globalAndFieldString = globalString + fieldString
|
||||
|
||||
expect(doc.field_globalAndField).toStrictEqual(globalAndFieldString + globalAndFieldString)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user