From 19e01ea3ac24e542514ddae27addbfaabcff648b Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 10 Jul 2024 15:47:09 +0400 Subject: [PATCH] Add checks when resource is an entity --- docs/reference-guides/data/data-core.md | 4 ++-- packages/core-data/README.md | 4 ++-- packages/core-data/src/resolvers.js | 4 ++++ packages/core-data/src/selectors.ts | 11 ++++++++--- packages/core-data/src/test/resolvers.js | 19 +++++++++++++++++++ packages/core-data/src/test/selectors.js | 8 ++++++++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 23503ce411eda5..063052d1a43888 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -23,7 +23,7 @@ _Parameters_ _Returns_ -- `boolean | undefined`: Whether or not the user can perform the action, or `undefined` if the OPTIONS request is still being made. +- `boolean | undefined | null`: Whether or not the user can perform the action, or `undefined` if the OPTIONS request is still being made. ### canUserEditEntityRecord @@ -42,7 +42,7 @@ _Parameters_ _Returns_ -- `boolean | undefined`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. +- `boolean | undefined | null`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. ### getAuthors diff --git a/packages/core-data/README.md b/packages/core-data/README.md index 90f53a61a28331..d6e6d97e9a1d77 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -344,7 +344,7 @@ _Parameters_ _Returns_ -- `boolean | undefined`: Whether or not the user can perform the action, or `undefined` if the OPTIONS request is still being made. +- `boolean | undefined | null`: Whether or not the user can perform the action, or `undefined` if the OPTIONS request is still being made. ### canUserEditEntityRecord @@ -363,7 +363,7 @@ _Parameters_ _Returns_ -- `boolean | undefined`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. +- `boolean | undefined | null`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. ### getAuthors diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index 4882a79df2c823..446ba8466161d0 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -368,6 +368,10 @@ export const canUser = let resourcePath = null; if ( typeof resource === 'object' ) { + if ( ! resource.kind || ! resource.name ) { + return; + } + const configs = await dispatch( getOrLoadEntitiesConfig( resource.kind, resource.name ) ); diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 60aff2dab78bcb..7c82982553727c 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -1147,9 +1147,14 @@ export function canUser( action: string, resource: string | Record< string, any >, id?: EntityRecordKey -): boolean | undefined { +): boolean | undefined | null { + const isEntity = typeof resource === 'object'; + if ( isEntity && ( ! resource.kind || ! resource.name ) ) { + return null; + } + const key = ( - typeof resource === 'object' + isEntity ? [ action, resource.kind, resource.name, resource.id ] : [ action, resource, id ] ) @@ -1179,7 +1184,7 @@ export function canUserEditEntityRecord( kind: string, name: string, recordId: EntityRecordKey -): boolean | undefined { +): boolean | undefined | null { return canUser( state, 'update', { kind, name, id: recordId } ); } diff --git a/packages/core-data/src/test/resolvers.js b/packages/core-data/src/test/resolvers.js index e99f9f2b4e098f..c751a67f73d46e 100644 --- a/packages/core-data/src/test/resolvers.js +++ b/packages/core-data/src/test/resolvers.js @@ -333,6 +333,25 @@ describe( 'canUser', () => { expect( dispatch.receiveUserPermission ).not.toHaveBeenCalled(); } ); + it( 'does nothing when entity kind or name is missing', async () => { + triggerFetch.mockImplementation( () => + Promise.reject( { status: 404 } ) + ); + + await canUser( 'create', { kind: 'root', name: 'media' } )( { + dispatch, + registry, + } ); + await canUser( 'create', { name: 'wp_block' } )( { + dispatch, + registry, + } ); + + expect( triggerFetch ).not.toHaveBeenCalledWith(); + + expect( dispatch.receiveUserPermission ).not.toHaveBeenCalled(); + } ); + it( 'receives false when the user is not allowed to perform an action', async () => { triggerFetch.mockImplementation( () => ( { headers: new Map( [ [ 'allow', 'GET' ] ] ), diff --git a/packages/core-data/src/test/selectors.js b/packages/core-data/src/test/selectors.js index 7c917f703eeb6a..b3edbab9b69263 100644 --- a/packages/core-data/src/test/selectors.js +++ b/packages/core-data/src/test/selectors.js @@ -694,6 +694,14 @@ describe( 'canUser', () => { ).toBe( undefined ); } ); + it( 'returns null when entity kind or name is missing', () => { + const state = deepFreeze( { + userPermissions: {}, + } ); + expect( canUser( state, 'create', { name: 'media' } ) ).toBe( null ); + expect( canUser( state, 'create', { kind: 'root' } ) ).toBe( null ); + } ); + it( 'returns whether an action can be performed', () => { const state = deepFreeze( { userPermissions: {