reverted: --- b/core/lib/Drupal/Core/Entity/EntityListBuilder.php +++ a/core/lib/Drupal/Core/Entity/EntityListBuilder.php @@ -3,7 +3,6 @@ namespace Drupal\Core\Entity; use Drupal\Core\Messenger\MessengerTrait; -use Drupal\block\BlockOperationsProviderInterface; use Drupal\Core\Routing\RedirectDestinationTrait; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -144,10 +143,6 @@ 'url' => $this->ensureDestination($entity->toUrl('delete-form')), ]; } - // Add operation links from entity. - if ($entity instanceof BlockOperationsProviderInterface && $entity->getOperationLinks()) { - $operations += $entity->getOperationLinks(); - } return $operations; } reverted: --- b/core/modules/block/src/BlockListBuilder.php +++ a/core/modules/block/src/BlockListBuilder.php @@ -365,14 +365,6 @@ if (isset($operations['delete'])) { $operations['delete']['title'] = $this->t('Remove'); } - - if ($entity instanceof BlockOperationsProviderInterface) { - $operations += $entity->getOperationLinks(); - } - - foreach ($operations as $operation) { - $operation['url']->setOption('query', ['destination' => 'admin/structure/block']); - } return $operations; } diff -u b/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php --- b/core/modules/block/src/Entity/Block.php +++ b/core/modules/block/src/Entity/Block.php @@ -10,7 +10,7 @@ use Drupal\Core\Config\Entity\ConfigEntityInterface; use Drupal\Core\Entity\EntityWithPluginCollectionInterface; use Drupal\Core\Entity\EntityStorageInterface; -use Drupal\block\BlockOperationsProviderInterface; +use Drupal\system\BlockOperationsProviderInterface; /** * Defines a Block configuration entity class. diff -u b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php --- b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php +++ b/core/modules/block_content/src/Plugin/Block/BlockContentBlock.php @@ -9,7 +9,7 @@ use Drupal\Core\Entity\EntityDisplayRepositoryInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Form\FormStateInterface; -use Drupal\block\BlockOperationsProviderInterface; +use Drupal\system\BlockOperationsProviderInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Routing\UrlGeneratorInterface; use Drupal\Core\Session\AccountInterface; @@ -219,14 +219,16 @@ */ public function getOperationLinks() { $entity = $this->getEntity(); - // Set url options to an empty array. - return [ - 'block-edit' => [ + $links = []; + if (\Drupal::currentUser()->hasPermission('edit any' . $entity->bundle() . ' block content')) { + // Set url options to an empty array. + $links['block-edit'] = [ 'title' => $this->t('Edit block'), 'url' => $entity->toUrl('edit-form')->setOptions([]), 'weight' => 50, - ], - ]; + ]; + } + return $links; } } diff -u b/core/modules/block_content/tests/src/Kernel/BlockContentTest.php b/core/modules/block_content/tests/src/Kernel/BlockContentTest.php --- b/core/modules/block_content/tests/src/Kernel/BlockContentTest.php +++ b/core/modules/block_content/tests/src/Kernel/BlockContentTest.php @@ -7,6 +7,7 @@ use Drupal\block_content\Entity\BlockContentType; use Drupal\Component\Plugin\PluginBase; use Drupal\KernelTests\KernelTestBase; +use Drupal\Tests\user\Traits\UserCreationTrait; /** * Tests the block content. @@ -15,6 +16,8 @@ */ class BlockContentTest extends KernelTestBase { + use UserCreationTrait; + /** * {@inheritdoc} */ @@ -60,6 +63,13 @@ 'url' => $block_content->toUrl('edit-form')->setOptions([]), 'weight' => 50, ]; + + // Test when user doesn't have "administer block" permission. + $this->assertEmpty($links); + + $this->setUpCurrentUser(['uid' => 1], ['edit any spiffy block content']); + $links = $block->getOperationLinks(); + // Test when user does have "administer block" permission. $this->assertEquals(['block-edit' => $block_link], $links); } diff -u b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php --- b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php +++ b/core/modules/system/src/Plugin/Block/SystemMenuBlock.php @@ -9,7 +9,7 @@ use Drupal\Core\Menu\MenuActiveTrailInterface; use Drupal\Core\Menu\MenuLinkTreeInterface; use Drupal\Core\Menu\MenuTreeParameters; -use Drupal\block\BlockOperationsProviderInterface; +use Drupal\system\BlockOperationsProviderInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Url; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -253,7 +253,7 @@ $menu = $this->getDerivativeId(); $links = []; - if ($this->moduleHandler->moduleExists('menu_ui')) { + if ($this->moduleHandler->moduleExists('menu_ui') && \Drupal::currentUser()->hasPermission('administer menu')) { $links['menu-edit'] = [ 'title' => $this->t('Edit menu'), 'url' => Url::fromRoute('entity.menu.edit_form', ['menu' => $menu]), diff -u b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php --- b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php +++ b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php @@ -9,6 +9,7 @@ use Drupal\Core\Render\Element; use Drupal\system\Tests\Routing\MockRouteProvider; use Drupal\Tests\Core\Menu\MenuLinkMock; +use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\user\Entity\User; use Drupal\Core\Routing\RouteObjectInterface; use Symfony\Component\HttpFoundation\Request; @@ -29,6 +30,8 @@ */ class SystemMenuBlockTest extends KernelTestBase { + use UserCreationTrait; + /** * Modules to enable. * @@ -208,7 +211,14 @@ 'url' => Url::fromRoute('entity.menu.edit_form', ['menu' => $this->menu->id()]), 'weight' => 50, ]; + + // Test when user does have "administer menu" permission. $this->assertEquals(['menu-edit' => $menu_link], $links); + + $this->setUpCurrentUser([]); + $links = $block->getOperationLinks(); + // Test when user doesn't have "administer menu" permission. + $this->assertEmpty($links); } /** diff -u b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php --- b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php +++ b/core/modules/views/src/Plugin/Block/ViewsBlockBase.php @@ -2,7 +2,7 @@ namespace Drupal\views\Plugin\Block; -use Drupal\block\BlockOperationsProviderInterface; +use Drupal\system\BlockOperationsProviderInterface; use Drupal\Core\Url; use Drupal\Core\Access\AccessResult; use Drupal\Core\Block\BlockBase; @@ -253,7 +253,7 @@ $delta = $this->getDerivativeId(); [$view, $display_id] = explode('-', $delta, 2); $links = []; - if ($this->moduleHandler->moduleExists('views_ui')) { + if ($this->moduleHandler->moduleExists('views_ui') && \Drupal::currentUser()->hasPermission('administer views')) { $links['view-edit'] = [ 'title' => $this->t('Edit view'), 'url' => Url::fromRoute('entity.view.edit_display_form', [ diff -u b/core/modules/views/tests/src/Kernel/Plugin/ViewsBlockTest.php b/core/modules/views/tests/src/Kernel/Plugin/ViewsBlockTest.php --- b/core/modules/views/tests/src/Kernel/Plugin/ViewsBlockTest.php +++ b/core/modules/views/tests/src/Kernel/Plugin/ViewsBlockTest.php @@ -4,6 +4,7 @@ use Drupal\block\Entity\Block; use Drupal\Core\Url; +use Drupal\Tests\user\Traits\UserCreationTrait; use Drupal\views\Plugin\Block\ViewsBlock; use Drupal\views\Tests\ViewTestData; use Drupal\Tests\views\Kernel\ViewsKernelTestBase; @@ -16,6 +17,8 @@ */ class ViewsBlockTest extends ViewsKernelTestBase { + use UserCreationTrait; + /** * Modules to enable. * @@ -164,6 +167,13 @@ ]), 'weight' => 50, ]; + + // Test when user doesn't have "administer views" permission. + $this->assertEmpty($links); + + $this->setUpCurrentUser(['uid' => 1], ['administer views']); + $links = $block->getOperationLinks(); + // Test when user does have "administer views" permission. $this->assertEquals(['view-edit' => $view_link], $links); } only in patch2: unchanged: --- a/core/modules/block/block.module +++ b/core/modules/block/block.module @@ -5,7 +5,9 @@ * Controls the visual building blocks a page is constructed with. */ +use Drupal\block\BlockOperationsProviderInterface; use Drupal\Component\Utility\Html; +use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Installer\InstallerKernel; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Link; @@ -315,3 +317,19 @@ function block_configurable_language_delete(ConfigurableLanguageInterface $langu } } } + +/** + * Implements hook_entity_operation(). + */ +function block_entity_operation(EntityInterface $entity) { + $operations = []; + if ($entity instanceof BlockOperationsProviderInterface) { + $operations += $entity->getOperationLinks(); + } + + foreach ($operations as $operation) { + $operation['url']->setOption('query', ['destination' => 'admin/structure/block']); + } + + return $operations; +} only in patch2: unchanged: --- /dev/null +++ b/core/modules/system/src/BlockOperationsProviderInterface.php @@ -0,0 +1,21 @@ +