Skip to content

Commit

Permalink
Dedupe logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Mamaduka committed Jul 15, 2024
1 parent d6c27cf commit 27b4b0d
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 62 deletions.
73 changes: 18 additions & 55 deletions packages/core-data/src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@ import apiFetch from '@wordpress/api-fetch';
*/
import { STORE_NAME } from './name';
import { getOrLoadEntitiesConfig, DEFAULT_ENTITY_KEY } from './entities';
import { forwardResolver, getNormalizedCommaSeparable } from './utils';
import {
forwardResolver,
getNormalizedCommaSeparable,
getUserPermissionCacheKey,
getUserPermissionsFromResponse,
ALLOWED_RESOURCE_ACTIONS,
} from './utils';
import { getSyncProvider } from './sync';
import { fetchBlockPatterns } from './fetch';

Expand Down Expand Up @@ -167,35 +173,16 @@ export const getEntityRecord =

const response = await apiFetch( { path, parse: false } );
const record = await response.json();

const allowHeader = response.headers?.get( 'allow' );
const allowedMethods = allowHeader?.allow || allowHeader || '';
const permissions = {};
const methods = {
create: 'POST',
read: 'GET',
update: 'PUT',
delete: 'DELETE',
};
for ( const [ actionName, methodName ] of Object.entries(
methods
) ) {
permissions[ actionName ] =
allowedMethods.includes( methodName );
}
const permissions = getUserPermissionsFromResponse( response );

registry.batch( () => {
dispatch.receiveEntityRecords( kind, name, record, query );

for ( const action of [
'create',
'read',
'update',
'delete',
] ) {
const permissionKey = [ action, kind, name, key ]
.filter( Boolean )
.join( '/' );
for ( const action of ALLOWED_RESOURCE_ACTIONS ) {
const permissionKey = getUserPermissionCacheKey(
action,
{ kind, name, id: key }
);

dispatch.receiveUserPermission(
permissionKey,
Expand Down Expand Up @@ -395,9 +382,7 @@ export const getEmbedPreview =
export const canUser =
( requestedAction, resource, id ) =>
async ( { dispatch, registry } ) => {
const retrievedActions = [ 'create', 'read', 'update', 'delete' ];

if ( ! retrievedActions.includes( requestedAction ) ) {
if ( ! ALLOWED_RESOURCE_ACTIONS.includes( requestedAction ) ) {
throw new Error( `'${ requestedAction }' is not a valid action.` );
}

Expand Down Expand Up @@ -429,7 +414,7 @@ export const canUser =
const { hasStartedResolution } = registry.select( STORE_NAME );

// Prevent resolving the same resource twice.
for ( const relatedAction of retrievedActions ) {
for ( const relatedAction of ALLOWED_RESOURCE_ACTIONS ) {
if ( relatedAction === requestedAction ) {
continue;
}
Expand All @@ -456,32 +441,10 @@ export const canUser =
return;
}

// Optional chaining operator is used here because the API requests don't
// return the expected result in the native version. Instead, API requests
// only return the result, without including response properties like the headers.
const allowHeader = response.headers?.get( 'allow' );
const allowedMethods = allowHeader?.allow || allowHeader || '';

const permissions = {};
const methods = {
create: 'POST',
read: 'GET',
update: 'PUT',
delete: 'DELETE',
};
for ( const [ actionName, methodName ] of Object.entries( methods ) ) {
permissions[ actionName ] = allowedMethods.includes( methodName );
}

const permissions = getUserPermissionsFromResponse( response );
registry.batch( () => {
for ( const action of retrievedActions ) {
const key = (
typeof resource === 'object'
? [ action, resource.kind, resource.name, resource.id ]
: [ action, resource, id ]
)
.filter( Boolean )
.join( '/' );
for ( const action of ALLOWED_RESOURCE_ACTIONS ) {
const key = getUserPermissionCacheKey( action, resource, id );

dispatch.receiveUserPermission( key, permissions[ action ] );

Expand Down
9 changes: 2 additions & 7 deletions packages/core-data/src/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
isRawAttribute,
setNestedValue,
isNumericID,
getUserPermissionCacheKey,
} from './utils';
import type * as ET from './entity-types';
import type { UndoManager } from '@wordpress/undo-manager';
Expand Down Expand Up @@ -1156,13 +1157,7 @@ export function canUser(
return false;
}

const key = (
isEntity
? [ action, resource.kind, resource.name, resource.id ]
: [ action, resource, id ]
)
.filter( Boolean )
.join( '/' );
const key = getUserPermissionCacheKey( action, resource, id );

return state.userPermissions[ key ];
}
Expand Down
5 changes: 5 additions & 0 deletions packages/core-data/src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@ export { default as isRawAttribute } from './is-raw-attribute';
export { default as setNestedValue } from './set-nested-value';
export { default as getNestedValue } from './get-nested-value';
export { default as isNumericID } from './is-numeric-id';
export {
getUserPermissionCacheKey,
getUserPermissionsFromResponse,
ALLOWED_RESOURCE_ACTIONS,
} from './user-permissions';
40 changes: 40 additions & 0 deletions packages/core-data/src/utils/user-permissions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
export const ALLOWED_RESOURCE_ACTIONS = [
'create',
'read',
'update',
'delete',
];

export function getUserPermissionsFromResponse( response ) {
const permissions = {};

// Optional chaining operator is used here because the API requests don't
// return the expected result in the native version. Instead, API requests
// only return the result, without including response properties like the headers.
const allowHeader = response.headers?.get( 'allow' );
const allowedMethods = allowHeader?.allow || allowHeader || '';

const methods = {
create: 'POST',
read: 'GET',
update: 'PUT',
delete: 'DELETE',
};
for ( const [ actionName, methodName ] of Object.entries( methods ) ) {
permissions[ actionName ] = allowedMethods.includes( methodName );
}

return permissions;
}

export function getUserPermissionCacheKey( action, resource, id ) {
const key = (
typeof resource === 'object'
? [ action, resource.kind, resource.name, resource.id ]
: [ action, resource, id ]
)
.filter( Boolean )
.join( '/' );

return key;
}

0 comments on commit 27b4b0d

Please sign in to comment.