diff --git a/core/modules/content_moderation/src/ModerationInformation.php b/core/modules/content_moderation/src/ModerationInformation.php index 0fc9af4d2ccba58e935af965c346ee813b351693..7e3e513307fe0772d2b0b18a0f109a7445345e0e 100644 --- a/core/modules/content_moderation/src/ModerationInformation.php +++ b/core/modules/content_moderation/src/ModerationInformation.php @@ -87,6 +87,9 @@ public function getLatestRevisionId($entity_type_id, $entity_id) { $result = $storage->getQuery() ->latestRevision() ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) + // No access check is performed here since this is an API function and + // should return the same ID regardless of the current user. + ->accessCheck(FALSE) ->execute(); if ($result) { return key($result); @@ -102,6 +105,9 @@ public function getDefaultRevisionId($entity_type_id, $entity_id) { $result = $storage->getQuery() ->currentRevision() ->condition($this->entityTypeManager->getDefinition($entity_type_id)->getKey('id'), $entity_id) + // No access check is performed here since this is an API function and + // should return the same ID regardless of the current user. + ->accessCheck(FALSE) ->execute(); if ($result) { return key($result); diff --git a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php index ea79c2d0558c6b9a5b08aa2437d20aeadf8d5967..76e9d97608c48c44f52c945bc8aff40448f6ab03 100644 --- a/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php +++ b/core/modules/content_moderation/tests/src/Functional/NodeAccessTest.php @@ -2,6 +2,8 @@ namespace Drupal\Tests\content_moderation\Functional; +use Drupal\node\Entity\NodeType; + /** * Tests permission access control around nodes. * @@ -19,7 +21,7 @@ class NodeAccessTest extends ModerationStateTestBase { 'block', 'block_content', 'node', - 'node_access_test_empty', + 'node_access_test', ]; /** @@ -49,6 +51,9 @@ protected function setUp() { $this->createContentTypeFromUi('Moderated content', 'moderated_content', FALSE); $this->grantUserPermissionToCreateContentOfType($this->adminUser, 'moderated_content'); + // Add the private field to the node type. + node_access_test_add_field(NodeType::load('moderated_content')); + // Rebuild permissions because hook_node_grants() is implemented by the // node_access_test_empty module. node_access_rebuild(); @@ -58,6 +63,10 @@ protected function setUp() { * Verifies that a non-admin user can still access the appropriate pages. */ public function testPageAccess() { + // Initially disable access grant records in + // node_access_test_node_access_records(). + \Drupal::state()->set('node_access_test.private', TRUE); + $this->drupalLogin($this->adminUser); // Access the node form before moderation is enabled, the publication state @@ -149,6 +158,30 @@ public function testPageAccess() { $this->assertResponse(403); $this->drupalGet($view_path); $this->assertResponse(200); + + // Now create a private node that the user is not granted access to by the + // node grants, but is granted access via hook_node_access(). + // @see node_access_test_node_access + $node = $this->createNode([ + 'type' => 'moderated_content', + 'private' => TRUE, + 'uid' => $this->adminUser->id(), + ]); + $user = $this->createUser([ + 'use editorial transition publish', + ]); + $this->drupalLogin($user); + + // Grant access to the node via node_access_test_node_access(). + \Drupal::state()->set('node_access_test.allow_uid', $user->id()); + + $this->drupalGet($node->toUrl()); + $this->assertResponse(200); + + // Verify the moderation form is in place by publishing the node. + $this->drupalPostForm(NULL, [], t('Apply')); + $node = \Drupal::entityTypeManager()->getStorage('node')->loadUnchanged($node->id()); + $this->assertEquals('published', $node->moderation_state->value); } } diff --git a/core/modules/content_moderation/tests/src/Kernel/NodeAccessTest.php b/core/modules/content_moderation/tests/src/Kernel/NodeAccessTest.php new file mode 100644 index 0000000000000000000000000000000000000000..6716ca36100cbe2915fb0bd71f6934daa19fd173 --- /dev/null +++ b/core/modules/content_moderation/tests/src/Kernel/NodeAccessTest.php @@ -0,0 +1,88 @@ +<?php + +namespace Drupal\Tests\content_moderation\Kernel; + +use Drupal\KernelTests\KernelTestBase; +use Drupal\node\Entity\NodeType; +use Drupal\Tests\node\Traits\NodeCreationTrait; +use Drupal\Tests\user\Traits\UserCreationTrait; +use Drupal\workflows\Entity\Workflow; + +/** + * Tests with node access enabled. + * + * @group content_moderation + */ +class NodeAccessTest extends KernelTestBase { + + use NodeCreationTrait; + use UserCreationTrait; + + /** + * The moderation information service. + * + * @var \Drupal\content_moderation\ModerationInformationInterface + */ + protected $moderationInformation; + + /** + * {@inheritdoc} + */ + public static $modules = [ + 'content_moderation', + 'filter', + 'node', + 'node_access_test', + 'system', + 'user', + 'workflows', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->installEntitySchema('content_moderation_state'); + $this->installEntitySchema('node'); + $this->installEntitySchema('user'); + $this->installEntitySchema('workflow'); + $this->installConfig(['content_moderation', 'filter']); + $this->installSchema('system', ['sequences']); + $this->installSchema('node', ['node_access']); + + // Add a moderated node type. + $node_type = NodeType::create([ + 'type' => 'page', + 'label' => 'Page', + ]); + $node_type->save(); + $workflow = Workflow::load('editorial'); + $workflow->getTypePlugin()->addEntityTypeAndBundle('node', 'page'); + $workflow->save(); + + $this->moderationInformation = \Drupal::service('content_moderation.moderation_information'); + } + + /** + * Tests for moderation information methods with node access. + */ + public function testModerationInformation() { + // Create an admin user. + $user = $this->createUser([], NULL, TRUE); + \Drupal::currentUser()->setAccount($user); + + // Create a node. + $node = $this->createNode(['type' => 'page']); + $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id())); + $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id())); + + // Create a non-admin user. + $user = $this->createUser(); + \Drupal::currentUser()->setAccount($user); + $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getDefaultRevisionId('node', $node->id())); + $this->assertEquals($node->getRevisionId(), $this->moderationInformation->getLatestRevisionId('node', $node->id())); + } + +} diff --git a/core/modules/node/tests/modules/node_access_test/node_access_test.module b/core/modules/node/tests/modules/node_access_test/node_access_test.module index 40baeb53edede3092bd29f2ec815ee8f5d45b5b6..5a9756b51adc8f80b58fab29aadb3a6b71aff342 100644 --- a/core/modules/node/tests/modules/node_access_test/node_access_test.module +++ b/core/modules/node/tests/modules/node_access_test/node_access_test.module @@ -152,6 +152,12 @@ function node_access_test_node_access(NodeInterface $node, $op, AccountInterface // Make all Catalan content secret. return AccessResult::forbidden()->setCacheMaxAge(0); } + + // Grant access if a specific user is specified. + if (\Drupal::state()->get('node_access_test.allow_uid') === $account->id()) { + return AccessResult::allowed(); + } + // No opinion. return AccessResult::neutral()->setCacheMaxAge(0); }