diff --git a/core/modules/views/src/EntityViewsData.php b/core/modules/views/src/EntityViewsData.php index cf886f4caf..f8d8ed6301 100644 --- a/core/modules/views/src/EntityViewsData.php +++ b/core/modules/views/src/EntityViewsData.php @@ -178,6 +178,7 @@ public function getViewsData() { 'field' => $base_field, 'title' => $this->entityType->getLabel(), 'cache_contexts' => $this->entityType->getListCacheContexts(), + 'access query tag' => $this->entityType->id() . '_access', ]; $data[$base_table]['table']['entity revision'] = FALSE; diff --git a/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.info.yml b/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.info.yml new file mode 100644 index 0000000000..eb54049cca --- /dev/null +++ b/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.info.yml @@ -0,0 +1,8 @@ +name: 'Views test query access' +type: module +description: 'Module to test entity query access in Views.' +package: Testing +version: VERSION +core: 8.x +dependencies: + - drupal:views diff --git a/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.module b/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.module new file mode 100644 index 0000000000..b8e1263c27 --- /dev/null +++ b/core/modules/views/tests/modules/views_test_query_access/views_test_query_access.module @@ -0,0 +1,65 @@ +getMetaData('view'); + $entity_type = $view->getBaseEntityType(); + + $storage = \Drupal::entityTypeManager()->getStorage($entity_type->id()); + if (!($storage instanceof SqlEntityStorageInterface)) { + return; + } + + $table_mapping = $storage->getTableMapping(); + if (!($table_mapping instanceof DefaultTableMapping)) { + return; + } + + $base_table = $table_mapping->getBaseTable(); + $data_table = $table_mapping->getDataTable(); + + // We are excluding entities by UUID, which means we need to be certain the + // base table is joined in the query. + $tables = $query->getTables(); + if (isset($tables[$data_table]) && !isset($tables[$base_table])) { + $data_table_alias = $tables[$data_table]['alias']; + $id_key = $entity_type->getKey('id'); + $base_table = $query->innerJoin($base_table, NULL, "$data_table_alias.$id_key = $base_table.$id_key"); + } + + // Figure out the column name of the UUID field and add a condition on that. + $base_field_definitions = \Drupal::service('entity_field.manager') + ->getBaseFieldDefinitions($entity_type->id()); + $uuid_key = $entity_type->getKey('uuid'); + $uuid_column_name = $table_mapping->getFieldColumnName($base_field_definitions[$uuid_key], NULL); + $query->condition("$base_table.$uuid_column_name", 'hidden-' . $entity_type->id(), '<>'); +} diff --git a/core/modules/views/tests/src/Functional/Entity/EntityQueryAccessTest.php b/core/modules/views/tests/src/Functional/Entity/EntityQueryAccessTest.php new file mode 100644 index 0000000000..73a7f65510 --- /dev/null +++ b/core/modules/views/tests/src/Functional/Entity/EntityQueryAccessTest.php @@ -0,0 +1,108 @@ +container->get('module_installer')->install(['media']); + + $media_type = $this->createMediaType('test'); + $source_field = $media_type->getSource() + ->getSourceFieldDefinition($media_type) + ->getName(); + + $hidden_media = Media::create([ + 'bundle' => $media_type->id(), + // This UUID should prevent this media item from being visible in the + // view. + // @see views_test_access_query_media_access_alter() + 'uuid' => 'hidden-media', + 'name' => $this->randomString(), + $source_field => $this->randomString(), + ]); + $hidden_media->save(); + + $accessible_media = Media::create([ + 'bundle' => $media_type->id(), + 'name' => $this->randomString(), + $source_field => $this->randomString(), + ]); + $accessible_media->save(); + + $account = $this->drupalCreateUser([ + 'access media overview', + 'administer media', + ]); + $this->drupalLogin($account); + + $this->drupalGet('/admin/content/media'); + $assert_session = $this->assertSession(); + $assert_session->statusCodeEquals(200); + $assert_session->linkExists($accessible_media->label()); + $assert_session->linkNotExists($hidden_media->label()); + } + + /** + * Tests that the 'block_content_access' query tag is respected by Views. + */ + public function testBlockContentEntityQueryAccess() { + $this->container->get('module_installer')->install(['block_content']); + + BlockContentType::create([ + 'id' => 'test', + 'label' => 'Test', + ])->save(); + + $hidden_block = BlockContent::create([ + 'type' => 'test', + // This UUID should prevent this block from being visible in the view. + // @see views_test_access_query_block_content_access_alter() + 'uuid' => 'hidden-block_content', + 'info' => $this->randomString(), + ]); + $hidden_block->save(); + + $accessible_block = BlockContent::create([ + 'type' => 'test', + 'info' => $this->randomString(), + ]); + $accessible_block->save(); + + $account = $this->drupalCreateUser([ + 'administer blocks', + ]); + $this->drupalLogin($account); + + $this->drupalGet('/admin/structure/block/block-content'); + $assert_session = $this->assertSession(); + $assert_session->statusCodeEquals(200); + $assert_session->pageTextContains($accessible_block->label()); + $assert_session->pageTextNotContains($hidden_block->label()); + } + +}