Skip to content

Commit

Permalink
Core Data: Support entity queries in the 'useResourcePermissions' hook (
Browse files Browse the repository at this point in the history
WordPress#63653)


Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: tyxla <[email protected]>
Co-authored-by: gziolo <[email protected]>
  • Loading branch information
4 people authored Jul 24, 2024
1 parent 0b94a19 commit 6128cea
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 52 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 8 additions & 14 deletions packages/block-library/src/navigation-link/link-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,18 @@ function LinkUIBlockInserter( { clientId, onBack, onSelectBlock } ) {
}

function UnforwardedLinkUI( props, ref ) {
const { label, url, opensInNewTab, type, kind } = props.link;
const postType = type || 'page';

const [ addingBlock, setAddingBlock ] = useState( false );
const [ focusAddBlockButton, setFocusAddBlockButton ] = useState( false );
const { saveEntityRecord } = useDispatch( coreStore );
const pagesPermissions = useResourcePermissions( 'pages' );
const postsPermissions = useResourcePermissions( 'posts' );
const permissions = useResourcePermissions( {
kind: 'postType',
name: postType,
} );

async function handleCreate( pageTitle ) {
const postType = props.link.type || 'page';

const page = await saveEntityRecord( 'postType', postType, {
title: pageTitle,
status: 'draft',
Expand All @@ -180,15 +183,6 @@ function UnforwardedLinkUI( props, ref ) {
};
}

const { label, url, opensInNewTab, type, kind } = props.link;

let userCanCreate = false;
if ( ! type || type === 'page' ) {
userCanCreate = pagesPermissions.canCreate;
} else if ( type === 'post' ) {
userCanCreate = postsPermissions.canCreate;
}

// Memoize link value to avoid overriding the LinkControl's internal state.
// This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.
const link = useMemo(
Expand Down Expand Up @@ -241,7 +235,7 @@ function UnforwardedLinkUI( props, ref ) {
hasRichPreviews
value={ link }
showInitialSuggestions
withCreateSuggestion={ userCanCreate }
withCreateSuggestion={ permissions.canCreate }
createSuggestion={ handleCreate }
createSuggestionButtonText={ ( searchTerm ) => {
let format;
Expand Down
69 changes: 54 additions & 15 deletions packages/block-library/src/navigation/test/use-navigation-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import { store as coreStore } from '@wordpress/core-data';
*/
import useNavigationMenu from '../use-navigation-menu';

const BASE_ENTITY = {
kind: 'postType',
name: 'wp_navigation',
id: undefined,
};

function createRegistryWithStores() {
// Create a registry and register used stores.
const registry = createRegistry();
Expand Down Expand Up @@ -63,37 +69,70 @@ function resolveRecords( registry, menus ) {

function resolveReadPermission( registry, allowed ) {
const dispatch = registry.dispatch( coreStore );
dispatch.receiveUserPermission( 'create/navigation', allowed );
dispatch.startResolution( 'canUser', [ 'read', 'navigation' ] );
dispatch.finishResolution( 'canUser', [ 'read', 'navigation' ] );
dispatch.receiveUserPermission( 'read/postType/wp_navigation', allowed );
dispatch.startResolution( 'canUser', [ 'read', BASE_ENTITY ] );
dispatch.finishResolution( 'canUser', [ 'read', BASE_ENTITY ] );
}

function resolveReadRecordPermission( registry, ref, allowed ) {
const dispatch = registry.dispatch( coreStore );
dispatch.receiveUserPermission( 'create/navigation', allowed );
dispatch.startResolution( 'canUser', [ 'read', 'navigation', ref ] );
dispatch.finishResolution( 'canUser', [ 'read', 'navigation', ref ] );
dispatch.receiveUserPermission(
`read/postType/wp_navigation/${ ref }`,
allowed
);
dispatch.startResolution( 'canUser', [
'read',
{ ...BASE_ENTITY, id: ref },
] );
dispatch.finishResolution( 'canUser', [
'read',
{ ...BASE_ENTITY, id: ref },
] );
}

function resolveCreatePermission( registry, allowed ) {
const dispatch = registry.dispatch( coreStore );
dispatch.receiveUserPermission( 'create/navigation', allowed );
dispatch.startResolution( 'canUser', [ 'create', 'navigation' ] );
dispatch.finishResolution( 'canUser', [ 'create', 'navigation' ] );
dispatch.receiveUserPermission( 'create/postType/wp_navigation', allowed );
dispatch.startResolution( 'canUser', [
'create',
{ kind: 'postType', name: 'wp_navigation' },
] );
dispatch.finishResolution( 'canUser', [
'create',
{ kind: 'postType', name: 'wp_navigation' },
] );
}

function resolveUpdatePermission( registry, ref, allowed ) {
const dispatch = registry.dispatch( coreStore );
dispatch.receiveUserPermission( `update/navigation/${ ref }`, allowed );
dispatch.startResolution( 'canUser', [ 'update', 'navigation', ref ] );
dispatch.finishResolution( 'canUser', [ 'update', 'navigation', ref ] );
dispatch.receiveUserPermission(
`update/postType/wp_navigation/${ ref }`,
allowed
);
dispatch.startResolution( 'canUser', [
'update',
{ ...BASE_ENTITY, id: ref },
] );
dispatch.finishResolution( 'canUser', [
'update',
{ ...BASE_ENTITY, id: ref },
] );
}

function resolveDeletePermission( registry, ref, allowed ) {
const dispatch = registry.dispatch( coreStore );
dispatch.receiveUserPermission( `delete/navigation/${ ref }`, allowed );
dispatch.startResolution( 'canUser', [ 'delete', 'navigation', ref ] );
dispatch.finishResolution( 'canUser', [ 'delete', 'navigation', ref ] );
dispatch.receiveUserPermission(
`delete/postType/wp_navigation/${ ref }`,
allowed
);
dispatch.startResolution( 'canUser', [
'delete',
{ ...BASE_ENTITY, id: ref },
] );
dispatch.finishResolution( 'canUser', [
'delete',
{ ...BASE_ENTITY, id: ref },
] );
}

describe( 'useNavigationMenus', () => {
Expand Down
6 changes: 5 additions & 1 deletion packages/block-library/src/navigation/use-navigation-menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import { useSelect } from '@wordpress/data';
import { PRELOADED_NAVIGATION_MENUS_QUERY } from './constants';

export default function useNavigationMenu( ref ) {
const permissions = useResourcePermissions( 'navigation', ref );
const permissions = useResourcePermissions( {
kind: 'postType',
name: 'wp_navigation',
id: ref,
} );

const {
navigationMenu,
Expand Down
15 changes: 11 additions & 4 deletions packages/core-data/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,10 @@ _Usage_
import { useResourcePermissions } from '@wordpress/core-data';

function PagesList() {
const { canCreate, isResolving } = useResourcePermissions( 'pages' );
const { canCreate, isResolving } = useResourcePermissions( {
kind: 'postType',
name: 'page',
} );

if ( isResolving ) {
return 'Loading ...';
Expand All @@ -1196,7 +1199,11 @@ import { useResourcePermissions } from '@wordpress/core-data';

function Page( { pageId } ) {
const { canCreate, canUpdate, canDelete, isResolving } =
useResourcePermissions( 'pages', pageId );
useResourcePermissions( {
kind: 'postType',
name: 'page',
id: pageId,
} );

if ( isResolving ) {
return 'Loading ...';
Expand All @@ -1222,8 +1229,8 @@ the store state using `canUser()`, or resolved if missing.

_Parameters_

- _resource_ `string`: The resource in question, e.g. media.
- _id_ `IdType`: ID of a specific resource entry, if needed, e.g. 10.
- _resource_ `string | EntityResource`: Entity resource to check. Accepts entity object `{ kind: 'root', name: 'media', id: 1 }` or REST base as a string - `media`.
- _id_ `IdType`: Optional ID of the resource to check, e.g. 10. Note: This argument is discouraged when using an entity object as a resource to check permissions and will be ignored.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions packages/core-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@wordpress/sync": "file:../sync",
"@wordpress/undo-manager": "file:../undo-manager",
"@wordpress/url": "file:../url",
"@wordpress/warning": "file:../warning",
"change-case": "^4.1.2",
"equivalent-key-map": "^0.2.2",
"fast-deep-equal": "^3.1.3",
Expand Down
93 changes: 93 additions & 0 deletions packages/core-data/src/hooks/test/use-resource-permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,97 @@ describe( 'useResourcePermissions', () => {
} )
);
} );

it( 'retrieves the relevant permissions for a id-less entity', async () => {
let data;
const TestComponent = () => {
data = useResourcePermissions( {
kind: 'root',
name: 'media',
} );
return <div />;
};
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);
expect( data ).toEqual( {
status: 'IDLE',
isResolving: false,
hasResolved: false,
canCreate: false,
canRead: false,
} );

await waitFor( () =>
expect( data ).toEqual( {
status: 'SUCCESS',
isResolving: false,
hasResolved: true,
canCreate: true,
canRead: false,
} )
);
} );

it( 'retrieves the relevant permissions for an entity', async () => {
let data;
const TestComponent = () => {
data = useResourcePermissions( {
kind: 'root',
name: 'media',
id: 1,
} );
return <div />;
};
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);
expect( data ).toEqual( {
status: 'IDLE',
isResolving: false,
hasResolved: false,
canCreate: false,
canRead: false,
canUpdate: false,
canDelete: false,
} );

await waitFor( () =>
expect( data ).toEqual( {
status: 'SUCCESS',
isResolving: false,
hasResolved: true,
canCreate: true,
canRead: false,
canUpdate: false,
canDelete: false,
} )
);
} );

it( 'should warn when called with incorrect arguments signature', () => {
const TestComponent = () => {
useResourcePermissions(
{
kind: 'root',
name: 'media',
},
1
);
return null;
};
render(
<RegistryProvider value={ registry }>
<TestComponent />
</RegistryProvider>
);

expect( console ).toHaveWarnedWith(
`When 'resource' is an entity object, passing 'id' as a separate argument isn't supported.`
);
} );
} );
Loading

0 comments on commit 6128cea

Please sign in to comment.