From 9f4e89ed1b69ceb54d253b6510e9a8acc43a43e0 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Mon, 30 Oct 2023 07:46:42 +1000
Subject: [PATCH] Issue #3366719 by smustgrave, acbramley, yash.rode: Allow
 reverting block content with "administer block content" permission

---
 .../src/BlockContentAccessControlHandler.php  | 73 ++++++++-----------
 .../Kernel/BlockContentAccessHandlerTest.php  | 18 ++---
 2 files changed, 41 insertions(+), 50 deletions(-)

diff --git a/core/modules/block_content/src/BlockContentAccessControlHandler.php b/core/modules/block_content/src/BlockContentAccessControlHandler.php
index 54052feeff8e..8821080a9ce8 100644
--- a/core/modules/block_content/src/BlockContentAccessControlHandler.php
+++ b/core/modules/block_content/src/BlockContentAccessControlHandler.php
@@ -58,49 +58,40 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
     assert($entity instanceof BlockContentInterface);
     $bundle = $entity->bundle();
     $forbidIfNotReusable = fn (): AccessResultInterface => AccessResult::forbiddenIf($entity->isReusable() === FALSE, sprintf('Block content must be reusable to use `%s` operation', $operation));
-    $access = match ($operation) {
-      // Allow view and update access to user with the 'edit any (type) block
-      // content' permission or the 'administer blocks' permission.
-      'view' => AccessResult::allowedIf($entity->isPublished())
-        ->orIf(AccessResult::allowedIfHasPermissions($account, [
+    $access = AccessResult::allowedIfHasPermissions($account, ['administer block content']);
+    if (!$access->isAllowed()) {
+      $access = match ($operation) {
+        // Allow view and update access to user with the 'edit any (type) block
+        // content' permission or the 'administer block content' permission.
+        'view' => AccessResult::allowedIf($entity->isPublished())
+          ->orIf(AccessResult::allowedIfHasPermissions($account, [
+            'access block library',
+          ])),
+        'update' => AccessResult::allowedIfHasPermissions($account, [
           'access block library',
-        ]))->orIf(AccessResult::allowedIfHasPermissions($account, [
-          'administer block content',
-        ])),
-      'update' => AccessResult::allowedIfHasPermissions($account, [
-        'access block library',
-        'edit any ' . $bundle . ' block content',
-      ])->orIf(AccessResult::allowedIfHasPermissions($account, [
-        'administer block content',
-      ])),
-      'delete' => AccessResult::allowedIfHasPermissions($account, [
-        'access block library',
-        'delete any ' . $bundle . ' block content',
-      ])->orIf(AccessResult::allowedIfHasPermissions($account, [
-        'administer block content',
-      ])),
-      // Revisions.
-      'view all revisions' => AccessResult::allowedIfHasPermissions($account, [
-        'access block library',
-        'view any ' . $bundle . ' block content history',
-      ])->orIf(AccessResult::allowedIfHasPermissions($account, [
-        'administer block content',
-      ])),
-      'revert' => AccessResult::allowedIfHasPermissions($account, [
-        'access block library',
-        'revert any ' . $bundle . ' block content revisions',
-      ])->orIf($forbidIfNotReusable()),
-      'delete revision' => AccessResult::allowedIfHasPermissions($account, [
-        'access block library',
-        'delete any ' . $bundle . ' block content revisions',
-      ])
-        ->orIf($forbidIfNotReusable())
-        ->orIf(AccessResult::allowedIfHasPermissions($account, [
-          'administer block content',
-        ])),
+          'edit any ' . $bundle . ' block content',
+        ]),
+        'delete' => AccessResult::allowedIfHasPermissions($account, [
+          'access block library',
+          'delete any ' . $bundle . ' block content',
+        ]),
+        // Revisions.
+        'view all revisions' => AccessResult::allowedIfHasPermissions($account, [
+          'access block library',
+          'view any ' . $bundle . ' block content history',
+        ]),
+        'revert' => AccessResult::allowedIfHasPermissions($account, [
+          'access block library',
+          'revert any ' . $bundle . ' block content revisions',
+        ])->orIf($forbidIfNotReusable()),
+        'delete revision' => AccessResult::allowedIfHasPermissions($account, [
+          'access block library',
+          'delete any ' . $bundle . ' block content revisions',
+        ])->orIf($forbidIfNotReusable()),
 
-      default => parent::checkAccess($entity, $operation, $account),
-    };
+        default => parent::checkAccess($entity, $operation, $account),
+      };
+    }
 
     // Add the entity as a cacheable dependency because access will at least be
     // determined by whether the block is reusable.
diff --git a/core/modules/block_content/tests/src/Kernel/BlockContentAccessHandlerTest.php b/core/modules/block_content/tests/src/Kernel/BlockContentAccessHandlerTest.php
index b4929ce54787..cae7c2215424 100644
--- a/core/modules/block_content/tests/src/Kernel/BlockContentAccessHandlerTest.php
+++ b/core/modules/block_content/tests/src/Kernel/BlockContentAccessHandlerTest.php
@@ -447,7 +447,7 @@ public function providerTestAccess(): array {
       NULL,
       AccessResultNeutral::class,
     ];
-    $cases['view all revisions:administer blocks'] = [
+    $cases['view all revisions:administer block content'] = [
       'view all revisions',
       TRUE,
       TRUE,
@@ -485,16 +485,16 @@ public function providerTestAccess(): array {
       NULL,
       AccessResultNeutral::class,
     ];
-    $cases['revert:administer blocks:latest'] = [
+    $cases['revert:administer block content:latest'] = [
       'revert',
       TRUE,
       TRUE,
-      ['access block library'],
+      ['administer block content'],
       TRUE,
       NULL,
       AccessResultForbidden::class,
     ];
-    $cases['revert:administer blocks:historical'] = [
+    $cases['revert:administer block content:historical'] = [
       'revert',
       TRUE,
       TRUE,
@@ -507,7 +507,7 @@ public function providerTestAccess(): array {
       'revert',
       TRUE,
       TRUE,
-      ['administer blocks'],
+      ['administer block content'],
       TRUE,
       NULL,
       AccessResultForbidden::class,
@@ -551,16 +551,16 @@ public function providerTestAccess(): array {
       NULL,
       AccessResultNeutral::class,
     ];
-    $cases['delete revision:administer blocks:latest'] = [
+    $cases['delete revision:administer block content:latest'] = [
       'delete revision',
       TRUE,
       TRUE,
-      ['administer blocks'],
+      ['administer block content'],
       TRUE,
       NULL,
       AccessResultForbidden::class,
     ];
-    $cases['delete revision:administer blocks:historical'] = [
+    $cases['delete revision:administer block content:historical'] = [
       'delete revision',
       TRUE,
       TRUE,
@@ -573,7 +573,7 @@ public function providerTestAccess(): array {
       'delete revision',
       TRUE,
       TRUE,
-      ['administer blocks'],
+      ['administer block content'],
       TRUE,
       NULL,
       AccessResultForbidden::class,
-- 
GitLab