Commit 9d6dcefd authored by effulgentsia's avatar effulgentsia

Issue #2976334 by tedbow, Wim Leers, johndevman, tim.plunkett, amateescu,...

Issue #2976334 by tedbow, Wim Leers, johndevman, tim.plunkett, amateescu, phenaproxima, larowlan, Berdir, EclipseGc, samuel.mortenson, johnzzon: Allow Custom blocks to be set as non-reusable adding access restriction based on where it was used
parent 3b3eda50
......@@ -6,18 +6,32 @@
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
/**
* Adds a 'reusable' filter to all Custom Block views.
*/
function block_content_post_update_add_views_reusable_filter(&$sandbox = NULL) {
$data_table = \Drupal::entityTypeManager()
->getDefinition('block_content')
->getDataTable();
$entity_type = \Drupal::entityTypeManager()->getDefinition('block_content');
$storage = \Drupal::entityTypeManager()->getStorage('block_content');
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($data_table) {
// If the storage class is an instance SqlContentEntityStorage we can use it
// to determine the table to use, otherwise we have to get the table from the
// entity type.
if ($storage instanceof SqlContentEntityStorage) {
$table = $entity_type->isTranslatable() ? $storage->getDataTable() : $storage->getBaseTable();
}
else {
$table = $entity_type->isTranslatable() ? $entity_type->getDataTable() : $entity_type->getBaseTable();
}
// If we were not able to get a table name we can not update the views.
if (empty($table)) {
return;
}
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($table) {
/** @var \Drupal\views\ViewEntityInterface $view */
if ($view->get('base_table') != $data_table) {
if ($view->get('base_table') !== $table) {
return FALSE;
}
$save_view = FALSE;
......@@ -28,12 +42,42 @@ function block_content_post_update_add_views_reusable_filter(&$sandbox = NULL) {
($display_name === 'default' || isset($display['display_options']['filters']))) {
$display['display_options']['filters']['reusable'] = [
'id' => 'reusable',
'plugin_id' => 'boolean',
'table' => $data_table,
'table' => $table,
'field' => 'reusable',
'relationship' => 'none',
'group_type' => 'group',
'admin_label' => '',
'operator' => '=',
'value' => '1',
'group' => '1',
'exposed' => FALSE,
'expose' => [
'operator_id' => '',
'label' => '',
'description' => '',
'use_operator' => FALSE,
'operator' => '',
'identifier' => '',
'required' => FALSE,
'remember' => FALSE,
'multiple' => FALSE,
],
'is_grouped' => FALSE,
'group_info' => [
'label' => '',
'description' => '',
'identifier' => '',
'optional' => TRUE,
'widget' => 'select',
'multiple' => FALSE,
'remember' => FALSE,
'default_group' => 'All',
'default_group_multiple' => [],
'group_items' => [],
],
'entity_type' => 'block_content',
'entity_field' => 'reusable',
'plugin_id' => 'boolean',
];
$save_view = TRUE;
}
......
......@@ -13,7 +13,6 @@
*/
class AccessGroupAnd implements AccessibleInterface {
/**
* The access dependencies.
*
......
......@@ -55,12 +55,14 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
if ($operation === 'view') {
$access = AccessResult::allowedIf($entity->isPublished())->addCacheableDependency($entity)
$access = AccessResult::allowedIf($entity->isPublished())
->orIf(AccessResult::allowedIfHasPermission($account, 'administer blocks'));
}
else {
$access = 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.
$access->addCacheableDependency($entity);
/** @var \Drupal\block_content\BlockContentInterface $entity */
if ($entity->isReusable() === FALSE) {
......
......@@ -217,8 +217,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
->setDescription(t('A boolean indicating whether this block is reusable.'))
->setTranslatable(FALSE)
->setRevisionable(FALSE)
->setDefaultValue(TRUE)
->setInitialValue(TRUE);
->setDefaultValue(TRUE);
return $fields;
}
......@@ -306,7 +305,7 @@ public function setRevisionLogMessage($revision_log_message) {
* {@inheritdoc}
*/
public function isReusable() {
return $this->get('reusable')->first()->get('value')->getCastedValue();
return (bool) $this->get('reusable')->value;
}
/**
......
<?php
/**
* @file
* Contains database additions to drupal-8.bare.standard.php.gz for testing the
* upgrade path of https://www.drupal.org/project/drupal/issues/2976334.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
// Override configuration for 'block_content' View with extra display with with
// overridden filters.
$config = Yaml::decode(file_get_contents(__DIR__ . '/views.view.block_content_2976334.yml'));
$connection->update('config')
->fields([
'data' => serialize($config),
])
->condition('name', 'views.view.' . $config['id'])
->execute();
name: "Custom Block module reusable tests"
type: module
description: "Support module for custom block reusable testing."
package: Testing
version: VERSION
core: 8.x
dependencies:
- drupal:block_content
- drupal:views
......@@ -9,6 +9,7 @@
* Tests 'reusable' field related update functions for the Block Content module.
*
* @group Update
* @group block_content
* @group legacy
*/
class BlockContentReusableUpdateTest extends UpdatePathTestBase {
......@@ -18,29 +19,26 @@ class BlockContentReusableUpdateTest extends UpdatePathTestBase {
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.4.0.bare.standard.php.gz',
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
// Override the 'block_content' view with an extra display with overridden
// filters. This extra display should also have a filter added for
// 'reusable' field so that it does not expose non-reusable fields. This
// display also has a filter that only shows blocks that contain 'block2'
// in the 'info' field.
__DIR__ . '/../../../fixtures/update/drupal-8.views_block_content-2976334.php',
];
}
/**
* Tests adding 'reusable' entity base field to the block content entity type.
*
* @see block_content_update_8600
* @see block_content_post_update_add_views_reusable_filter
* @see block_content_update_8600()
* @see block_content_post_update_add_views_reusable_filter()
*/
public function testReusableFieldAddition() {
$assert_session = $this->assertSession();
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
// Delete custom block library view.
$this->config('views.view.block_content')->delete();
// Install the test module with the 'block_content' view with an extra
// display with overridden filters. This extra display should also have a
// filter added for 'reusable' field so that it does not expose non-reusable
// fields. This display also has a filter that only shows blocks that
// contain 'block2' in the 'info' field.
$this->container->get('module_installer')->install(['block_content_view_override']);
// Ensure that 'reusable' field is not present before updates.
$this->assertEmpty($entity_definition_update_manager->getFieldStorageDefinition('reusable', 'block_content'));
......
......@@ -100,7 +100,6 @@ public function testMergeNonGroup($use_set_first) {
$accessResultNeutral = $dependencies[1]->access('view', $this->account, TRUE);
$this->assertTrue($accessResultNeutral->isNeutral());
$this->assertEquals('I have no opinion', $accessResultNeutral->getReason());
}
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment