Verified Commit 117e716d authored by Lauri Timmanee's avatar Lauri Timmanee
Browse files

Issue #3323788 by yash.rode, lauriii, acbramley, Berdir, AaronMcHale,...

Issue #3323788 by yash.rode, lauriii, acbramley, Berdir, AaronMcHale, smustgrave, phenaproxima: Revert and Delete actions should not be available for the current revision
parent 2364c755
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -76,6 +76,10 @@ public function access(EntityInterface $entity, $operation, AccountInterface $ac
    if ($entity instanceof RevisionableInterface) {
      /** @var \Drupal\Core\Entity\RevisionableInterface $entity */
      $cid .= ':' . $entity->getRevisionId();
      // It is not possible to delete or revert the default revision.
      if ($entity->isDefaultRevision() && ($operation === 'revert' || $operation === 'delete revision')) {
        return $return_as_object ? AccessResult::forbidden() : FALSE;
      }
    }

    if (($return = $this->getCache($cid, $operation, $langcode, $account)) !== NULL) {
+2 −4
Original line number Diff line number Diff line
@@ -6,9 +6,9 @@
use Drupal\block_content\Event\BlockContentGetDependencyEvent;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -57,7 +57,6 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
    assert($entity instanceof BlockContentInterface);
    $bundle = $entity->bundle();
    $forbidIfNotDefaultAndLatest = fn (): AccessResultInterface => AccessResult::forbiddenIf($entity->isDefaultRevision() && $entity->isLatestRevision());
    $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
@@ -90,12 +89,11 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
      'revert' => AccessResult::allowedIfHasPermissions($account, [
        'access block library',
        'revert any ' . $bundle . ' block content revisions',
      ])->orIf($forbidIfNotDefaultAndLatest())->orIf($forbidIfNotReusable()),
      ])->orIf($forbidIfNotReusable()),
      'delete revision' => AccessResult::allowedIfHasPermissions($account, [
        'access block library',
        'delete any ' . $bundle . ' block content revisions',
      ])
        ->orIf($forbidIfNotDefaultAndLatest())
        ->orIf($forbidIfNotReusable())
        ->orIf(AccessResult::allowedIfHasPermissions($account, [
          'administer block content',
+15 −4
Original line number Diff line number Diff line
@@ -50,20 +50,31 @@ public function testDeleteForm(): void {
    $this->drupalGet($entity->toUrl('revision-delete-form'));
    $this->assertSession()->statusCodeEquals(403);

    // Create a new latest revision.
    // Create a new non default revision.
    $entity
      ->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
      ->setRevisionTranslationAffected(TRUE)
      ->setNewRevision();
    $entity->isDefaultRevision(FALSE);
    $entity->save();
    $nonDefaultRevisionId = $entity->getRevisionId();

    // Reload the entity.
    // Reload the default entity.
    $revision = \Drupal::entityTypeManager()->getStorage('block_content')
      ->loadRevision($revisionId);
    // Cannot delete default revision.
    $this->drupalGet($revision->toUrl('revision-delete-form'));
    $this->assertSession()->pageTextContains('Are you sure you want to delete the revision from Sun, 01/11/2009 - 16:00?');
    $this->assertSession()->statusCodeEquals(403);
    $this->assertFalse($revision->access('delete revision', $this->adminUser, FALSE));

    // Reload the non default entity.
    $revision2 = \Drupal::entityTypeManager()->getStorage('block_content')
      ->loadRevision($nonDefaultRevisionId);
    $this->drupalGet($revision2->toUrl('revision-delete-form'));
    $this->assertSession()->pageTextContains('Are you sure you want to delete the revision from Sun, 01/11/2009 - 17:00?');
    $this->assertSession()->buttonExists('Delete');
    $this->assertSession()->linkExists('Cancel');
    $this->assertTrue($revision2->access('delete revision', $this->adminUser, FALSE));

    $countRevisions = static function (): int {
      return (int) \Drupal::entityTypeManager()->getStorage('block_content')
@@ -79,7 +90,7 @@ public function testDeleteForm(): void {
    $this->assertEquals($count - 1, $countRevisions());
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->addressEquals(sprintf('admin/content/block/%s/revisions', $entity->id()));
    $this->assertSession()->pageTextContains(sprintf('Revision from Sun, 01/11/2009 - 16:00 of basic %s has been deleted.', $entity->label()));
    $this->assertSession()->pageTextContains(sprintf('Revision from Sun, 01/11/2009 - 17:00 of basic %s has been deleted.', $entity->label()));
    $this->assertSession()->elementsCount('css', 'table tbody tr', 1);
  }

+15 −4
Original line number Diff line number Diff line
@@ -50,20 +50,31 @@ public function testRevertForm(): void {
    $this->drupalGet($entity->toUrl('revision-revert-form'));
    $this->assertSession()->statusCodeEquals(403);

    // Create a new latest revision.
    // Create a new non default revision.
    $entity
      ->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
      ->setRevisionTranslationAffected(TRUE)
      ->setNewRevision();
    $entity->isDefaultRevision(FALSE);
    $entity->save();
    $nonDefaultRevisionId = $entity->getRevisionId();

    // Reload the entity.
    // Reload the default entity.
    $revision = \Drupal::entityTypeManager()->getStorage('block_content')
      ->loadRevision($revisionId);
    // Cannot revert default revision.
    $this->drupalGet($revision->toUrl('revision-revert-form'));
    $this->assertSession()->pageTextContains('Are you sure you want to revert to the revision from Sun, 01/11/2009 - 16:00?');
    $this->assertSession()->statusCodeEquals(403);
    $this->assertFalse($revision->access('revert', $this->adminUser, FALSE));

    // Reload the non default entity.
    $revision2 = \Drupal::entityTypeManager()->getStorage('block_content')
      ->loadRevision($nonDefaultRevisionId);
    $this->drupalGet($revision2->toUrl('revision-revert-form'));
    $this->assertSession()->pageTextContains('Are you sure you want to revert to the revision from Sun, 01/11/2009 - 17:00?');
    $this->assertSession()->buttonExists('Revert');
    $this->assertSession()->linkExists('Cancel');
    $this->assertTrue($revision2->access('revert', $this->adminUser, FALSE));

    $countRevisions = static function (): int {
      return (int) \Drupal::entityTypeManager()->getStorage('block_content')
@@ -79,7 +90,7 @@ public function testRevertForm(): void {
    $this->assertEquals($count + 1, $countRevisions());
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->addressEquals(sprintf('admin/content/block/%s/revisions', $entity->id()));
    $this->assertSession()->pageTextContains(sprintf('basic %s has been reverted to the revision from Sun, 01/11/2009 - 16:00.', $entity->label()));
    $this->assertSession()->pageTextContains(sprintf('basic %s has been reverted to the revision from Sun, 01/11/2009 - 17:00.', $entity->label()));
    // Three rows, from the top: the newly reverted revision, the revision from
    // 5pm, and the revision from 4pm.
    $this->assertSession()->elementsCount('css', 'table tbody tr', 3);
+2 −4
Original line number Diff line number Diff line
@@ -79,12 +79,10 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
      return AccessResult::allowedIf(in_array($operation, $labels, TRUE));
    }
    elseif ($operation === 'revert') {
      // Disallow reverting to latest.
      return AccessResult::allowedIf(!$entity->isDefaultRevision() && !$entity->isLatestRevision() && in_array('revert', $labels, TRUE));
      return AccessResult::allowedIf(in_array('revert', $labels, TRUE));
    }
    elseif ($operation === 'delete revision') {
      // Disallow deleting latest and current revision.
      return AccessResult::allowedIf(!$entity->isLatestRevision() && in_array('delete revision', $labels, TRUE));
      return AccessResult::allowedIf(in_array('delete revision', $labels, TRUE));
    }

    // No opinion.
Loading