feat: add join field config where property (#8973)

### What?

Makes it possible to filter join documents using a `where` added
directly in the config.


### Why?

It makes the join field more powerful for adding contextual meaning to
the documents being returned. For example, maybe you have a
`requiresAction` field that you set and you can have a join that
automatically filters the documents to those that need attention.

### How?

In the database adapter, we merge the requested `where` to the `where`
defined on the field.
On the frontend the results are filtered using the `filterOptions`
property in the component.

Fixes
https://github.com/payloadcms/payload/discussions/8936
https://github.com/payloadcms/payload/discussions/8937

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
This commit is contained in:
Dan Ribbens
2024-11-06 10:06:25 -05:00
committed by GitHub
parent cdcefa88f2
commit 93a55d1075
19 changed files with 596 additions and 67 deletions

View File

@@ -41,8 +41,12 @@ const openAccess = {
}
const PublicReadabilityAccess: FieldAccess = ({ req: { user }, siblingData }) => {
if (user) return true
if (siblingData?.allowPublicReadability) return true
if (user) {
return true
}
if (siblingData?.allowPublicReadability) {
return true
}
return false
}
@@ -187,6 +191,23 @@ export default buildConfigWithDefaults({
},
],
},
{
slug: 'relation-restricted',
access: {
read: () => true,
},
fields: [
{
name: 'name',
type: 'text',
},
{
name: 'post',
type: 'relationship',
relationTo: slug,
},
],
},
{
slug: fullyRestrictedSlug,
access: {
@@ -261,7 +282,9 @@ export default buildConfigWithDefaults({
slug: restrictedVersionsSlug,
access: {
read: ({ req: { user } }) => {
if (user) return true
if (user) {
return true
}
return {
hidden: {
@@ -270,7 +293,9 @@ export default buildConfigWithDefaults({
}
},
readVersions: ({ req: { user } }) => {
if (user) return true
if (user) {
return true
}
return {
'version.hidden': {
@@ -428,7 +453,9 @@ export default buildConfigWithDefaults({
slug: hiddenAccessSlug,
access: {
read: ({ req: { user } }) => {
if (user) return true
if (user) {
return true
}
return {
hidden: {
@@ -454,7 +481,9 @@ export default buildConfigWithDefaults({
slug: hiddenAccessCountSlug,
access: {
read: ({ req: { user } }) => {
if (user) return true
if (user) {
return true
}
return {
hidden: {

View File

@@ -175,6 +175,47 @@ describe('Access Control', () => {
expect(retrievedDoc.restrictedField).toBeUndefined()
})
it('should error when querying field without read access', async () => {
const { id } = await createDoc({ restrictedField: 'restricted' })
await expect(
async () =>
await payload.find({
collection: slug,
overrideAccess: false,
where: {
and: [
{
id: { equals: id },
},
{
restrictedField: {
equals: 'restricted',
},
},
],
},
}),
).rejects.toThrow('The following path cannot be queried: restrictedField')
})
it('should respect access control for join request where queries of relationship properties', async () => {
const post = await createDoc({})
await createDoc({ post: post.id, name: 'test' }, 'relation-restricted')
await expect(
async () =>
await payload.find({
collection: 'relation-restricted',
overrideAccess: false,
where: {
'post.restrictedField': {
equals: 'restricted',
},
},
}),
).rejects.toThrow('The following path cannot be queried: restrictedField')
})
it('field without read access should not show when overrideAccess: true', async () => {
const { id, restrictedField } = await createDoc({ restrictedField: 'restricted' })