diff --git a/packages/payload/src/query-presets/access.ts b/packages/payload/src/query-presets/access.ts index 4d62a088c..d7bb05049 100644 --- a/packages/payload/src/query-presets/access.ts +++ b/packages/payload/src/query-presets/access.ts @@ -71,7 +71,17 @@ export const getAccess = (config: Config): Record => return { and: [ - ...(typeof constraintAccess === 'object' ? [constraintAccess] : []), + ...(typeof constraintAccess === 'object' + ? [constraintAccess] + : constraintAccess === false + ? [ + { + id: { + equals: null, + }, + }, + ] + : []), { [`access.${operation}.constraint`]: { equals: constraint.value, diff --git a/packages/payload/src/query-presets/constraints.ts b/packages/payload/src/query-presets/constraints.ts index 2453276b5..8e9cec4f5 100644 --- a/packages/payload/src/query-presets/constraints.ts +++ b/packages/payload/src/query-presets/constraints.ts @@ -78,7 +78,7 @@ export const getConstraints = (config: Config): Field => ({ }, ...(config?.queryPresets?.constraints?.[operation]?.reduce( (acc: Field[], option: QueryPresetConstraint) => { - option.fields.forEach((field, index) => { + option.fields?.forEach((field, index) => { acc.push({ ...field }) if (fieldAffectsData(field)) { diff --git a/packages/payload/src/query-presets/types.ts b/packages/payload/src/query-presets/types.ts index a2f35de73..722a2fc6e 100644 --- a/packages/payload/src/query-presets/types.ts +++ b/packages/payload/src/query-presets/types.ts @@ -25,7 +25,7 @@ export type QueryPreset = { export type QueryPresetConstraint = { access: Access - fields: Field[] + fields?: Field[] label: string value: string } diff --git a/test/query-presets/config.ts b/test/query-presets/config.ts index 2a786ef4a..ebf5dd111 100644 --- a/test/query-presets/config.ts +++ b/test/query-presets/config.ts @@ -24,9 +24,9 @@ export default buildConfigWithDefaults({ // }, access: { read: ({ req: { user } }) => - user ? !user?.roles?.some((role) => role === 'anonymous') : false, + user ? user && !user?.roles?.some((role) => role === 'anonymous') : false, update: ({ req: { user } }) => - user ? !user?.roles?.some((role) => role === 'anonymous') : false, + user ? user && !user?.roles?.some((role) => role === 'anonymous') : false, }, constraints: { read: [ @@ -40,6 +40,11 @@ export default buildConfigWithDefaults({ }, }), }, + { + label: 'Noone', + value: 'noone', + access: () => false, + }, ], update: [ { diff --git a/test/query-presets/int.spec.ts b/test/query-presets/int.spec.ts index 3fba8f4f6..42bd771ac 100644 --- a/test/query-presets/int.spec.ts +++ b/test/query-presets/int.spec.ts @@ -503,6 +503,42 @@ describe('Query Presets', () => { expect((error as Error).message).toBe('You are not allowed to perform this action.') } }) + + it('should respect boolean access control results', async () => { + // create a preset with the read constraint set to "noone" + const presetForNoone = await payload.create({ + collection: queryPresetsCollectionSlug, + user, + data: { + relatedCollection: 'pages', + title: 'Noone', + where: { + text: { + equals: 'example page', + }, + }, + access: { + read: { + constraint: 'noone', + }, + }, + }, + }) + + try { + const foundPresetWithUser1 = await payload.findByID({ + collection: queryPresetsCollectionSlug, + depth: 0, + user, + overrideAccess: false, + id: presetForNoone.id, + }) + + expect(foundPresetWithUser1).toBeFalsy() + } catch (error: unknown) { + expect((error as Error).message).toBe('Not Found') + } + }) }) it.skip('should disable query presets when "enabledQueryPresets" is not true on the collection', async () => { diff --git a/test/query-presets/payload-types.ts b/test/query-presets/payload-types.ts index 759cc0ae9..391874044 100644 --- a/test/query-presets/payload-types.ts +++ b/test/query-presets/payload-types.ts @@ -86,7 +86,7 @@ export interface Config { 'payload-query-presets': PayloadQueryPresetsSelect | PayloadQueryPresetsSelect; }; db: { - defaultIDType: number; + defaultIDType: string; }; globals: {}; globalsSelect: {}; @@ -122,7 +122,7 @@ export interface UserAuthOperations { * via the `definition` "pages". */ export interface Page { - id: number; + id: string; text?: string | null; updatedAt: string; createdAt: string; @@ -133,7 +133,7 @@ export interface Page { * via the `definition` "users". */ export interface User { - id: number; + id: string; name?: string | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; updatedAt: string; @@ -152,7 +152,7 @@ export interface User { * via the `definition` "posts". */ export interface Post { - id: number; + id: string; text?: string | null; updatedAt: string; createdAt: string; @@ -163,24 +163,24 @@ export interface Post { * via the `definition` "payload-locked-documents". */ export interface PayloadLockedDocument { - id: number; + id: string; document?: | ({ relationTo: 'pages'; - value: number | Page; + value: string | Page; } | null) | ({ relationTo: 'users'; - value: number | User; + value: string | User; } | null) | ({ relationTo: 'posts'; - value: number | Post; + value: string | Post; } | null); globalSlug?: string | null; user: { relationTo: 'users'; - value: number | User; + value: string | User; }; updatedAt: string; createdAt: string; @@ -190,10 +190,10 @@ export interface PayloadLockedDocument { * via the `definition` "payload-preferences". */ export interface PayloadPreference { - id: number; + id: string; user: { relationTo: 'users'; - value: number | User; + value: string | User; }; key?: string | null; value?: @@ -213,7 +213,7 @@ export interface PayloadPreference { * via the `definition` "payload-migrations". */ export interface PayloadMigration { - id: number; + id: string; name?: string | null; batch?: number | null; updatedAt: string; @@ -224,23 +224,23 @@ export interface PayloadMigration { * via the `definition` "payload-query-presets". */ export interface PayloadQueryPreset { - id: number; + id: string; title: string; isShared?: boolean | null; access?: { read?: { - constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (number | User)[] | null; + constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles' | 'noone') | null; + users?: (string | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; update?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers' | 'specificRoles') | null; - users?: (number | User)[] | null; + users?: (string | User)[] | null; roles?: ('admin' | 'user' | 'anonymous')[] | null; }; delete?: { constraint?: ('everyone' | 'onlyMe' | 'specificUsers') | null; - users?: (number | User)[] | null; + users?: (string | User)[] | null; }; }; where?: diff --git a/test/query-presets/seed.ts b/test/query-presets/seed.ts index 38f116f67..029c28391 100644 --- a/test/query-presets/seed.ts +++ b/test/query-presets/seed.ts @@ -167,6 +167,21 @@ export const seed = async (_payload: Payload) => { overrideAccess: false, data: seedData.onlyMe, }), + () => + _payload.create({ + collection: 'payload-query-presets', + user: devUser, + overrideAccess: false, + data: { + relatedCollection: 'pages', + title: 'Noone', + access: { + read: { + constraint: 'noone', + }, + }, + }, + }), ], false, ) diff --git a/tsconfig.base.json b/tsconfig.base.json index e2b64e3bc..daa36c721 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -31,7 +31,7 @@ } ], "paths": { - "@payload-config": ["./test/form-state/config.ts"], + "@payload-config": ["./test/query-presets/config.ts"], "@payloadcms/admin-bar": ["./packages/admin-bar/src"], "@payloadcms/live-preview": ["./packages/live-preview/src"], "@payloadcms/live-preview-react": ["./packages/live-preview-react/src/index.ts"],