diff --git a/core/modules/taxonomy/src/TermAccessControlHandler.php b/core/modules/taxonomy/src/TermAccessControlHandler.php index faf4816..b25dca4 100644 --- a/core/modules/taxonomy/src/TermAccessControlHandler.php +++ b/core/modules/taxonomy/src/TermAccessControlHandler.php @@ -37,14 +37,14 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter return AccessResult::allowed()->cachePerPermissions(); } - return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'."); + return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in {$entity->bundle()}' OR 'administer taxonomy'."); case 'delete': if ($account->hasPermission("delete terms in {$entity->bundle()}")) { return AccessResult::allowed()->cachePerPermissions(); } - return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'."); + return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'."); default: // No opinion. diff --git a/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php new file mode 100644 index 0000000..fb3d065 --- /dev/null +++ b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php @@ -0,0 +1,124 @@ +assertSession(); + + $vocabulary = $this->createVocabulary(); + + // Create two terms. + $published_term = Term::create([ + 'vid' => $vocabulary->id(), + 'name' => 'Published term', + 'status' => 1, + ]); + $published_term->save(); + $unpublished_term = Term::create([ + 'vid' => $vocabulary->id(), + 'name' => 'Unpublished term', + 'status' => 0, + ]); + $unpublished_term->save(); + + // Start off logged in as admin. + $this->drupalLogin($this->drupalCreateUser(['administer taxonomy'])); + + // Test the 'administer taxonomy' permission. + $this->drupalGet('taxonomy/term/' . $published_term->id()); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($published_term, 'view', TRUE); + $this->drupalGet('taxonomy/term/' . $unpublished_term->id()); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($unpublished_term, 'view', TRUE); + + $this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit'); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($published_term, 'update', TRUE); + $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit'); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($unpublished_term, 'update', TRUE); + + $this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete'); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($published_term, 'delete', TRUE); + $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete'); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($unpublished_term, 'delete', TRUE); + + // Test the 'access content' permission. + $this->drupalLogin($this->drupalCreateUser(['access content'])); + + $this->drupalGet('taxonomy/term/' . $published_term->id()); + $assert_session->statusCodeEquals(200); + $this->assertTermAccess($published_term, 'view', TRUE); + + $this->drupalGet('taxonomy/term/' . $unpublished_term->id()); + $assert_session->statusCodeEquals(403); + $this->assertTermAccess($unpublished_term, 'view', FALSE, "The 'access content' permission is required and the taxonomy term must be published."); + + $this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit'); + $assert_session->statusCodeEquals(403); + $this->assertTermAccess($published_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'."); + $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit'); + $assert_session->statusCodeEquals(403); + $this->assertTermAccess($unpublished_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'."); + + $this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete'); + $assert_session->statusCodeEquals(403); + $this->assertTermAccess($published_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'."); + $this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete'); + $assert_session->statusCodeEquals(403); + $this->assertTermAccess($unpublished_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'."); + + // Install the Views module and repeat the checks for the 'view' permission. + \Drupal::service('module_installer')->install(['views'], TRUE); + $this->rebuildContainer(); + + $this->drupalGet('taxonomy/term/' . $published_term->id()); + $assert_session->statusCodeEquals(200); + + // For some reason, Views emits a 404 status code if the argument does not + // validate. + $this->drupalGet('taxonomy/term/' . $unpublished_term->id()); + $assert_session->statusCodeEquals(404); + } + + /** + * Checks access on taxonomy term. + * + * @param \Drupal\taxonomy\TermInterface $term + * A taxonomy term entity. + * @param $access_operation + * The entity operation, e.g. 'view', 'edit', 'delete', etc. + * @param bool $access_allowed + * Whether the current use has access to the given operation or not. + * @param string $access_reason + * (optional) The reason of the access result. + */ + protected function assertTermAccess(TermInterface $term, $access_operation, $access_allowed, $access_reason = '') { + $access_result = $term->access($access_operation, NULL, TRUE); + $this->assertSame($access_allowed, $access_result->isAllowed()); + + if ($access_reason) { + $this->assertSame($access_reason, $access_result->getReason()); + } + } + +}