diff --git a/packages/block-directory/src/store/actions.js b/packages/block-directory/src/store/actions.js index beea3d05ab01e..f14fb51b17745 100644 --- a/packages/block-directory/src/store/actions.js +++ b/packages/block-directory/src/store/actions.js @@ -66,16 +66,13 @@ export function* installBlockType( block ) { throw new Error( __( 'Block has no assets.' ) ); } yield setIsInstalling( block.id, true ); - const response = yield apiFetch( { + yield apiFetch( { path: '__experimental/block-directory/install', data: { slug: block.id, }, method: 'POST', } ); - if ( response.success !== true ) { - throw new Error( __( 'Unable to install this block.' ) ); - } yield addInstalledBlockType( block ); yield loadAssets( assets ); diff --git a/packages/block-directory/src/store/resolvers.js b/packages/block-directory/src/store/resolvers.js index d2ac2f167ce4b..5ca5f025e791a 100644 --- a/packages/block-directory/src/store/resolvers.js +++ b/packages/block-directory/src/store/resolvers.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { camelCase, mapKeys } from 'lodash'; +import { camelCase, get, hasIn, includes, mapKeys } from 'lodash'; /** * WordPress dependencies @@ -36,21 +36,34 @@ export default { yield receiveDownloadableBlocks( blocks, filterValue ); } catch ( error ) { - if ( error.code === 'rest_user_cannot_view' ) { + if ( error.code === 'rest_block_directory_cannot_view' ) { yield setInstallBlocksPermission( false ); } } }, *hasInstallBlocksPermission() { try { - yield apiFetch( { - path: `__experimental/block-directory/search?term=`, + const response = yield apiFetch( { + method: 'OPTIONS', + path: `__experimental/block-directory/search`, + parse: false, } ); - yield setInstallBlocksPermission( true ); - } catch ( error ) { - if ( error.code === 'rest_user_cannot_view' ) { - yield setInstallBlocksPermission( false ); + + let allowHeader; + if ( hasIn( response, [ 'headers', 'get' ] ) ) { + // If the request is fetched using the fetch api, the header can be + // retrieved using the 'get' method. + allowHeader = response.headers.get( 'allow' ); + } else { + // If the request was preloaded server-side and is returned by the + // preloading middleware, the header will be a simple property. + allowHeader = get( response, [ 'headers', 'Allow' ], '' ); } + + const isAllowed = includes( allowHeader, 'GET' ); + yield setInstallBlocksPermission( isAllowed ); + } catch ( error ) { + yield setInstallBlocksPermission( false ); } }, }; diff --git a/packages/block-directory/src/store/test/actions.js b/packages/block-directory/src/store/test/actions.js index eaac933fb0a65..4ecb769260b44 100644 --- a/packages/block-directory/src/store/test/actions.js +++ b/packages/block-directory/src/store/test/actions.js @@ -109,7 +109,7 @@ describe( 'actions', () => { message: 'Plugin not found.', data: null, }; - expect( generator.next( apiError ).value ).toMatchObject( { + expect( generator.throw( apiError ).value ).toMatchObject( { type: 'SET_ERROR_NOTICE', blockId: item.id, } ); diff --git a/packages/e2e-tests/specs/experiments/block-directory-add.test.js b/packages/e2e-tests/specs/experiments/block-directory-add.test.js index 7d21159c4b256..c3ad73ea7ea65 100644 --- a/packages/e2e-tests/specs/experiments/block-directory-add.test.js +++ b/packages/e2e-tests/specs/experiments/block-directory-add.test.js @@ -47,6 +47,24 @@ const MOCK_BLOCK1 = { humanized_updated: '5 months ago', }; +const MOCK_INSTALLED_BLOCK_PLUGIN_DETAILS = { + plugin: 'block-directory-test-block', + status: 'active', + name: 'Block Directory', + plugin_uri: '', + author: 'No Author', + author_uri: '', + description: { + raw: 'This plugin is useful for the block.', + rendered: 'This plugin is useful for the block.', + }, + version: '1.0', + network_only: false, + requires_wp: '', + requires_php: '', + text_domain: 'block-directory-test-block', +}; + const MOCK_BLOCK2 = { ...MOCK_BLOCK1, name: 'block-directory-test-block/secondary-block', @@ -73,7 +91,42 @@ const block = `( function() { } ); } )();`; +const MOCK_OPTIONS = { + namespace: '__experimental', + methods: [ 'GET' ], + endpoints: [ + { + methods: [ 'GET' ], + args: {}, + }, + ], + schema: { + $schema: 'http://json-schema.org/draft-04/schema#', + title: 'block-directory-item', + type: 'object', + properties: {}, + }, +}; + +const MOCK_OPTIONS_RESPONSE = { + match: ( request ) => + matchUrl( request.url(), SEARCH_URLS ) && + request.method() === 'OPTIONS', + onRequestMatch: async ( request ) => { + const response = { + content: 'application/json', + body: JSON.stringify( MOCK_OPTIONS ), + headers: { + Allow: 'GET', + }, + }; + + return request.respond( response ); + }, +}; + const MOCK_EMPTY_RESPONSES = [ + MOCK_OPTIONS_RESPONSE, { match: ( request ) => matchUrl( request.url(), SEARCH_URLS ), onRequestMatch: createJSONResponse( [] ), @@ -81,6 +134,7 @@ const MOCK_EMPTY_RESPONSES = [ ]; const MOCK_BLOCKS_RESPONSES = [ + MOCK_OPTIONS_RESPONSE, { // Mock response for search with the block match: ( request ) => matchUrl( request.url(), SEARCH_URLS ), @@ -89,7 +143,9 @@ const MOCK_BLOCKS_RESPONSES = [ { // Mock response for install match: ( request ) => matchUrl( request.url(), INSTALL_URLS ), - onRequestMatch: createJSONResponse( { success: true } ), + onRequestMatch: createJSONResponse( + MOCK_INSTALLED_BLOCK_PLUGIN_DETAILS + ), }, { // Mock the response for the js asset once it gets injected