fix: beforeValidate deleting value when access returns false (#11549)
### What? Regression caused by https://github.com/payloadcms/payload/pull/11433 If a beforeChange hook was checking for a missing or undefined `value` in order to change the value before inserting into the database, data could be lost. ### Why? In #11433 the logic for setting the fallback field value was moved above the logic that cleared the value when access control returned false. ### How? This change ensures that the fallback value is passed into the beforeValidate function _and_ still available with the fallback value on siblingData if access control returns false. Fixes https://github.com/payloadcms/payload/issues/11543
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
import type { JsonObject, JsonValue, PayloadRequest } from '../../../types/index.js'
|
||||||
|
import type { FieldAffectingData } from '../../config/types.js'
|
||||||
|
|
||||||
|
import { getDefaultValue } from '../../getDefaultValue.js'
|
||||||
|
import { cloneDataFromOriginalDoc } from '../beforeChange/cloneDataFromOriginalDoc.js'
|
||||||
|
|
||||||
|
export async function getFallbackValue({
|
||||||
|
field,
|
||||||
|
req,
|
||||||
|
siblingDoc,
|
||||||
|
}: {
|
||||||
|
field: FieldAffectingData
|
||||||
|
req: PayloadRequest
|
||||||
|
siblingDoc: JsonObject
|
||||||
|
}): Promise<JsonValue> {
|
||||||
|
let fallbackValue = undefined
|
||||||
|
if ('name' in field && field.name) {
|
||||||
|
if (typeof siblingDoc[field.name] !== 'undefined') {
|
||||||
|
fallbackValue = cloneDataFromOriginalDoc(siblingDoc[field.name])
|
||||||
|
} else if ('defaultValue' in field && typeof field.defaultValue !== 'undefined') {
|
||||||
|
fallbackValue = await getDefaultValue({
|
||||||
|
defaultValue: field.defaultValue,
|
||||||
|
locale: req.locale || '',
|
||||||
|
req,
|
||||||
|
user: req.user,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallbackValue
|
||||||
|
}
|
||||||
@@ -8,10 +8,9 @@ import type { Block, Field, TabAsField } from '../../config/types.js'
|
|||||||
|
|
||||||
import { MissingEditorProp } from '../../../errors/index.js'
|
import { MissingEditorProp } from '../../../errors/index.js'
|
||||||
import { fieldAffectsData, tabHasName, valueIsValueWithRelation } from '../../config/types.js'
|
import { fieldAffectsData, tabHasName, valueIsValueWithRelation } from '../../config/types.js'
|
||||||
import { getDefaultValue } from '../../getDefaultValue.js'
|
|
||||||
import { getFieldPathsModified as getFieldPaths } from '../../getFieldPaths.js'
|
import { getFieldPathsModified as getFieldPaths } from '../../getFieldPaths.js'
|
||||||
import { cloneDataFromOriginalDoc } from '../beforeChange/cloneDataFromOriginalDoc.js'
|
|
||||||
import { getExistingRowDoc } from '../beforeChange/getExistingRowDoc.js'
|
import { getExistingRowDoc } from '../beforeChange/getExistingRowDoc.js'
|
||||||
|
import { getFallbackValue } from './getFallbackValue.js'
|
||||||
import { traverseFields } from './traverseFields.js'
|
import { traverseFields } from './traverseFields.js'
|
||||||
|
|
||||||
type Args<T> = {
|
type Args<T> = {
|
||||||
@@ -274,21 +273,15 @@ export const promise = async <T>({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure the fallback value is only computed one time
|
||||||
|
// either here or when access control returns false
|
||||||
|
const fallbackResult = {
|
||||||
|
executed: false,
|
||||||
|
value: undefined,
|
||||||
|
}
|
||||||
if (typeof siblingData[field.name] === 'undefined') {
|
if (typeof siblingData[field.name] === 'undefined') {
|
||||||
// If no incoming data, but existing document data is found, merge it in
|
fallbackResult.value = await getFallbackValue({ field, req, siblingDoc })
|
||||||
if (typeof siblingDoc[field.name] !== 'undefined') {
|
fallbackResult.executed = true
|
||||||
siblingData[field.name] = cloneDataFromOriginalDoc(siblingDoc[field.name])
|
|
||||||
|
|
||||||
// Otherwise compute default value
|
|
||||||
} else if (typeof field.defaultValue !== 'undefined') {
|
|
||||||
siblingData[field.name] = await getDefaultValue({
|
|
||||||
defaultValue: field.defaultValue,
|
|
||||||
locale: req.locale,
|
|
||||||
req,
|
|
||||||
user: req.user,
|
|
||||||
value: siblingData[field.name],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute hooks
|
// Execute hooks
|
||||||
@@ -312,7 +305,10 @@ export const promise = async <T>({
|
|||||||
schemaPath: schemaPathSegments,
|
schemaPath: schemaPathSegments,
|
||||||
siblingData,
|
siblingData,
|
||||||
siblingFields,
|
siblingFields,
|
||||||
value: siblingData[field.name],
|
value:
|
||||||
|
typeof siblingData[field.name] === 'undefined'
|
||||||
|
? fallbackResult.value
|
||||||
|
: siblingData[field.name],
|
||||||
})
|
})
|
||||||
|
|
||||||
if (hookedValue !== undefined) {
|
if (hookedValue !== undefined) {
|
||||||
@@ -331,6 +327,12 @@ export const promise = async <T>({
|
|||||||
delete siblingData[field.name]
|
delete siblingData[field.name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof siblingData[field.name] === 'undefined') {
|
||||||
|
siblingData[field.name] = !fallbackResult.executed
|
||||||
|
? await getFallbackValue({ field, req, siblingDoc })
|
||||||
|
: fallbackResult.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverse subfields
|
// Traverse subfields
|
||||||
|
|||||||
44
test/access-control/collections/hooks/index.ts
Normal file
44
test/access-control/collections/hooks/index.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import type { CollectionConfig } from 'payload'
|
||||||
|
|
||||||
|
import { hooksSlug } from '../../shared.js'
|
||||||
|
|
||||||
|
export const Hooks: CollectionConfig = {
|
||||||
|
slug: hooksSlug,
|
||||||
|
access: {
|
||||||
|
update: () => true,
|
||||||
|
},
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: 'cannotMutateRequired',
|
||||||
|
type: 'text',
|
||||||
|
access: {
|
||||||
|
update: () => false,
|
||||||
|
},
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'cannotMutateNotRequired',
|
||||||
|
type: 'text',
|
||||||
|
access: {
|
||||||
|
update: () => false,
|
||||||
|
},
|
||||||
|
hooks: {
|
||||||
|
beforeChange: [
|
||||||
|
({ value }) => {
|
||||||
|
if (!value) {
|
||||||
|
return 'no value found'
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'canMutate',
|
||||||
|
type: 'text',
|
||||||
|
access: {
|
||||||
|
update: () => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
|||||||
import { devUser } from '../credentials.js'
|
import { devUser } from '../credentials.js'
|
||||||
import { textToLexicalJSON } from '../fields/collections/LexicalLocalized/textToLexicalJSON.js'
|
import { textToLexicalJSON } from '../fields/collections/LexicalLocalized/textToLexicalJSON.js'
|
||||||
import { Disabled } from './collections/Disabled/index.js'
|
import { Disabled } from './collections/Disabled/index.js'
|
||||||
|
import { Hooks } from './collections/hooks/index.js'
|
||||||
import { Regression1 } from './collections/Regression-1/index.js'
|
import { Regression1 } from './collections/Regression-1/index.js'
|
||||||
import { Regression2 } from './collections/Regression-2/index.js'
|
import { Regression2 } from './collections/Regression-2/index.js'
|
||||||
import { RichText } from './collections/RichText/index.js'
|
import { RichText } from './collections/RichText/index.js'
|
||||||
@@ -567,6 +568,7 @@ export default buildConfigWithDefaults(
|
|||||||
RichText,
|
RichText,
|
||||||
Regression1,
|
Regression1,
|
||||||
Regression2,
|
Regression2,
|
||||||
|
Hooks,
|
||||||
],
|
],
|
||||||
globals: [
|
globals: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import type {
|
|||||||
} from 'payload'
|
} from 'payload'
|
||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { Forbidden } from 'payload'
|
import { Forbidden, ValidationError } from 'payload'
|
||||||
import { fileURLToPath } from 'url'
|
import { fileURLToPath } from 'url'
|
||||||
|
|
||||||
import type { FullyRestricted, Post } from './payload-types.js'
|
import type { FullyRestricted, Post } from './payload-types.js'
|
||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
hiddenAccessCountSlug,
|
hiddenAccessCountSlug,
|
||||||
hiddenAccessSlug,
|
hiddenAccessSlug,
|
||||||
hiddenFieldsSlug,
|
hiddenFieldsSlug,
|
||||||
|
hooksSlug,
|
||||||
relyOnRequestHeadersSlug,
|
relyOnRequestHeadersSlug,
|
||||||
restrictedVersionsSlug,
|
restrictedVersionsSlug,
|
||||||
secondArrayText,
|
secondArrayText,
|
||||||
@@ -58,115 +59,181 @@ describe('Access Control', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not affect hidden fields when patching data', async () => {
|
describe('Fields', () => {
|
||||||
const doc = await payload.create({
|
it('should not affect hidden fields when patching data', async () => {
|
||||||
collection: hiddenFieldsSlug,
|
const doc = await payload.create({
|
||||||
data: {
|
collection: hiddenFieldsSlug,
|
||||||
partiallyHiddenArray: [
|
data: {
|
||||||
{
|
partiallyHiddenArray: [
|
||||||
|
{
|
||||||
|
name: 'public_name',
|
||||||
|
value: 'private_value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
partiallyHiddenGroup: {
|
||||||
name: 'public_name',
|
name: 'public_name',
|
||||||
value: 'private_value',
|
value: 'private_value',
|
||||||
},
|
},
|
||||||
],
|
|
||||||
partiallyHiddenGroup: {
|
|
||||||
name: 'public_name',
|
|
||||||
value: 'private_value',
|
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
|
|
||||||
|
await payload.update({
|
||||||
|
id: doc.id,
|
||||||
|
collection: hiddenFieldsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'Doc Title',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedDoc = await payload.findByID({
|
||||||
|
id: doc.id,
|
||||||
|
collection: hiddenFieldsSlug,
|
||||||
|
showHiddenFields: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedDoc.partiallyHiddenGroup.value).toStrictEqual('private_value')
|
||||||
|
expect(updatedDoc.partiallyHiddenArray[0].value).toStrictEqual('private_value')
|
||||||
})
|
})
|
||||||
|
|
||||||
await payload.update({
|
it('should not affect hidden fields when patching data - update many', async () => {
|
||||||
id: doc.id,
|
const docsMany = await payload.create({
|
||||||
collection: hiddenFieldsSlug,
|
collection: hiddenFieldsSlug,
|
||||||
data: {
|
data: {
|
||||||
title: 'Doc Title',
|
partiallyHiddenArray: [
|
||||||
},
|
{
|
||||||
})
|
name: 'public_name',
|
||||||
|
value: 'private_value',
|
||||||
const updatedDoc = await payload.findByID({
|
},
|
||||||
id: doc.id,
|
],
|
||||||
collection: hiddenFieldsSlug,
|
partiallyHiddenGroup: {
|
||||||
showHiddenFields: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(updatedDoc.partiallyHiddenGroup.value).toStrictEqual('private_value')
|
|
||||||
expect(updatedDoc.partiallyHiddenArray[0].value).toStrictEqual('private_value')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not affect hidden fields when patching data - update many', async () => {
|
|
||||||
const docsMany = await payload.create({
|
|
||||||
collection: hiddenFieldsSlug,
|
|
||||||
data: {
|
|
||||||
partiallyHiddenArray: [
|
|
||||||
{
|
|
||||||
name: 'public_name',
|
name: 'public_name',
|
||||||
value: 'private_value',
|
value: 'private_value',
|
||||||
},
|
},
|
||||||
],
|
|
||||||
partiallyHiddenGroup: {
|
|
||||||
name: 'public_name',
|
|
||||||
value: 'private_value',
|
|
||||||
},
|
},
|
||||||
},
|
})
|
||||||
|
|
||||||
|
await payload.update({
|
||||||
|
collection: hiddenFieldsSlug,
|
||||||
|
data: {
|
||||||
|
title: 'Doc Title',
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
id: { equals: docsMany.id },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedMany = await payload.findByID({
|
||||||
|
id: docsMany.id,
|
||||||
|
collection: hiddenFieldsSlug,
|
||||||
|
showHiddenFields: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedMany.partiallyHiddenGroup.value).toStrictEqual('private_value')
|
||||||
|
expect(updatedMany.partiallyHiddenArray[0].value).toStrictEqual('private_value')
|
||||||
})
|
})
|
||||||
|
|
||||||
await payload.update({
|
it('should be able to restrict access based upon siblingData', async () => {
|
||||||
collection: hiddenFieldsSlug,
|
const { id } = await payload.create({
|
||||||
data: {
|
collection: siblingDataSlug,
|
||||||
title: 'Doc Title',
|
data: {
|
||||||
},
|
array: [
|
||||||
where: {
|
{
|
||||||
id: { equals: docsMany.id },
|
allowPublicReadability: true,
|
||||||
},
|
text: firstArrayText,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
allowPublicReadability: false,
|
||||||
|
text: secondArrayText,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const doc = await payload.findByID({
|
||||||
|
id,
|
||||||
|
collection: siblingDataSlug,
|
||||||
|
overrideAccess: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(doc.array?.[0].text).toBe(firstArrayText)
|
||||||
|
// Should respect PublicReadabilityAccess function and not be sent
|
||||||
|
expect(doc.array?.[1].text).toBeUndefined()
|
||||||
|
|
||||||
|
// Retrieve with default of overriding access
|
||||||
|
const docOverride = await payload.findByID({
|
||||||
|
id,
|
||||||
|
collection: siblingDataSlug,
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(docOverride.array?.[0].text).toBe(firstArrayText)
|
||||||
|
expect(docOverride.array?.[1].text).toBe(secondArrayText)
|
||||||
})
|
})
|
||||||
|
|
||||||
const updatedMany = await payload.findByID({
|
it('should use fallback value when trying to update a field without permission', async () => {
|
||||||
id: docsMany.id,
|
const doc = await payload.create({
|
||||||
collection: hiddenFieldsSlug,
|
collection: hooksSlug,
|
||||||
showHiddenFields: true,
|
data: {
|
||||||
|
cannotMutateRequired: 'original',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedDoc = await payload.update({
|
||||||
|
id: doc.id,
|
||||||
|
collection: hooksSlug,
|
||||||
|
overrideAccess: false,
|
||||||
|
data: {
|
||||||
|
cannotMutateRequired: 'new',
|
||||||
|
canMutate: 'canMutate',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedDoc.cannotMutateRequired).toBe('original')
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(updatedMany.partiallyHiddenGroup.value).toStrictEqual('private_value')
|
it('should use fallback value when required data is missing', async () => {
|
||||||
expect(updatedMany.partiallyHiddenArray[0].value).toStrictEqual('private_value')
|
const doc = await payload.create({
|
||||||
|
collection: hooksSlug,
|
||||||
|
data: {
|
||||||
|
cannotMutateRequired: 'original',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedDoc = await payload.update({
|
||||||
|
id: doc.id,
|
||||||
|
collection: hooksSlug,
|
||||||
|
overrideAccess: false,
|
||||||
|
data: {
|
||||||
|
canMutate: 'canMutate',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// should fallback to original data and not throw validation error
|
||||||
|
expect(updatedDoc.cannotMutateRequired).toBe('original')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should pass fallback value through to beforeChange hook when access returns false', async () => {
|
||||||
|
const doc = await payload.create({
|
||||||
|
collection: hooksSlug,
|
||||||
|
data: {
|
||||||
|
cannotMutateRequired: 'cannotMutateRequired',
|
||||||
|
cannotMutateNotRequired: 'cannotMutateNotRequired',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedDoc = await payload.update({
|
||||||
|
id: doc.id,
|
||||||
|
collection: hooksSlug,
|
||||||
|
overrideAccess: false,
|
||||||
|
data: {
|
||||||
|
cannotMutateNotRequired: 'updated',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// should fallback to original data and not throw validation error
|
||||||
|
expect(updatedDoc.cannotMutateRequired).toBe('cannotMutateRequired')
|
||||||
|
expect(updatedDoc.cannotMutateNotRequired).toBe('cannotMutateNotRequired')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to restrict access based upon siblingData', async () => {
|
|
||||||
const { id } = await payload.create({
|
|
||||||
collection: siblingDataSlug,
|
|
||||||
data: {
|
|
||||||
array: [
|
|
||||||
{
|
|
||||||
allowPublicReadability: true,
|
|
||||||
text: firstArrayText,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
allowPublicReadability: false,
|
|
||||||
text: secondArrayText,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const doc = await payload.findByID({
|
|
||||||
id,
|
|
||||||
collection: siblingDataSlug,
|
|
||||||
overrideAccess: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(doc.array?.[0].text).toBe(firstArrayText)
|
|
||||||
// Should respect PublicReadabilityAccess function and not be sent
|
|
||||||
expect(doc.array?.[1].text).toBeUndefined()
|
|
||||||
|
|
||||||
// Retrieve with default of overriding access
|
|
||||||
const docOverride = await payload.findByID({
|
|
||||||
id,
|
|
||||||
collection: siblingDataSlug,
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(docOverride.array?.[0].text).toBe(firstArrayText)
|
|
||||||
expect(docOverride.array?.[1].text).toBe(secondArrayText)
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('Collections', () => {
|
describe('Collections', () => {
|
||||||
describe('restricted collection', () => {
|
describe('restricted collection', () => {
|
||||||
it('field without read access should not show', async () => {
|
it('field without read access should not show', async () => {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ export interface Config {
|
|||||||
'rich-text': RichText;
|
'rich-text': RichText;
|
||||||
regression1: Regression1;
|
regression1: Regression1;
|
||||||
regression2: Regression2;
|
regression2: Regression2;
|
||||||
|
hooks: Hook;
|
||||||
'payload-locked-documents': PayloadLockedDocument;
|
'payload-locked-documents': PayloadLockedDocument;
|
||||||
'payload-preferences': PayloadPreference;
|
'payload-preferences': PayloadPreference;
|
||||||
'payload-migrations': PayloadMigration;
|
'payload-migrations': PayloadMigration;
|
||||||
@@ -117,6 +118,7 @@ export interface Config {
|
|||||||
'rich-text': RichTextSelect<false> | RichTextSelect<true>;
|
'rich-text': RichTextSelect<false> | RichTextSelect<true>;
|
||||||
regression1: Regression1Select<false> | Regression1Select<true>;
|
regression1: Regression1Select<false> | Regression1Select<true>;
|
||||||
regression2: Regression2Select<false> | Regression2Select<true>;
|
regression2: Regression2Select<false> | Regression2Select<true>;
|
||||||
|
hooks: HooksSelect<false> | HooksSelect<true>;
|
||||||
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
'payload-locked-documents': PayloadLockedDocumentsSelect<false> | PayloadLockedDocumentsSelect<true>;
|
||||||
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
'payload-preferences': PayloadPreferencesSelect<false> | PayloadPreferencesSelect<true>;
|
||||||
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
|
||||||
@@ -680,6 +682,18 @@ export interface Regression2 {
|
|||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "hooks".
|
||||||
|
*/
|
||||||
|
export interface Hook {
|
||||||
|
id: string;
|
||||||
|
cannotMutateRequired: string;
|
||||||
|
cannotMutateNotRequired?: string | null;
|
||||||
|
canMutate?: string | null;
|
||||||
|
updatedAt: string;
|
||||||
|
createdAt: string;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "payload-locked-documents".
|
* via the `definition` "payload-locked-documents".
|
||||||
@@ -774,6 +788,10 @@ export interface PayloadLockedDocument {
|
|||||||
| ({
|
| ({
|
||||||
relationTo: 'regression2';
|
relationTo: 'regression2';
|
||||||
value: string | Regression2;
|
value: string | Regression2;
|
||||||
|
} | null)
|
||||||
|
| ({
|
||||||
|
relationTo: 'hooks';
|
||||||
|
value: string | Hook;
|
||||||
} | null);
|
} | null);
|
||||||
globalSlug?: string | null;
|
globalSlug?: string | null;
|
||||||
user:
|
user:
|
||||||
@@ -1168,6 +1186,17 @@ export interface Regression2Select<T extends boolean = true> {
|
|||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
|
* via the `definition` "hooks_select".
|
||||||
|
*/
|
||||||
|
export interface HooksSelect<T extends boolean = true> {
|
||||||
|
cannotMutateRequired?: T;
|
||||||
|
cannotMutateNotRequired?: T;
|
||||||
|
canMutate?: T;
|
||||||
|
updatedAt?: T;
|
||||||
|
createdAt?: T;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This interface was referenced by `Config`'s JSON-Schema
|
* This interface was referenced by `Config`'s JSON-Schema
|
||||||
* via the `definition` "payload-locked-documents_select".
|
* via the `definition` "payload-locked-documents_select".
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const slug = 'posts'
|
|||||||
export const unrestrictedSlug = 'unrestricted'
|
export const unrestrictedSlug = 'unrestricted'
|
||||||
export const readOnlySlug = 'read-only-collection'
|
export const readOnlySlug = 'read-only-collection'
|
||||||
export const readOnlyGlobalSlug = 'read-only-global'
|
export const readOnlyGlobalSlug = 'read-only-global'
|
||||||
|
export const hooksSlug = 'hooks'
|
||||||
|
|
||||||
export const userRestrictedCollectionSlug = 'user-restricted-collection'
|
export const userRestrictedCollectionSlug = 'user-restricted-collection'
|
||||||
export const fullyRestrictedSlug = 'fully-restricted'
|
export const fullyRestrictedSlug = 'fully-restricted'
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ export interface BeforeValidate {
|
|||||||
id: string;
|
id: string;
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
selection?: ('a' | 'b') | null;
|
selection?: ('a' | 'b') | null;
|
||||||
|
cannotMutate?: string | null;
|
||||||
|
canMutate?: string | null;
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
}
|
}
|
||||||
@@ -741,6 +743,8 @@ export interface BeforeChangeHooksSelect<T extends boolean = true> {
|
|||||||
export interface BeforeValidateSelect<T extends boolean = true> {
|
export interface BeforeValidateSelect<T extends boolean = true> {
|
||||||
title?: T;
|
title?: T;
|
||||||
selection?: T;
|
selection?: T;
|
||||||
|
cannotMutate?: T;
|
||||||
|
canMutate?: T;
|
||||||
updatedAt?: T;
|
updatedAt?: T;
|
||||||
createdAt?: T;
|
createdAt?: T;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user