access_policy-1.0.x-dev/tests/src/Kernel/AccessPolicySelectionTest.php
tests/src/Kernel/AccessPolicySelectionTest.php
<?php namespace Drupal\Tests\access_policy\Kernel; use Drupal\access_policy\Entity\AccessPolicy; use Drupal\field\Entity\FieldConfig; use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\NodeType; /** * Tests Access Policy selection manager. * * @group access_policy */ class AccessPolicySelectionTest extends AccessPolicyKernelTestBase { /** * The access policy selection service. * * @var \Drupal\access_policy\AccessPolicySelectionInterface */ protected $accessPolicySelection; /** * The entity type settings service. * * @var \Drupal\access_policy\EntityTypeSettingsInterface */ protected $entityTypeSettings; /** * {@inheritdoc} * * @throws \Exception */ protected function setUp(): void { parent::setUp(); NodeType::create(['type' => 'page', 'name' => 'Page']); NodeType::create(['type' => 'article', 'name' => 'Article']); $this->installConfig(['access_policy_test']); $this->entityTypeSettings = $this->container->get('access_policy.entity_type_settings'); $this->accessPolicySelection = $this->container->get('access_policy.selection'); } /** * Tests getting the default access policy for first available policies. * * If the default setting is set to on_create it should return the * first access policy that the user has access too. Prioritized by * weight. * * @throws \Exception */ public function testGetFirstAvailableDefaultAccessPolicy() { // Set access policies as first accessible. $settings = $this->entityTypeSettings->load('node'); $settings->set('selection_strategy', 'manual'); $settings->set('selection_strategy_settings', [ 'allow_empty' => TRUE, 'default_policy' => 'first_available', 'show_operations_link' => FALSE, ]); $settings->save(); AccessPolicy::create([ 'id' => 'policy_test_1', 'label' => 'Policy test 1', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => 0, ])->save(); AccessPolicy::create([ 'id' => 'policy_test_2', 'label' => 'Policy test 2', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => -10, ])->save(); $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', ]); $node->save(); // This user doesn't have permission to any of these access policies so it // should not return anything. $user = $this->createUser(); $default_policy = $this->accessPolicySelection->getDefaultPolicy($node, $user); $this->assertEquals(FALSE, $default_policy, 'This should not return an access policy'); $this->accessPolicySelection->resetCache(); // The user only has access to editing one access policy therefore it // should only return that access policy. $user_2 = $this->createUser([ 'assign policy_test_2 access policy', ]); $default_policy = $this->accessPolicySelection->getDefaultPolicy($node, $user_2); $policy = reset($default_policy); $this->assertEquals('policy_test_2', $policy->id(), 'Only one access policy is assigned.'); $this->accessPolicySelection->resetCache(); // The user has access to two access policies but it will only return the // one with the lowest weight (highest priority). $user_3 = $this->createUser([ 'assign policy_test_1 access policy', 'assign policy_test_2 access policy', ]); $default_policy = $this->accessPolicySelection->getDefaultPolicy($node, $user_3); $policy = reset($default_policy); $this->assertEquals('policy_test_2', $policy->id(), 'policy test 2 has lower weight (higher priority) and should be returned.'); } /** * Tests getting the default access policy when default is empty. * * If the default setting is set to empty the user should not get a default * policy. Even if they have permission to use it. * * @throws \Exception */ public function testGetDefaultAccessPolicyWhenEmpty() { $settings = $this->entityTypeSettings->load('node'); $settings->set('selection_strategy', 'manual'); $settings->save(); $accessPolicySelection = \Drupal::service('access_policy.selection'); AccessPolicy::create([ 'id' => 'policy_test', 'label' => 'Policy test', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => 0, ])->save(); $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', ]); $node->save(); $user = $this->createUser([ 'assign policy_test access policy', ]); $default_policy = $accessPolicySelection->getDefaultPolicy($node, $user); $this->assertEquals(FALSE, $default_policy, 'This should not return an access policy'); } /** * Tests getting the access policy when a selection rule is defined. */ public function testGetAccessPolicyWithSelectionRule() { $policy_1 = AccessPolicy::create([ 'id' => 'policy_test_1', 'label' => 'Policy test 1', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => 0, ]); $policy_1->save(); $policy_2 = AccessPolicy::create([ 'id' => 'policy_test_2', 'label' => 'Policy test 2', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => -10, ]); $policy_2->save(); $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text'); $policy_2->addHandler('selection_rule', $selection_rule); $policy_2->save(); $user_1 = $this->createUser([ 'assign policy_test_1 access policy', 'assign policy_test_2 access policy', ]); $this->setCurrentUser($user_1); // Even though policy_test_2 has lower weight it will not be selected // because the content does not have a value for field_text. $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $policy = reset($policy); $this->assertEquals('policy_test_1', $policy->id(), 'The access policy should be policy_test_1'); // Because this has a value in field_text, policy_test_2 will be selected. $node_2 = $this->createNode([ 'type' => 'page', 'title' => 'Page', 'field_text' => 'This has a value.', ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node_2); $policy = reset($policy); $this->assertEquals('policy_test_2', $policy->id(), 'The access policy should be policy_test_2'); // Remove the field text and save the node, this should change the policy // to policy_test_1. // We need to remove the policyUpdated flag in order to properly test it // again. @see EntityOperations::entityPresave(). unset($node_2->policyUpdated); $node_2->set('field_text', ''); $node_2->save(); $policy_2 = $this->contentAccessPolicyManager->getAccessPolicy($node_2); $policy_2 = reset($policy_2); $this->assertEquals('policy_test_1', $policy_2->id(), 'The access policy should be policy_test_1'); // Article does not have the field_text field, it should be policy_test_1. $node_3 = $this->createNode([ 'type' => 'article', 'title' => 'Article', ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node_3); $policy = reset($policy); $this->assertEquals('policy_test_1', $policy->id(), 'The access policy should be policy_test_1'); // User 2 only has access to policy_test_2 access policy. Because node_4 // does not have text value it should remove any policy. $user_2 = $this->createUser([ 'assign policy_test_2 access policy', ]); $this->setCurrentUser($user_2); $node_4 = $this->createNode([ 'type' => 'page', 'title' => 'Page', 'field_text' => '', ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node_4); $this->assertEmpty($policy, 'The access policy should be empty'); } /** * Tests getting the access policy with multiple AND selection rules. */ public function testGetAccessPolicyWithMultipleAndSelectionRules() { // Create a boolean field for this test. $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_boolean', 'entity_type' => 'node', 'type' => 'boolean', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_name' => 'field_boolean', 'entity_type' => 'node', 'bundle' => 'page', 'label' => "boolean", 'required' => TRUE, 'settings' => [ 'on_label' => 'On', 'off_label' => 'Off', ], ]); $field->save(); $policy_1 = AccessPolicy::create([ 'id' => 'policy_test_1', 'label' => 'Policy test 1', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => -10, ]); $policy_1->save(); // This will only be assigned if field_text is Foo OR Bar. $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy_1->addHandler('selection_rule', $selection_rule); $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_boolean'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'true', ]); $policy_1->addHandler('selection_rule', $selection_rule); $policy_1->save(); $user_1 = $this->createUser([ 'assign policy_test_1 access policy', ]); $this->setCurrentUser($user_1); $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', 'field_text' => 'Foo', 'field_boolean' => TRUE, ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $policy = reset($policy); $this->assertEquals('policy_test_1', $policy->id(), 'policy_test_1 should be assigned'); // Change the boolean value, this should remove the policy. // We need to remove the policyUpdated flag in order to properly test it // again. @see EntityOperations::entityPresave(). unset($node->policyUpdated); $node->set('field_boolean', FALSE); $node->save(); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $this->assertEmpty($policy, 'policy_test_1 should be removed.'); } /** * Tests getting the access policy with multiple OR selection rules. */ public function testGetAccessPolicyWithMultipleOrSelectionRules() { $policy_1 = AccessPolicy::create([ 'id' => 'policy_test_1', 'label' => 'Policy test 1', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => -10, 'selection_rule_operator' => 'OR', ]); $policy_1->save(); // This will only be assigned if field_text is Foo OR Bar. $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy_1->addHandler('selection_rule', $selection_rule); $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'Bar', ]); $policy_1->addHandler('selection_rule', $selection_rule); $policy_1->save(); $user_1 = $this->createUser([ 'assign policy_test_1 access policy', ]); $this->setCurrentUser($user_1); $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', 'field_text' => 'Foo', ]); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $policy = reset($policy); $this->assertEquals('policy_test_1', $policy->id(), 'policy_test_1 should be assigned.'); // Remove the text value, this should remove the policy. // We need to remove the policyUpdated flag in order to properly test it // again. @see EntityOperations::entityPresave(). unset($node->policyUpdated); $node->set('field_text', ''); $node->save(); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $this->assertEmpty($policy, 'policy_test_1 should be removed.'); // Change text to Bar, this should reassign to the policy. unset($node->policyUpdated); $node->set('field_text', 'Bar'); $node->save(); $policy = $this->contentAccessPolicyManager->getAccessPolicy($node); $policy = reset($policy); $this->assertEquals('policy_test_1', $policy->id(), 'policy_test_1 should be assigned.'); } /** * Tests assigning multiple access policies with selection rules. */ public function testGetMultipleAccessPoliciesWithSelectionRules() { $field_storage = FieldStorageConfig::create([ 'field_name' => 'field_text_2', 'entity_type' => 'node', 'type' => 'text', ]); $field_storage->save(); $field = FieldConfig::create([ 'field_storage' => $field_storage, 'bundle' => 'page', ]); $field->save(); $policy_group_1 = AccessPolicy::create([ 'id' => 'policy_group_1', 'label' => 'Policy group 1', 'access_rules' => [], 'target_entity_type_id' => 'node', 'selection_set' => ['restricted'], 'weight' => -10, ]); $policy_group_1->save(); $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'Foo', ]); $policy_group_1->addHandler('selection_rule', $selection_rule); // This policy is second in the list, this is to ensure that only // policy_group_n policies get assigned even though they have different // priorities. $basic_policy = AccessPolicy::create([ 'id' => 'basic', 'label' => 'Basic', 'access_rules' => [], 'target_entity_type_id' => 'node', 'weight' => -5, ]); $basic_policy->save(); $policy_group_2 = AccessPolicy::create([ 'id' => 'policy_group_2', 'label' => 'Policy group 2', 'access_rules' => [], 'target_entity_type_id' => 'node', 'selection_set' => ['restricted'], ]); $policy_group_2->save(); // This will only be assigned if field_text is Foo OR Bar. $selection_rule = $this->selectionRuleManager->getHandler('node', 'field_text_2'); $selection_rule->setSettings([ 'operator' => '=', 'value' => 'Bar', ]); $policy_group_2->addHandler('selection_rule', $selection_rule); $user_1 = $this->createUser([ 'assign policy_group_1 access policy', 'assign policy_group_2 access policy', 'assign basic access policy', ]); $this->setCurrentUser($user_1); $node = $this->createNode([ 'type' => 'page', 'title' => 'Page', 'field_text' => 'Foo', 'field_text_2' => 'Foo bar', ]); $actual = []; $policies = $this->contentAccessPolicyManager->getAccessPolicy($node); foreach ($policies as $policy) { $actual[] = $policy->id(); } $expected = [ 'policy_group_1', 'policy_group_2', ]; $this->assertSame($expected, $actual, 'Both access policies should be assigned.'); } }