chore: move to eslint v9 (#7041)
- Upgrades eslint from v8 to v9 - Upgrades all other eslint packages. We will have to do a new full-project lint, as new rules have been added - Upgrades husky from v8 to v9 - Upgrades lint-staged from v14 to v15 - Moves the old .eslintrc.cjs file format to the new eslint.config.js flat file format. Previously, we were very specific regarding which rules are applied to which files. Now that `extends` is no longer a thing, I have to use deepMerge & imports instead. This is rather uncommon and is not a documented pattern - e.g. typescript-eslint docs want us to add the default typescript-eslint rules to the top-level & then disable it in files using the disable-typechecked config. However, I hate this opt-out approach. The way I did it here adds a lot of clarity as to which rules are applied to which files, and is pretty easy to read. Much less black magic ## .eslintignore These files are no longer supported (see https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files). I moved the entries to the ignores property in the eslint config. => one less file in each package folder!
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
ignorePatterns: ['payload-types.ts'],
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.eslint.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
},
|
||||
}
|
||||
@@ -4,6 +4,8 @@ const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
import type { FieldAccess } from 'payload'
|
||||
|
||||
import type { Config, User } from './payload-types.js'
|
||||
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
import { TestButton } from './TestButton.js'
|
||||
@@ -34,9 +36,9 @@ import {
|
||||
|
||||
const openAccess = {
|
||||
create: () => true,
|
||||
delete: () => true,
|
||||
read: () => true,
|
||||
update: () => true,
|
||||
delete: () => true,
|
||||
}
|
||||
|
||||
const PublicReadabilityAccess: FieldAccess = ({ req: { user }, siblingData }) => {
|
||||
@@ -51,83 +53,20 @@ const UseRequestHeadersAccess: FieldAccess = ({ req: { headers } }) => {
|
||||
return !!headers && headers.get('authorization') === requestHeaders.get('authorization')
|
||||
}
|
||||
|
||||
function isUser(user: Config['user']): user is {
|
||||
collection: 'users'
|
||||
} & User {
|
||||
return user?.collection === 'users'
|
||||
}
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
admin: {
|
||||
user: 'users',
|
||||
autoLogin: false,
|
||||
user: 'users',
|
||||
},
|
||||
globals: [
|
||||
{
|
||||
slug: 'settings',
|
||||
fields: [
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'test',
|
||||
label: 'Allow access to test global',
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
components: {
|
||||
elements: {
|
||||
SaveButton: TestButton,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'test',
|
||||
fields: [],
|
||||
access: {
|
||||
read: async ({ req: { payload } }) => {
|
||||
const access = await payload.findGlobal({ slug: 'settings' })
|
||||
return Boolean(access.test)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: readOnlyGlobalSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: userRestrictedGlobalSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
read: () => true,
|
||||
update: ({ req, data }) => data?.name === req.user?.email,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: readNotUpdateGlobalSlug,
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
collections: [
|
||||
{
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
access: {
|
||||
// admin: () => true,
|
||||
admin: async ({ req }) => {
|
||||
@@ -141,20 +80,21 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
},
|
||||
},
|
||||
auth: true,
|
||||
fields: [
|
||||
{
|
||||
name: 'roles',
|
||||
type: 'select',
|
||||
hasMany: true,
|
||||
options: ['admin', 'user'],
|
||||
defaultValue: ['user'],
|
||||
access: {
|
||||
create: ({ req }) => req.user?.roles?.includes('admin'),
|
||||
create: ({ req }) => isUser(req.user) && req.user?.roles?.includes('admin'),
|
||||
read: () => false,
|
||||
update: ({ req }) => {
|
||||
return req.user?.roles?.includes('admin')
|
||||
return isUser(req.user) && req.user?.roles?.includes('admin')
|
||||
},
|
||||
},
|
||||
defaultValue: ['user'],
|
||||
hasMany: true,
|
||||
options: ['admin', 'user'],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -179,16 +119,16 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
name: 'group',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
name: 'restrictedGroupText',
|
||||
type: 'text',
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
create: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -200,27 +140,27 @@ export default buildConfigWithDefaults({
|
||||
name: 'restrictedRowText',
|
||||
type: 'text',
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
create: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Access',
|
||||
fields: [
|
||||
{
|
||||
name: 'restrictedCollapsibleText',
|
||||
type: 'text',
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
create: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
label: 'Access',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -234,71 +174,59 @@ export default buildConfigWithDefaults({
|
||||
{
|
||||
name: 'userRestrictedDocs',
|
||||
type: 'relationship',
|
||||
relationTo: userRestrictedCollectionSlug,
|
||||
hasMany: true,
|
||||
relationTo: userRestrictedCollectionSlug,
|
||||
},
|
||||
{
|
||||
name: 'createNotUpdateDocs',
|
||||
type: 'relationship',
|
||||
relationTo: createNotUpdateCollectionSlug,
|
||||
hasMany: true,
|
||||
relationTo: createNotUpdateCollectionSlug,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: fullyRestrictedSlug,
|
||||
access: {
|
||||
create: () => false,
|
||||
delete: () => false,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => false,
|
||||
update: () => false,
|
||||
delete: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: readOnlySlug,
|
||||
access: {
|
||||
create: () => false,
|
||||
delete: () => false,
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
create: () => false,
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
delete: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: userRestrictedCollectionSlug,
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
create: () => true,
|
||||
delete: () => false,
|
||||
read: () => true,
|
||||
update: ({ req }) => ({
|
||||
name: {
|
||||
equals: req.user?.email,
|
||||
},
|
||||
}),
|
||||
delete: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: createNotUpdateCollectionSlug,
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
@@ -308,27 +236,27 @@ export default buildConfigWithDefaults({
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
access: {
|
||||
create: () => true,
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
delete: () => false,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: restrictedVersionsSlug,
|
||||
versions: true,
|
||||
slug: createNotUpdateCollectionSlug,
|
||||
access: {
|
||||
create: () => true,
|
||||
delete: () => false,
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
admin: {
|
||||
useAsTitle: 'name',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'hidden',
|
||||
type: 'checkbox',
|
||||
hidden: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: restrictedVersionsSlug,
|
||||
access: {
|
||||
read: ({ req: { user } }) => {
|
||||
if (user) return true
|
||||
@@ -349,6 +277,18 @@ export default buildConfigWithDefaults({
|
||||
}
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'hidden',
|
||||
type: 'checkbox',
|
||||
hidden: true,
|
||||
},
|
||||
],
|
||||
versions: true,
|
||||
},
|
||||
{
|
||||
slug: siblingDataSlug,
|
||||
@@ -363,8 +303,8 @@ export default buildConfigWithDefaults({
|
||||
fields: [
|
||||
{
|
||||
name: 'allowPublicReadability',
|
||||
label: 'Allow Public Readability',
|
||||
type: 'checkbox',
|
||||
label: 'Allow Public Readability',
|
||||
},
|
||||
{
|
||||
name: 'text',
|
||||
@@ -383,9 +323,9 @@ export default buildConfigWithDefaults({
|
||||
slug: relyOnRequestHeadersSlug,
|
||||
access: {
|
||||
create: UseRequestHeadersAccess,
|
||||
delete: UseRequestHeadersAccess,
|
||||
read: UseRequestHeadersAccess,
|
||||
update: UseRequestHeadersAccess,
|
||||
delete: UseRequestHeadersAccess,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
@@ -396,10 +336,6 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
{
|
||||
slug: docLevelAccessSlug,
|
||||
labels: {
|
||||
singular: 'Doc Level Access',
|
||||
plural: 'Doc Level Access',
|
||||
},
|
||||
access: {
|
||||
delete: () => ({
|
||||
and: [
|
||||
@@ -420,7 +356,6 @@ export default buildConfigWithDefaults({
|
||||
{
|
||||
name: 'approvedTitle',
|
||||
type: 'text',
|
||||
localized: true,
|
||||
access: {
|
||||
update: (args) => {
|
||||
if (args?.doc?.lockTitle) {
|
||||
@@ -429,6 +364,7 @@ export default buildConfigWithDefaults({
|
||||
return true
|
||||
},
|
||||
},
|
||||
localized: true,
|
||||
},
|
||||
{
|
||||
name: 'lockTitle',
|
||||
@@ -436,6 +372,10 @@ export default buildConfigWithDefaults({
|
||||
defaultValue: false,
|
||||
},
|
||||
],
|
||||
labels: {
|
||||
plural: 'Doc Level Access',
|
||||
singular: 'Doc Level Access',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: hiddenFieldsSlug,
|
||||
@@ -536,6 +476,74 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
Disabled,
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: 'settings',
|
||||
admin: {
|
||||
components: {
|
||||
elements: {
|
||||
SaveButton: TestButton,
|
||||
},
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'test',
|
||||
type: 'checkbox',
|
||||
label: 'Allow access to test global',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'test',
|
||||
access: {
|
||||
read: async ({ req: { payload } }) => {
|
||||
const access = await payload.findGlobal({ slug: 'settings' })
|
||||
return Boolean(access.test)
|
||||
},
|
||||
},
|
||||
fields: [],
|
||||
},
|
||||
{
|
||||
slug: readOnlyGlobalSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: userRestrictedGlobalSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
update: ({ data, req }) => data?.name === req.user?.email,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: readNotUpdateGlobalSlug,
|
||||
access: {
|
||||
read: () => true,
|
||||
update: () => false,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
@@ -587,12 +595,12 @@ export default buildConfigWithDefaults({
|
||||
data: {
|
||||
array: [
|
||||
{
|
||||
text: firstArrayText,
|
||||
allowPublicReadability: true,
|
||||
text: firstArrayText,
|
||||
},
|
||||
{
|
||||
text: secondArrayText,
|
||||
allowPublicReadability: false,
|
||||
text: secondArrayText,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -422,9 +422,9 @@ describe('access control', () => {
|
||||
existingDoc = await payload.create({
|
||||
collection: docLevelAccessSlug,
|
||||
data: {
|
||||
approvedForRemoval: false,
|
||||
approvedTitle: 'Title',
|
||||
lockTitle: true,
|
||||
approvedForRemoval: false,
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -466,12 +466,12 @@ describe('access control', () => {
|
||||
await page.waitForURL(logoutURL)
|
||||
|
||||
await login({
|
||||
page,
|
||||
serverURL,
|
||||
data: {
|
||||
email: noAdminAccessEmail,
|
||||
password: 'test',
|
||||
},
|
||||
page,
|
||||
serverURL,
|
||||
})
|
||||
|
||||
await expect(page.locator('.next-error-h1')).toBeVisible()
|
||||
@@ -481,12 +481,12 @@ describe('access control', () => {
|
||||
|
||||
// Log back in for the next test
|
||||
await login({
|
||||
page,
|
||||
serverURL,
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
page,
|
||||
serverURL,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -500,9 +500,9 @@ describe('access control', () => {
|
||||
await page.goto(logoutURL)
|
||||
await page.waitForURL(logoutURL)
|
||||
|
||||
const nonAdminUser: NonAdminUser & {
|
||||
const nonAdminUser: {
|
||||
token?: string
|
||||
} = await payload.login({
|
||||
} & NonAdminUser = await payload.login({
|
||||
collection: nonAdminUserSlug,
|
||||
data: {
|
||||
email: nonAdminUserEmail,
|
||||
@@ -513,8 +513,8 @@ describe('access control', () => {
|
||||
await context.addCookies([
|
||||
{
|
||||
name: 'payload-token',
|
||||
value: nonAdminUser.token,
|
||||
url: serverURL,
|
||||
value: nonAdminUser.token,
|
||||
},
|
||||
])
|
||||
|
||||
@@ -554,10 +554,9 @@ describe('access control', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
async function createDoc(data: any): Promise<TypeWithID & Record<string, unknown>> {
|
||||
async function createDoc(data: any): Promise<Record<string, unknown> & TypeWithID> {
|
||||
return payload.create({
|
||||
collection: slug,
|
||||
data,
|
||||
}) as any as Promise<TypeWithID & Record<string, unknown>>
|
||||
}) as any as Promise<Record<string, unknown> & TypeWithID>
|
||||
}
|
||||
|
||||
20
test/access-control/eslint.config.js
Normal file
20
test/access-control/eslint.config.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { rootEslintConfig, rootParserOptions } from '../../eslint.config.js'
|
||||
|
||||
/** @typedef {import('eslint').Linter.FlatConfig} */
|
||||
let FlatConfig
|
||||
|
||||
/** @type {FlatConfig[]} */
|
||||
export const index = [
|
||||
...rootEslintConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: './tsconfig.eslint.json',
|
||||
tsconfigDirName: import.meta.dirname,
|
||||
...rootParserOptions,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export default index
|
||||
@@ -1,8 +1,14 @@
|
||||
import type { Payload, PayloadRequest } from 'payload'
|
||||
import type {
|
||||
CollectionSlug,
|
||||
DataFromCollectionSlug,
|
||||
Payload,
|
||||
PayloadRequest,
|
||||
RequiredDataFromCollectionSlug,
|
||||
} from 'payload'
|
||||
|
||||
import { Forbidden } from 'payload'
|
||||
|
||||
import type { Post, RelyOnRequestHeader, Restricted } from './payload-types.js'
|
||||
import type { FullyRestricted, Post } from './payload-types.js'
|
||||
|
||||
import { initPayloadInt } from '../helpers/initPayloadInt.js'
|
||||
import configPromise, { requestHeaders } from './config.js'
|
||||
@@ -23,7 +29,7 @@ let payload: Payload
|
||||
|
||||
describe('Access Control', () => {
|
||||
let post1: Post
|
||||
let restricted: Restricted
|
||||
let restricted: FullyRestricted
|
||||
|
||||
beforeAll(async () => {
|
||||
;({ payload } = await initPayloadInt(configPromise))
|
||||
@@ -32,7 +38,7 @@ describe('Access Control', () => {
|
||||
beforeEach(async () => {
|
||||
post1 = await payload.create({
|
||||
collection: slug,
|
||||
data: { name: 'name' },
|
||||
data: {},
|
||||
})
|
||||
|
||||
restricted = await payload.create({
|
||||
@@ -65,21 +71,21 @@ describe('Access Control', () => {
|
||||
})
|
||||
|
||||
await payload.update({
|
||||
collection: hiddenFieldsSlug,
|
||||
id: doc.id,
|
||||
collection: hiddenFieldsSlug,
|
||||
data: {
|
||||
title: 'Doc Title',
|
||||
},
|
||||
})
|
||||
|
||||
const updatedDoc = await payload.findByID({
|
||||
collection: hiddenFieldsSlug,
|
||||
id: doc.id,
|
||||
collection: hiddenFieldsSlug,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
|
||||
expect(updatedDoc.partiallyHiddenGroup.value).toEqual('private_value')
|
||||
expect(updatedDoc.partiallyHiddenArray[0].value).toEqual('private_value')
|
||||
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 () => {
|
||||
@@ -101,22 +107,22 @@ describe('Access Control', () => {
|
||||
|
||||
await payload.update({
|
||||
collection: hiddenFieldsSlug,
|
||||
where: {
|
||||
id: { equals: docsMany.id },
|
||||
},
|
||||
data: {
|
||||
title: 'Doc Title',
|
||||
},
|
||||
where: {
|
||||
id: { equals: docsMany.id },
|
||||
},
|
||||
})
|
||||
|
||||
const updatedMany = await payload.findByID({
|
||||
collection: hiddenFieldsSlug,
|
||||
id: docsMany.id,
|
||||
collection: hiddenFieldsSlug,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
|
||||
expect(updatedMany.partiallyHiddenGroup.value).toEqual('private_value')
|
||||
expect(updatedMany.partiallyHiddenArray[0].value).toEqual('private_value')
|
||||
expect(updatedMany.partiallyHiddenGroup.value).toStrictEqual('private_value')
|
||||
expect(updatedMany.partiallyHiddenArray[0].value).toStrictEqual('private_value')
|
||||
})
|
||||
|
||||
it('should be able to restrict access based upon siblingData', async () => {
|
||||
@@ -125,12 +131,12 @@ describe('Access Control', () => {
|
||||
data: {
|
||||
array: [
|
||||
{
|
||||
text: firstArrayText,
|
||||
allowPublicReadability: true,
|
||||
text: firstArrayText,
|
||||
},
|
||||
{
|
||||
text: secondArrayText,
|
||||
allowPublicReadability: false,
|
||||
text: secondArrayText,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -159,27 +165,27 @@ describe('Access Control', () => {
|
||||
describe('Collections', () => {
|
||||
describe('restricted collection', () => {
|
||||
it('field without read access should not show', async () => {
|
||||
const { id } = await createDoc<Post>({ restrictedField: 'restricted' })
|
||||
const { id } = await createDoc({ restrictedField: 'restricted' })
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id, overrideAccess: false })
|
||||
const retrievedDoc = await payload.findByID({ id, collection: slug, overrideAccess: false })
|
||||
|
||||
expect(retrievedDoc.restrictedField).toBeUndefined()
|
||||
})
|
||||
|
||||
it('field without read access should not show when overrideAccess: true', async () => {
|
||||
const { id, restrictedField } = await createDoc<Post>({ restrictedField: 'restricted' })
|
||||
const { id, restrictedField } = await createDoc({ restrictedField: 'restricted' })
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id, overrideAccess: true })
|
||||
const retrievedDoc = await payload.findByID({ id, collection: slug, overrideAccess: true })
|
||||
|
||||
expect(retrievedDoc.restrictedField).toEqual(restrictedField)
|
||||
expect(retrievedDoc.restrictedField).toStrictEqual(restrictedField)
|
||||
})
|
||||
|
||||
it('field without read access should not show when overrideAccess default', async () => {
|
||||
const { id, restrictedField } = await createDoc<Post>({ restrictedField: 'restricted' })
|
||||
const { id, restrictedField } = await createDoc({ restrictedField: 'restricted' })
|
||||
|
||||
const retrievedDoc = await payload.findByID({ collection: slug, id })
|
||||
const retrievedDoc = await payload.findByID({ id, collection: slug })
|
||||
|
||||
expect(retrievedDoc.restrictedField).toEqual(restrictedField)
|
||||
expect(retrievedDoc.restrictedField).toStrictEqual(restrictedField)
|
||||
})
|
||||
})
|
||||
describe('non-enumerated request properties passed to access control', () => {
|
||||
@@ -190,25 +196,25 @@ describe('Access Control', () => {
|
||||
const name = 'name'
|
||||
const overrideAccess = false
|
||||
|
||||
const { id } = await createDoc<RelyOnRequestHeader>({ name }, relyOnRequestHeadersSlug, {
|
||||
req,
|
||||
const { id } = await createDoc({ name }, relyOnRequestHeadersSlug, {
|
||||
overrideAccess,
|
||||
req,
|
||||
})
|
||||
const docById = await payload.findByID({
|
||||
collection: relyOnRequestHeadersSlug,
|
||||
id,
|
||||
req,
|
||||
collection: relyOnRequestHeadersSlug,
|
||||
overrideAccess,
|
||||
req,
|
||||
})
|
||||
const { docs: docsByName } = await payload.find({
|
||||
collection: relyOnRequestHeadersSlug,
|
||||
overrideAccess,
|
||||
req,
|
||||
where: {
|
||||
name: {
|
||||
equals: name,
|
||||
},
|
||||
},
|
||||
req,
|
||||
overrideAccess,
|
||||
})
|
||||
|
||||
expect(docById).not.toBeUndefined()
|
||||
@@ -220,23 +226,25 @@ describe('Access Control', () => {
|
||||
const overrideAccess = false
|
||||
|
||||
await expect(() =>
|
||||
createDoc<RelyOnRequestHeader>({ name }, relyOnRequestHeadersSlug, { overrideAccess }),
|
||||
createDoc({ name }, relyOnRequestHeadersSlug, {
|
||||
overrideAccess,
|
||||
}),
|
||||
).rejects.toThrow(Forbidden)
|
||||
const { id } = await createDoc<RelyOnRequestHeader>({ name }, relyOnRequestHeadersSlug)
|
||||
const { id } = await createDoc({ name }, relyOnRequestHeadersSlug)
|
||||
|
||||
await expect(() =>
|
||||
payload.findByID({ collection: relyOnRequestHeadersSlug, id, overrideAccess }),
|
||||
payload.findByID({ id, collection: relyOnRequestHeadersSlug, overrideAccess }),
|
||||
).rejects.toThrow(Forbidden)
|
||||
|
||||
await expect(() =>
|
||||
payload.find({
|
||||
collection: relyOnRequestHeadersSlug,
|
||||
overrideAccess,
|
||||
where: {
|
||||
name: {
|
||||
equals: name,
|
||||
},
|
||||
},
|
||||
overrideAccess,
|
||||
}),
|
||||
).rejects.toThrow(Forbidden)
|
||||
})
|
||||
@@ -248,8 +256,8 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess: false', async () => {
|
||||
const req = async () =>
|
||||
await payload.update({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: false, // this should respect access control
|
||||
})
|
||||
@@ -259,8 +267,8 @@ describe('Access Control', () => {
|
||||
|
||||
it('should allow overrideAccess: true', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: true, // this should override access control
|
||||
})
|
||||
@@ -270,8 +278,8 @@ describe('Access Control', () => {
|
||||
|
||||
it('should allow overrideAccess by default', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: slug,
|
||||
id: post1.id,
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
})
|
||||
|
||||
@@ -282,11 +290,11 @@ describe('Access Control', () => {
|
||||
const req = async () =>
|
||||
await payload.update({
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: false, // this should respect access control
|
||||
where: {
|
||||
id: { equals: post1.id },
|
||||
},
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: false, // this should respect access control
|
||||
})
|
||||
|
||||
await expect(req).rejects.toThrow(Forbidden)
|
||||
@@ -295,11 +303,11 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess: true - update many', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: true, // this should override access control
|
||||
where: {
|
||||
id: { equals: post1.id },
|
||||
},
|
||||
data: { restrictedField: restricted.id },
|
||||
overrideAccess: true, // this should override access control
|
||||
})
|
||||
|
||||
expect(doc.docs[0]).toMatchObject({ id: post1.id })
|
||||
@@ -308,10 +316,10 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess by default - update many', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: slug,
|
||||
data: { restrictedField: restricted.id },
|
||||
where: {
|
||||
id: { equals: post1.id },
|
||||
},
|
||||
data: { restrictedField: restricted.id },
|
||||
})
|
||||
|
||||
expect(doc.docs[0]).toMatchObject({ id: post1.id })
|
||||
@@ -324,8 +332,8 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess: false', async () => {
|
||||
const req = async () =>
|
||||
await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
id: restricted.id,
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: false, // this should respect access control
|
||||
})
|
||||
@@ -335,8 +343,8 @@ describe('Access Control', () => {
|
||||
|
||||
it('should allow overrideAccess: true', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
id: restricted.id,
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: true, // this should override access control
|
||||
})
|
||||
@@ -346,8 +354,8 @@ describe('Access Control', () => {
|
||||
|
||||
it('should allow overrideAccess by default', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
id: restricted.id,
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
})
|
||||
|
||||
@@ -358,11 +366,11 @@ describe('Access Control', () => {
|
||||
const req = async () =>
|
||||
await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: false, // this should respect access control
|
||||
where: {
|
||||
id: { equals: restricted.id },
|
||||
},
|
||||
data: { name: updatedName },
|
||||
overrideAccess: false, // this should respect access control
|
||||
})
|
||||
|
||||
await expect(req).rejects.toThrow(Forbidden)
|
||||
@@ -371,11 +379,11 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess: true - update many', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
overrideAccess: true, // this should override access control
|
||||
where: {
|
||||
id: { equals: restricted.id },
|
||||
},
|
||||
data: { name: updatedName },
|
||||
overrideAccess: true, // this should override access control
|
||||
})
|
||||
|
||||
expect(doc.docs[0]).toMatchObject({ id: restricted.id, name: updatedName })
|
||||
@@ -384,10 +392,10 @@ describe('Access Control', () => {
|
||||
it('should allow overrideAccess by default - update many', async () => {
|
||||
const doc = await payload.update({
|
||||
collection: fullyRestrictedSlug,
|
||||
data: { name: updatedName },
|
||||
where: {
|
||||
id: { equals: restricted.id },
|
||||
},
|
||||
data: { name: updatedName },
|
||||
})
|
||||
|
||||
expect(doc.docs[0]).toMatchObject({ id: restricted.id, name: updatedName })
|
||||
@@ -407,8 +415,8 @@ describe('Access Control', () => {
|
||||
await payload.create({
|
||||
collection: hiddenAccessSlug,
|
||||
data: {
|
||||
title: 'hello',
|
||||
hidden: true,
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -431,8 +439,8 @@ describe('Access Control', () => {
|
||||
await payload.create({
|
||||
collection: hiddenAccessCountSlug,
|
||||
data: {
|
||||
title: 'hello',
|
||||
hidden: true,
|
||||
title: 'hello',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -461,11 +469,11 @@ describe('Access Control', () => {
|
||||
},
|
||||
})
|
||||
const { docs } = await payload.findVersions({
|
||||
collection: restrictedVersionsSlug,
|
||||
overrideAccess: false,
|
||||
where: {
|
||||
'version.name': { equals: 'match' },
|
||||
},
|
||||
collection: restrictedVersionsSlug,
|
||||
overrideAccess: false,
|
||||
})
|
||||
|
||||
expect(docs).toHaveLength(1)
|
||||
@@ -473,14 +481,16 @@ describe('Access Control', () => {
|
||||
})
|
||||
})
|
||||
|
||||
async function createDoc<Collection>(
|
||||
data: Partial<Collection>,
|
||||
overrideSlug = slug,
|
||||
async function createDoc<TSlug extends CollectionSlug = 'posts'>(
|
||||
data: RequiredDataFromCollectionSlug<TSlug>,
|
||||
overrideSlug?: TSlug,
|
||||
options?: Partial<Parameters<Payload['create']>[0]>,
|
||||
) {
|
||||
): Promise<DataFromCollectionSlug<TSlug>> {
|
||||
// @ts-expect-error
|
||||
return await payload.create({
|
||||
...options,
|
||||
collection: overrideSlug,
|
||||
collection: overrideSlug ?? slug,
|
||||
// @ts-expect-error
|
||||
data: data ?? {},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user