Issue #1984588 by dpi, larowlan, AaronMcHale, smustgrave, acbramley: Add Block Content revision UI
parent
ae061b3974
commit
86caf6f378
|
@ -15,6 +15,12 @@ delete-multiple-form:
|
|||
revision:
|
||||
uri: https://drupal.org/link-relations/revision
|
||||
description: A particular version of this resource.
|
||||
revision-revert-form:
|
||||
uri: https://drupal.org/link-relations/revision-revert-form
|
||||
description: A form where a particular version of this resource can be reverted.
|
||||
revision-delete-form:
|
||||
uri: https://drupal.org/link-relations/revision-delete-form
|
||||
description: A form where a particular version of this resource can be deleted.
|
||||
create:
|
||||
uri: https://drupal.org/link-relations/create
|
||||
description: A REST resource URL where a resource of this type can be created.
|
||||
|
|
|
@ -11,6 +11,7 @@ use Drupal\Core\Entity\RevisionableInterface;
|
|||
use Drupal\Core\Entity\RevisionableStorageInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Routing\RouteMatchInterface;
|
||||
use Drupal\Core\Entity\RevisionLogInterface;
|
||||
|
@ -155,10 +156,10 @@ class VersionHistoryController extends ControllerBase {
|
|||
$linkText = $revision->access('view label') ? $revision->label() : $this->t('- Restricted access -');
|
||||
}
|
||||
|
||||
$revisionViewLink = $revision->toLink($linkText, 'revision');
|
||||
$context['revision'] = $revisionViewLink->getUrl()->access()
|
||||
? $revisionViewLink->toString()
|
||||
: (string) $revisionViewLink->getText();
|
||||
$url = $revision->hasLinkTemplate('revision') ? $revision->toUrl('revision') : NULL;
|
||||
$context['revision'] = $url && $url->access()
|
||||
? Link::fromTextAndUrl($linkText, $url)->toString()
|
||||
: (string) $linkText;
|
||||
$context['message'] = $revision instanceof RevisionLogInterface ? [
|
||||
'#markup' => $revision->getRevisionLogMessage(),
|
||||
'#allowed_tags' => Xss::getHtmlTagList(),
|
||||
|
|
|
@ -5,9 +5,33 @@
|
|||
* Install, update and uninstall functions for the block_content module.
|
||||
*/
|
||||
|
||||
use Drupal\Core\Entity\Form\RevisionDeleteForm;
|
||||
use Drupal\Core\Entity\Form\RevisionRevertForm;
|
||||
use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
|
||||
/**
|
||||
* Implements hook_update_last_removed().
|
||||
*/
|
||||
function block_content_update_last_removed() {
|
||||
return 8600;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update entity definition to handle revision routes.
|
||||
*/
|
||||
function block_content_update_10100(&$sandbox = NULL): TranslatableMarkup {
|
||||
$entityDefinitionUpdateManager = \Drupal::entityDefinitionUpdateManager();
|
||||
$definition = $entityDefinitionUpdateManager->getEntityType('block_content');
|
||||
$routeProviders = $definition->get('route_provider');
|
||||
$routeProviders['revision'] = RevisionHtmlRouteProvider::class;
|
||||
$definition
|
||||
->setFormClass('revision-delete', RevisionDeleteForm::class)
|
||||
->setFormClass('revision-revert', RevisionRevertForm::class)
|
||||
->set('route_provider', $routeProviders)
|
||||
->setLinkTemplate('revision-delete-form', '/block/{block_content}/revision/{block_content_revision}/delete')
|
||||
->setLinkTemplate('revision-revert-form', '/block/{block_content}/revision/{block_content_revision}/revert')
|
||||
->setLinkTemplate('version-history', '/block/{block_content}/revisions');
|
||||
$entityDefinitionUpdateManager->updateEntityType($definition);
|
||||
return \t('Added revision routes to Custom block entity type.');
|
||||
}
|
||||
|
|
|
@ -54,21 +54,34 @@ class BlockContentAccessControlHandler extends EntityAccessControlHandler implem
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
// Allow view and update access to user with the 'edit any (type) block
|
||||
// content' permission or the 'administer blocks' permission.
|
||||
$edit_any_permission = 'edit any ' . $entity->bundle() . ' block content';
|
||||
if ($operation === 'view') {
|
||||
$access = AccessResult::allowedIf($entity->isPublished())
|
||||
assert($entity instanceof BlockContentInterface);
|
||||
$bundle = $entity->bundle();
|
||||
$forbidIfNotDefaultAndLatest = fn () => AccessResult::forbiddenIf($entity->isDefaultRevision() && $entity->isLatestRevision());
|
||||
$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::allowedIfHasPermission($account, 'administer blocks'))
|
||||
->orIf(AccessResult::allowedIfHasPermission($account, $edit_any_permission));
|
||||
}
|
||||
elseif ($operation === 'update') {
|
||||
$access = AccessResult::allowedIfHasPermission($account, 'administer blocks')
|
||||
->orIf(AccessResult::allowedIfHasPermission($account, $edit_any_permission));
|
||||
}
|
||||
else {
|
||||
$access = parent::checkAccess($entity, $operation, $account);
|
||||
}
|
||||
->orIf(AccessResult::allowedIfHasPermission($account, 'edit any ' . $bundle . ' block content')),
|
||||
'update' => AccessResult::allowedIfHasPermission($account, 'administer blocks')
|
||||
->orIf(AccessResult::allowedIfHasPermission($account, 'edit any ' . $bundle . ' block content')),
|
||||
|
||||
// Revisions.
|
||||
'view all revisions' => AccessResult::allowedIfHasPermissions($account, [
|
||||
'administer blocks',
|
||||
'view any ' . $bundle . ' block content history',
|
||||
], 'OR'),
|
||||
'revert' => AccessResult::allowedIfHasPermissions($account, [
|
||||
'administer blocks',
|
||||
'revert any ' . $bundle . ' block content revisions',
|
||||
], 'OR')->orIf($forbidIfNotDefaultAndLatest()),
|
||||
'delete revision' => AccessResult::allowedIfHasPermissions($account, [
|
||||
'administer blocks',
|
||||
'delete any ' . $bundle . ' block content revisions',
|
||||
], 'OR')->orIf($forbidIfNotDefaultAndLatest()),
|
||||
|
||||
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.
|
||||
|
|
|
@ -3,17 +3,40 @@
|
|||
namespace Drupal\block_content;
|
||||
|
||||
use Drupal\block_content\Entity\BlockContentType;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Entity\BundlePermissionHandlerTrait;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Provide dynamic permissions for blocks of different types.
|
||||
*/
|
||||
class BlockContentPermissions {
|
||||
class BlockContentPermissions implements ContainerInjectionInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
use BundlePermissionHandlerTrait;
|
||||
|
||||
/**
|
||||
* Constructs a BlockContentPermissions instance.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
|
||||
* Entity type manager.
|
||||
*/
|
||||
public function __construct(
|
||||
protected EntityTypeManagerInterface $entityTypeManager,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build permissions for each block type.
|
||||
*
|
||||
|
@ -21,7 +44,7 @@ class BlockContentPermissions {
|
|||
* The block type permissions.
|
||||
*/
|
||||
public function blockTypePermissions() {
|
||||
return $this->generatePermissions(BlockContentType::loadMultiple(), [$this, 'buildPermissions']);
|
||||
return $this->generatePermissions($this->entityTypeManager->getStorage('block_content_type')->loadMultiple(), [$this, 'buildPermissions']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +63,15 @@ class BlockContentPermissions {
|
|||
"edit any $type_id block content" => [
|
||||
'title' => $this->t('%type_name: Edit any block content', $type_params),
|
||||
],
|
||||
"view any $type_id block content history" => [
|
||||
'title' => $this->t('%type_name: View any block content history pages', $type_params),
|
||||
],
|
||||
"revert any $type_id block content revisions" => [
|
||||
'title' => $this->t('%type_name: Revert any block content revisions', $type_params),
|
||||
],
|
||||
"delete any $type_id block content revisions" => [
|
||||
'title' => $this->t('%type_name: Delete any block content revisions', $type_params),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,12 @@ use Drupal\user\UserInterface;
|
|||
* "add" = "Drupal\block_content\BlockContentForm",
|
||||
* "edit" = "Drupal\block_content\BlockContentForm",
|
||||
* "delete" = "Drupal\block_content\Form\BlockContentDeleteForm",
|
||||
* "default" = "Drupal\block_content\BlockContentForm"
|
||||
* "default" = "Drupal\block_content\BlockContentForm",
|
||||
* "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
|
||||
* "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
|
||||
* },
|
||||
* "route_provider" = {
|
||||
* "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
|
||||
* },
|
||||
* "translation" = "Drupal\block_content\BlockContentTranslationHandler"
|
||||
* },
|
||||
|
@ -50,6 +55,9 @@ use Drupal\user\UserInterface;
|
|||
* "edit-form" = "/block/{block_content}",
|
||||
* "collection" = "/admin/structure/block/block-content",
|
||||
* "create" = "/block",
|
||||
* "revision-delete-form" = "/block/{block_content}/revision/{block_content_revision}/delete",
|
||||
* "revision-revert-form" = "/block/{block_content}/revision/{block_content_revision}/revert",
|
||||
* "version-history" = "/block/{block_content}/revisions",
|
||||
* },
|
||||
* translatable = TRUE,
|
||||
* entity_keys = {
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Drupal\Tests\block_content\Functional;
|
||||
|
||||
/**
|
||||
* Block content revision delete form test.
|
||||
*
|
||||
* @group block_content
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Form\RevisionDeleteForm
|
||||
*/
|
||||
class BlockContentRevisionDeleteTest extends BlockContentTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view any basic block content history',
|
||||
'delete any basic block content revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision delete.
|
||||
*/
|
||||
public function testDeleteForm(): void {
|
||||
$entity = $this->createBlockContent(save: FALSE)
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 4pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE);
|
||||
$entity->setNewRevision();
|
||||
$entity->save();
|
||||
$revisionId = $entity->getRevisionId();
|
||||
|
||||
// Cannot delete latest revision.
|
||||
$this->drupalGet($entity->toUrl('revision-delete-form'));
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a new latest revision.
|
||||
$entity
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE)
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
// Reload the entity.
|
||||
$revision = \Drupal::entityTypeManager()->getStorage('block_content')
|
||||
->loadRevision($revisionId);
|
||||
$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()->buttonExists('Delete');
|
||||
$this->assertSession()->linkExists('Cancel');
|
||||
|
||||
$countRevisions = static function (): int {
|
||||
return (int) \Drupal::entityTypeManager()->getStorage('block_content')
|
||||
->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->allRevisions()
|
||||
->count()
|
||||
->execute();
|
||||
};
|
||||
|
||||
$count = $countRevisions();
|
||||
$this->submitForm([], 'Delete');
|
||||
$this->assertEquals($count - 1, $countRevisions());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->addressEquals(sprintf('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()->elementsCount('css', 'table tbody tr', 1);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Drupal\Tests\block_content\Functional;
|
||||
|
||||
/**
|
||||
* Block content revision form test.
|
||||
*
|
||||
* @group block_content
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Form\RevisionRevertForm
|
||||
*/
|
||||
class BlockContentRevisionRevertTest extends BlockContentTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view any basic block content history',
|
||||
'revert any basic block content revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->drupalPlaceBlock('page_title_block');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests revision revert.
|
||||
*/
|
||||
public function testRevertForm(): void {
|
||||
$entity = $this->createBlockContent(save: FALSE)
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 4pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE);
|
||||
$entity->setNewRevision();
|
||||
$entity->save();
|
||||
$revisionId = $entity->getRevisionId();
|
||||
|
||||
// Cannot revert latest revision.
|
||||
$this->drupalGet($entity->toUrl('revision-revert-form'));
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Create a new latest revision.
|
||||
$entity
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('11 January 2009 5pm'))->getTimestamp())
|
||||
->setRevisionTranslationAffected(TRUE)
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
// Reload the entity.
|
||||
$revision = \Drupal::entityTypeManager()->getStorage('block_content')
|
||||
->loadRevision($revisionId);
|
||||
$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()->buttonExists('Revert');
|
||||
$this->assertSession()->linkExists('Cancel');
|
||||
|
||||
$countRevisions = static function (): int {
|
||||
return (int) \Drupal::entityTypeManager()->getStorage('block_content')
|
||||
->getQuery()
|
||||
->accessCheck(FALSE)
|
||||
->allRevisions()
|
||||
->count()
|
||||
->execute();
|
||||
};
|
||||
|
||||
$count = $countRevisions();
|
||||
$this->submitForm([], 'Revert');
|
||||
$this->assertEquals($count + 1, $countRevisions());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->addressEquals(sprintf('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()));
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Drupal\Tests\block_content\Functional;
|
||||
|
||||
/**
|
||||
* Block content version history test.
|
||||
*
|
||||
* @group block_content
|
||||
* @coversDefaultClass \Drupal\Core\Entity\Controller\VersionHistoryController
|
||||
*/
|
||||
class BlockContentRevisionVersionHistoryTest extends BlockContentTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $defaultTheme = 'stark';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $permissions = [
|
||||
'view any basic block content history',
|
||||
'revert any basic block content revisions',
|
||||
'delete any basic block content revisions',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests version history page.
|
||||
*/
|
||||
public function testVersionHistory(): void {
|
||||
$entity = $this->createBlockContent(save: FALSE);
|
||||
|
||||
$entity
|
||||
->setInfo('first revision')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('1st June 2020 7am'))->getTimestamp())
|
||||
->setRevisionLogMessage('first revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'first author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$entity
|
||||
->setInfo('second revision')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('2nd June 2020 8am'))->getTimestamp())
|
||||
->setRevisionLogMessage('second revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'second author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$entity
|
||||
->setInfo('third revision')
|
||||
->setRevisionCreationTime((new \DateTimeImmutable('3rd June 2020 9am'))->getTimestamp())
|
||||
->setRevisionLogMessage('third revision log')
|
||||
->setRevisionUser($this->drupalCreateUser(name: 'third author'))
|
||||
->setNewRevision();
|
||||
$entity->save();
|
||||
|
||||
$this->drupalGet($entity->toUrl('version-history'));
|
||||
$this->assertSession()->elementsCount('css', 'table tbody tr', 3);
|
||||
|
||||
// Order is newest to oldest revision by creation order.
|
||||
$row1 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(1)');
|
||||
// Latest revision does not have revert or delete revision operation.
|
||||
$this->assertSession()->elementNotExists('named', ['link', 'Revert'], $row1);
|
||||
$this->assertSession()->elementNotExists('named', ['link', 'Delete'], $row1);
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', 'third revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(1)', '06/03/2020 - 09:00 by third author');
|
||||
|
||||
$row2 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(2)');
|
||||
$this->assertSession()->elementExists('named', ['link', 'Revert'], $row2);
|
||||
$this->assertSession()->elementExists('named', ['link', 'Delete'], $row2);
|
||||
$this->assertSession()->elementTextNotContains('css', 'table tbody tr:nth-child(2)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(2)', 'second revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(2)', '06/02/2020 - 08:00 by second author');
|
||||
|
||||
$row3 = $this->assertSession()->elementExists('css', 'table tbody tr:nth-child(3)');
|
||||
$this->assertSession()->elementExists('named', ['link', 'Revert'], $row3);
|
||||
$this->assertSession()->elementExists('named', ['link', 'Delete'], $row3);
|
||||
$this->assertSession()->elementTextNotContains('css', 'table tbody tr:nth-child(2)', 'Current revision');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(3)', 'first revision log');
|
||||
$this->assertSession()->elementTextContains('css', 'table tbody tr:nth-child(3)', '06/01/2020 - 07:00 by first author');
|
||||
}
|
||||
|
||||
}
|
|
@ -97,11 +97,45 @@ class BlockContentAccessHandlerTest extends KernelTestBase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test block content entity access.
|
||||
*
|
||||
* @param string $operation
|
||||
* The entity operation to test.
|
||||
* @param bool $published
|
||||
* Whether the latest revision should be published.
|
||||
* @param bool $reusable
|
||||
* Whether the block content should be reusable. Non-reusable blocks are
|
||||
* typically used in Layout Builder.
|
||||
* @param array $permissions
|
||||
* Permissions to grant to the test user.
|
||||
* @param string|null $parent_access
|
||||
* Whether the test user has access to the parent entity, valid values are
|
||||
* 'allowed', 'forbidden', or 'neutral'. Set to NULL to assert parent will
|
||||
* not be called.
|
||||
* @param string $expected_access
|
||||
* The expected access for the user and block content. Valid values are
|
||||
* 'allowed', 'forbidden', or 'neutral'.
|
||||
* @param bool $isLatest
|
||||
* Whether the block content should be the latest revision when checking
|
||||
* access. If FALSE, multiple revisions will be created, and an older
|
||||
* revision will be loaded before checking access.
|
||||
*
|
||||
* @covers ::checkAccess
|
||||
*
|
||||
* @dataProvider providerTestAccess
|
||||
*/
|
||||
public function testAccess($operation, $published, $reusable, $permissions, $parent_access, $expected_access) {
|
||||
public function testAccess(string $operation, bool $published, bool $reusable, array $permissions, ?string $parent_access, string $expected_access, bool $isLatest = TRUE) {
|
||||
/** @var \Drupal\Core\Entity\RevisionableStorageInterface $entityStorage */
|
||||
$entityStorage = \Drupal::entityTypeManager()->getStorage('block_content');
|
||||
|
||||
$loadRevisionId = NULL;
|
||||
if (!$isLatest) {
|
||||
// Save a historical revision, then setup for a new revision to be saved.
|
||||
$this->blockEntity->save();
|
||||
$loadRevisionId = $this->blockEntity->getRevisionId();
|
||||
$this->blockEntity = $entityStorage->createRevision($this->blockEntity);
|
||||
}
|
||||
|
||||
$published ? $this->blockEntity->setPublished() : $this->blockEntity->setUnpublished();
|
||||
$reusable ? $this->blockEntity->setReusable() : $this->blockEntity->setNonReusable();
|
||||
|
||||
|
@ -144,6 +178,11 @@ class BlockContentAccessHandlerTest extends KernelTestBase {
|
|||
}
|
||||
$this->blockEntity->save();
|
||||
|
||||
// Reload a previous revision.
|
||||
if ($loadRevisionId !== NULL) {
|
||||
$this->blockEntity = $entityStorage->loadRevision($loadRevisionId);
|
||||
}
|
||||
|
||||
$result = $this->accessControlHandler->access($this->blockEntity, $operation, $user, TRUE);
|
||||
switch ($expected_access) {
|
||||
case 'allowed':
|
||||
|
@ -387,6 +426,145 @@ class BlockContentAccessHandlerTest extends KernelTestBase {
|
|||
'neutral',
|
||||
],
|
||||
];
|
||||
|
||||
// View all revisions:
|
||||
$cases['view all revisions:none'] = [
|
||||
'view all revisions',
|
||||
TRUE,
|
||||
TRUE,
|
||||
[],
|
||||
NULL,
|
||||
'neutral',
|
||||
];
|
||||
$cases['view all revisions:administer blocks'] = [
|
||||
'view all revisions',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'allowed',
|
||||
];
|
||||
$cases['view all revisions:view bundle'] = [
|
||||
'view all revisions',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['view any square block content history'],
|
||||
NULL,
|
||||
'allowed',
|
||||
];
|
||||
|
||||
// Revert revisions:
|
||||
$cases['revert:none:latest'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
[],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['revert:none:historical'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
[],
|
||||
NULL,
|
||||
'neutral',
|
||||
FALSE,
|
||||
];
|
||||
$cases['revert:administer blocks:latest'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['revert:administer blocks:historical'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'allowed',
|
||||
FALSE,
|
||||
];
|
||||
$cases['revert:revert bundle:latest'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['revert:revert bundle:historical'] = [
|
||||
'revert',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['revert any square block content revisions'],
|
||||
NULL,
|
||||
'allowed',
|
||||
FALSE,
|
||||
];
|
||||
|
||||
// Delete revisions:
|
||||
$cases['delete revision:none:latest'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
[],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['delete revision:none:historical'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
[],
|
||||
NULL,
|
||||
'neutral',
|
||||
FALSE,
|
||||
];
|
||||
$cases['delete revision:administer blocks:latest'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['delete revision:administer blocks:historical'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'allowed',
|
||||
FALSE,
|
||||
];
|
||||
$cases['delete revision:delete bundle:latest'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['administer blocks'],
|
||||
NULL,
|
||||
'forbidden',
|
||||
TRUE,
|
||||
];
|
||||
$cases['delete revision:delete bundle:historical'] = [
|
||||
'delete revision',
|
||||
TRUE,
|
||||
TRUE,
|
||||
['delete any square block content revisions'],
|
||||
NULL,
|
||||
'allowed',
|
||||
FALSE,
|
||||
];
|
||||
|
||||
return $cases;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue