From 07ad0f83d03fd92b8f6d9a28ada413a16f5cc33e Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Mon, 17 Jun 2024 11:57:32 +0100 Subject: [PATCH] Fix: Check create capability on duplicate post action. --- .../src/components/post-actions/actions.js | 270 ++++++++++-------- 1 file changed, 151 insertions(+), 119 deletions(-) diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js index 199051fca93846..05aa94ee9963e6 100644 --- a/packages/editor/src/components/post-actions/actions.js +++ b/packages/editor/src/components/post-actions/actions.js @@ -722,132 +722,162 @@ const renamePostAction = { }, }; -const duplicatePostAction = { - id: 'duplicate-post', - label: _x( 'Duplicate', 'action label' ), - isEligible( { status } ) { - return status !== 'trash'; - }, - RenderModal: ( { items, closeModal, onActionPerformed } ) => { - const [ item ] = items; - const [ isCreatingPage, setIsCreatingPage ] = useState( false ); - const [ title, setTitle ] = useState( - sprintf( - /* translators: %s: Existing item title */ - __( '%s (Copy)' ), - getItemTitle( item ) - ) - ); +const useDuplicatePostAction = ( postType ) => { + const { userCanCreatePost } = useSelect( + ( select ) => { + const { getPostType, canUser } = select( coreStore ); + const resource = getPostType( postType )?.rest_base || ''; + return { + userCanCreatePost: canUser( 'create', resource ), + }; + }, + [ postType ] + ); + return useMemo( + () => + userCanCreatePost && { + id: 'duplicate-post', + label: _x( 'Duplicate', 'action label' ), + isEligible( { status } ) { + return status !== 'trash'; + }, + RenderModal: ( { items, closeModal, onActionPerformed } ) => { + const [ item ] = items; + const [ isCreatingPage, setIsCreatingPage ] = + useState( false ); + const [ title, setTitle ] = useState( + sprintf( + /* translators: %s: Existing item title */ + __( '%s (Copy)' ), + getItemTitle( item ) + ) + ); - const { saveEntityRecord } = useDispatch( coreStore ); - const { createSuccessNotice, createErrorNotice } = - useDispatch( noticesStore ); + const { saveEntityRecord } = useDispatch( coreStore ); + const { createSuccessNotice, createErrorNotice } = + useDispatch( noticesStore ); - async function createPage( event ) { - event.preventDefault(); + async function createPage( event ) { + event.preventDefault(); - if ( isCreatingPage ) { - return; - } + if ( isCreatingPage ) { + return; + } - const newItemOject = { - status: 'draft', - title, - slug: title || __( 'No title' ), - comment_status: item.comment_status, - content: - typeof item.content === 'string' - ? item.content - : item.content.raw, - excerpt: item.excerpt.raw, - meta: item.meta, - parent: item.parent, - password: item.password, - template: item.template, - format: item.format, - featured_media: item.featured_media, - menu_order: item.menu_order, - ping_status: item.ping_status, - }; - const assignablePropertiesPrefix = 'wp:action-assign-'; - // Get all the properties that the current user is able to assign normally author, categories, tags, - // and custom taxonomies. - const assignableProperties = Object.keys( item?._links || {} ) - .filter( ( property ) => - property.startsWith( assignablePropertiesPrefix ) - ) - .map( ( property ) => - property.slice( assignablePropertiesPrefix.length ) - ); - assignableProperties.forEach( ( property ) => { - if ( item[ property ] ) { - newItemOject[ property ] = item[ property ]; - } - } ); - setIsCreatingPage( true ); - try { - const newItem = await saveEntityRecord( - 'postType', - item.type, - newItemOject, - { throwOnError: true } - ); + const newItemOject = { + status: 'draft', + title, + slug: title || __( 'No title' ), + comment_status: item.comment_status, + content: + typeof item.content === 'string' + ? item.content + : item.content.raw, + excerpt: item.excerpt.raw, + meta: item.meta, + parent: item.parent, + password: item.password, + template: item.template, + format: item.format, + featured_media: item.featured_media, + menu_order: item.menu_order, + ping_status: item.ping_status, + }; + const assignablePropertiesPrefix = 'wp:action-assign-'; + // Get all the properties that the current user is able to assign normally author, categories, tags, + // and custom taxonomies. + const assignableProperties = Object.keys( + item?._links || {} + ) + .filter( ( property ) => + property.startsWith( + assignablePropertiesPrefix + ) + ) + .map( ( property ) => + property.slice( + assignablePropertiesPrefix.length + ) + ); + assignableProperties.forEach( ( property ) => { + if ( item[ property ] ) { + newItemOject[ property ] = item[ property ]; + } + } ); + setIsCreatingPage( true ); + try { + const newItem = await saveEntityRecord( + 'postType', + item.type, + newItemOject, + { throwOnError: true } + ); - createSuccessNotice( - sprintf( - // translators: %s: Title of the created template e.g: "Category". - __( '"%s" successfully created.' ), - decodeEntities( newItem.title?.rendered || title ) - ), - { - id: 'duplicate-post-action', - type: 'snackbar', - } - ); + createSuccessNotice( + sprintf( + // translators: %s: Title of the created template e.g: "Category". + __( '"%s" successfully created.' ), + decodeEntities( + newItem.title?.rendered || title + ) + ), + { + id: 'duplicate-post-action', + type: 'snackbar', + } + ); - if ( onActionPerformed ) { - onActionPerformed( [ newItem ] ); - } - } catch ( error ) { - const errorMessage = - error.message && error.code !== 'unknown_error' - ? error.message - : __( 'An error occurred while duplicating the page.' ); + if ( onActionPerformed ) { + onActionPerformed( [ newItem ] ); + } + } catch ( error ) { + const errorMessage = + error.message && error.code !== 'unknown_error' + ? error.message + : __( + 'An error occurred while duplicating the page.' + ); - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } finally { - setIsCreatingPage( false ); - closeModal(); - } - } - return ( -
- - - - - - - -
- ); - }, + createErrorNotice( errorMessage, { + type: 'snackbar', + } ); + } finally { + setIsCreatingPage( false ); + closeModal(); + } + } + return ( +
+ + + + + + + +
+ ); + }, + }, + [ userCanCreatePost ] + ); }; const isTemplatePartRevertable = ( item ) => { @@ -1058,6 +1088,7 @@ export function usePostActions( postType, onActionPerformed ) { const permanentlyDeletePostAction = usePermanentlyDeletePostAction(); const restorePostAction = useRestorePostAction(); + const duplicatePostAction = useDuplicatePostAction( postType ); const isTemplateOrTemplatePart = [ TEMPLATE_POST_TYPE, TEMPLATE_PART_POST_TYPE, @@ -1140,6 +1171,7 @@ export function usePostActions( postType, onActionPerformed ) { postTypeObject?.viewable, permanentlyDeletePostAction, restorePostAction, + duplicatePostAction, onActionPerformed, isLoaded, supportsRevisions,