diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 751a4c1..cc1e9b7 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -11,8 +11,9 @@ taxonomy_permissions 7.x-1.1 (2016-07-27): - Add a dummy test that never fails, to keep d.o's testbot happy. taxonomy_permissions 7.x-1.0 (2015-06-11): - - #2022707: After two years and 513 known installations it's time to create a release (no functional change in this commit). + - #2022707: After two years and 513 known installations it's time to create a + release (no functional change in this commit). taxonomy_permissions 7.x-1.0-rc1 (2013-06-18): - - Initial commit of Taxonomy Permissions, a module to add more permissions to the Taxonomy core module. - + - Initial commit of Taxonomy Permissions, a module to add more permissions to + the Taxonomy core module. diff --git a/README.txt b/README.txt index 2bb547e..3ccef73 100644 --- a/README.txt +++ b/README.txt @@ -59,4 +59,3 @@ For paid support and customizations of this module or other Drupal work contact the maintainer through his contact form: http://drupal.org/user/82964 - diff --git a/src/TaxonomyPermissionsControlHandler.php b/src/TaxonomyPermissionsControlHandler.php index 06f87f0..e512ce2 100644 --- a/src/TaxonomyPermissionsControlHandler.php +++ b/src/TaxonomyPermissionsControlHandler.php @@ -20,24 +20,49 @@ class TaxonomyPermissionsControlHandler extends EntityAccessControlHandler { protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) { switch ($operation) { case 'view': - return AccessResult::allowedIfHasPermissions($account, ["view terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); - break; + + return AccessResult::allowedIfHasPermissions( + $account, + [ + "view terms in {$entity->bundle()}", + 'administer taxonomy', + ], + 'OR'); case 'create': - return AccessResult::allowedIfHasPermissions($account, ["create terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); - break; + + return AccessResult::allowedIfHasPermissions( + $account, + [ + "create terms in {$entity->bundle()}", + 'administer taxonomy', + ], + 'OR'); case 'update': - return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); - break; + + return AccessResult::allowedIfHasPermissions( + $account, + [ + "edit terms in {$entity->bundle()}", + 'administer taxonomy', + ], + 'OR'); case 'delete': - return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR'); - break; + + return AccessResult::allowedIfHasPermissions( + $account, + [ + "delete terms in {$entity->bundle()}", + 'administer taxonomy', + ], + 'OR'); default: // No opinion. return AccessResult::neutral(); + } } diff --git a/src/Tests/TaxonomyPermissionsTestBase.php b/src/Tests/TaxonomyPermissionsTestBase.php deleted file mode 100644 index b71d00d..0000000 --- a/src/Tests/TaxonomyPermissionsTestBase.php +++ /dev/null @@ -1,394 +0,0 @@ -vocabulary = $this->createVocabulary(); - $this->term1 = $this->createTerm($this->vocabulary); - - // We remove standard permission provided by default. - $perms[] = 'view terms in ' . $this->vocabulary->id(); - user_role_revoke_permissions(AccountInterface::ANONYMOUS_ROLE, $perms); - user_role_revoke_permissions(AccountInterface::AUTHENTICATED_ROLE, $perms); - - $this->drupalCreateContentType(['type' => 'article']); - - $this->authorizedUser = $this->drupalCreateUser([ - 'create article content', - 'edit any article content', - 'access content', - 'view terms in ' . $this->vocabulary->id(), - ]); - - $this->basicUser = $this->drupalCreateUser([ - 'create article content', - 'edit any article content', - 'access content', - ]); - - $field_name = 'field_term'; - $this->attachFields($field_name); - - $this->article1 = $this->createSimpleArticle('Article 1', $field_name, $this->term1->id()); - } - - /** - * Tests if a user without permissions can view terms on node. - */ - protected function testViewTerm() { - - $this->drupalLogin($this->authorizedUser); - $this->drupalGet("node/{$this->article1->id()}"); - $this->assertResponse(200); - $this->assertText($this->term1->getName()); - $this->assertLink($this->term1->getName()); - - $this->drupalLogin($this->basicUser); - $this->drupalGet("node/{$this->article1->id()}"); - $this->assertResponse(200); - $this->assertNoText($this->term1->getName()); - $this->assertNoLink($this->term1->getName()); - } - - /** - * Tests if a user without permissions can access to term's page. - */ - protected function testAccessTermPage() { - $this->drupalLogin($this->authorizedUser); - $this->drupalGet("taxonomy/term/{$this->term1->id()}"); - $this->assertResponse(200); - - $this->drupalLogin($this->basicUser); - $this->drupalGet("taxonomy/term/{$this->term1->id()}"); - $this->assertResponse(403); - - - } - - /** - * Tests if a user without permissions can access to the field form. - */ - protected function testAccessFormTerm() { - - $this->drupalLogin($this->authorizedUser); - $this->drupalGet("node/{$this->article1->id()}/edit"); - $this->assertResponse(200); - $this->assertFieldByName('field_term[0][target_id]', $this->term1->getName() . ' (' . $this->term1->id() . ')', 'The expected value is found in the input field'); - - $this->drupalLogin($this->basicUser); - $this->drupalGet("node/{$this->article1->id()}/edit"); - $this->assertResponse(200); - $this->assertNoFieldByName('field_term[0][target_id]', $this->term1->getName() . ' (' . $this->term1->id() . ')', 'The input field taxonomy reference is not accessible'); - - } - - /** - * Creates a taxonomy term reference field on the specified bundle. - * - * @param string $entity_type - * The type of entity the field will be attached to. - * @param string $bundle - * The bundle name of the entity the field will be attached to. - * @param string $field_name - * The name of the field; if it already exists, a new instance of existing - * field will be created. - * @param string $field_label - * The label of the field. - * @param string $target_entity_type - * The type of the referenced entity. - * @param string $selection_handler - * The selection handler used by this field. - * @param array $selection_handler_settings - * An array of settings supported by the selection handler specified above. - * (e.g. 'target_bundles', 'sort', 'auto_create', etc). - * @param int $cardinality - * The cardinality of the field. - * @param string $user_method - * The method used for granting access to user. - * @param int $priority - * The priority access. - * - * @return \Drupal\field\Entity\FieldConfig $field - * The field created or loaded. - * - * @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase::buildConfigurationForm() - */ - protected function createField($entity_type, $bundle, $field_name, $field_label, $target_entity_type, $selection_handler = 'default', $selection_handler_settings = array(), $cardinality = 1, $user_method = 'user', $priority = 0) { - // Look for or add the specified field to the requested entity bundle. - if (!FieldStorageConfig::loadByName($entity_type, $field_name)) { - FieldStorageConfig::create(array( - 'field_name' => $field_name, - 'type' => 'entity_reference', - 'entity_type' => $entity_type, - 'cardinality' => $cardinality, - 'settings' => array( - 'target_type' => $target_entity_type, - ), - ))->save(); - } - if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) { - FieldConfig::create(array( - 'field_name' => $field_name, - 'entity_type' => $entity_type, - 'bundle' => $bundle, - 'label' => $field_label, - 'settings' => array( - 'handler' => $selection_handler, - 'handler_settings' => $selection_handler_settings, - ), - ))->save(); - } - $field = FieldConfig::loadByName($entity_type, $bundle, $field_name); - return $field; - } - - /** - * Set the widget for a component in a form display. - * - * @param string $form_display_id - * The form display id. - * @param string $entity_type - * The entity type name. - * @param string $bundle - * The bundle name. - * @param string $field_name - * The field name to set. - * @param string $widget_id - * The widget id to set. - * @param array $settings - * The settings of widget. - * @param string $mode - * The mode name. - */ - protected function setFormDisplay($form_display_id, $entity_type, $bundle, $field_name, $widget_id, $settings, $mode = 'default') { - // Set article's form display. - $this->formDisplay = EntityFormDisplay::load($form_display_id); - - if (!$this->formDisplay) { - EntityFormDisplay::create([ - 'targetEntityType' => $entity_type, - 'bundle' => $bundle, - 'mode' => $mode, - 'status' => TRUE, - ])->save(); - $this->formDisplay = EntityFormDisplay::load($form_display_id); - } - if ($this->formDisplay instanceof EntityFormDisplayInterface) { - $this->formDisplay->setComponent($field_name, [ - 'type' => $widget_id, - 'settings' => $settings, - ])->save(); - } - } - - /** - * Set the widget for a component in a View display. - * - * @param string $form_display_id - * The form display id. - * @param string $entity_type - * The entity type name. - * @param string $bundle - * The bundle name. - * @param string $field_name - * The field name to set. - * @param string $formatter_id - * The formatter id to set. - * @param array $settings - * The settings of widget. - * @param string $mode - * The mode name. - */ - protected function setViewDisplay($form_display_id, $entity_type, $bundle, $field_name, $formatter_id, $settings, $mode = 'default') { - // Set article's view display. - $this->viewDisplay = EntityViewDisplay::load($form_display_id); - if (!$this->viewDisplay) { - EntityViewDisplay::create([ - 'targetEntityType' => $entity_type, - 'bundle' => $bundle, - 'mode' => $mode, - 'status' => TRUE, - ])->save(); - $this->viewDisplay = EntityViewDisplay::load($form_display_id); - } - if ($this->viewDisplay instanceof EntityViewDisplayInterface) { - $this->viewDisplay->setComponent($field_name, [ - 'type' => $formatter_id, - 'settings' => $settings, - ])->save(); - } - - } - - /** - * Helper function to create and attach a field to a node. - * - * @param string $field_name - * The field name to create and attach. - */ - protected function attachFields($field_name) { - // Add a field to the article content type which reference term. - $handler_settings = array( - 'target_bundles' => array( - $this->vocabulary->id() => $this->vocabulary->id(), - ), - 'auto_create' => FALSE, - ); - - $this->createField('node', 'article', $field_name, 'Term referenced', 'taxonomy_term', 'default', $handler_settings); - - // Set the form display. - $settings = [ - 'match_operator' => 'CONTAINS', - 'size' => 30, - 'placeholder' => '', - ]; - $this->setFormDisplay('node.article.default', 'node', 'article', $field_name, 'entity_reference_autocomplete', $settings); - - // Set the view display. - $settings = [ - 'link' => TRUE, - ]; - $this->setViewDisplay('node.article.default', 'node', 'article', $field_name, 'entity_reference_label', $settings); - - } - - /** - * Create an article with value for field field_term. - * - * @param string $title - * The content title. - * @param string $field_name - * The Pbf field name to populate. - * @param int|string $target_id - * The target id of taxonomy term. - * - * @return \Drupal\node\NodeInterface - * The node created. - */ - protected function createSimpleArticle($title, $field_name = '', $target_id = NULL) { - $values = array( - 'type' => 'article', - 'title' => $title, - 'body' => [ - 'value' => 'Content body for ' . $title, - ], - ); - if ($field_name) { - $values[$field_name] = [ - 'target_id' => $target_id, - ]; - } - return $this->drupalCreateNode($values); - } - -} diff --git a/taxonomy_permissions.install b/taxonomy_permissions.install index ce31a4a..32ea774 100644 --- a/taxonomy_permissions.install +++ b/taxonomy_permissions.install @@ -10,11 +10,10 @@ use Drupal\taxonomy\Entity\Vocabulary; /** * Implements hook_install(). - * - * Give 'view terms' access to all vocabularies to all users to avoid surprises - * upon installation. */ function taxonomy_permissions_install() { + // Give 'view terms' access to all vocabularies to all users to avoid + // surprises upon installation. $perms = []; $vocabularies = Vocabulary::loadMultiple(); foreach ($vocabularies as $id => $vocabulary) { diff --git a/tests/src/Functional/TaxonomyPermissionsTestBase.php b/tests/src/Functional/TaxonomyPermissionsTestBase.php new file mode 100644 index 0000000..4224296 --- /dev/null +++ b/tests/src/Functional/TaxonomyPermissionsTestBase.php @@ -0,0 +1,382 @@ +vocabulary = $this->createVocabulary(); + $this->term1 = $this->createTerm($this->vocabulary); + + // We remove standard permission provided by default. + $perms[] = 'view terms in ' . $this->vocabulary->id(); + user_role_revoke_permissions(AccountInterface::ANONYMOUS_ROLE, $perms); + user_role_revoke_permissions(AccountInterface::AUTHENTICATED_ROLE, $perms); + + $this->drupalCreateContentType(['type' => 'article']); + + $this->authorizedUser = $this->drupalCreateUser([ + 'create article content', + 'edit any article content', + 'access content', + 'view terms in ' . $this->vocabulary->id(), + ]); + + $this->basicUser = $this->drupalCreateUser([ + 'create article content', + 'edit any article content', + 'access content', + ]); + + $field_name = 'field_term'; + $this->attachFields($field_name); + + $this->article1 = $this->createSimpleArticle('Article 1', $field_name, $this->term1->id()); + } + + /** + * Tests if a user without permissions can view terms on node. + */ + public function testViewTerm() { + $this->drupalLogin($this->authorizedUser); + $this->drupalGet("node/{$this->article1->id()}"); + $this->assertResponse(200); + $this->assertText($this->term1->getName()); + $this->assertLink($this->term1->getName()); + + $this->drupalLogin($this->basicUser); + $this->drupalGet("node/{$this->article1->id()}"); + $this->assertResponse(200); + $this->assertNoText($this->term1->getName()); + $this->assertNoLink($this->term1->getName()); + } + + /** + * Tests if a user without permissions can access to term's page. + */ + public function testAccessTermPage() { + $this->drupalLogin($this->authorizedUser); + $this->drupalGet("taxonomy/term/{$this->term1->id()}"); + $this->assertResponse(200); + + $this->drupalLogin($this->basicUser); + $this->drupalGet("taxonomy/term/{$this->term1->id()}"); + $this->assertResponse(403); + } + + /** + * Tests if a user without permissions can access to the field form. + */ + public function testAccessFormTerm() { + $this->drupalLogin($this->authorizedUser); + $this->drupalGet("node/{$this->article1->id()}/edit"); + $this->assertResponse(200); + $this->assertFieldByName('field_term[0][target_id]', $this->term1->getName() . ' (' . $this->term1->id() . ')', 'The expected value is found in the input field'); + + $this->drupalLogin($this->basicUser); + $this->drupalGet("node/{$this->article1->id()}/edit"); + $this->assertResponse(200); + $this->assertNoFieldByName('field_term[0][target_id]', $this->term1->getName() . ' (' . $this->term1->id() . ')', 'The input field taxonomy reference is not accessible'); + } + + /** + * Creates a taxonomy term reference field on the specified bundle. + * + * @param string $entity_type + * The type of entity the field will be attached to. + * @param string $bundle + * The bundle name of the entity the field will be attached to. + * @param string $field_name + * The name of the field; if it already exists, a new instance of existing + * field will be created. + * @param string $field_label + * The label of the field. + * @param string $target_entity_type + * The type of the referenced entity. + * @param string $selection_handler + * The selection handler used by this field. + * @param array $selection_handler_settings + * An array of settings supported by the selection handler specified above. + * (e.g. 'target_bundles', 'sort', 'auto_create', etc). + * @param int $cardinality + * The cardinality of the field. + * @param string $user_method + * The method used for granting access to user. + * @param int $priority + * The priority access. + * + * @return \Drupal\field\Entity\FieldConfig + * The field created or loaded. + * + * @see \Drupal\Core\Entity\Plugin\EntityReferenceSelection\SelectionBase::buildConfigurationForm() + */ + protected function createField($entity_type, $bundle, $field_name, $field_label, $target_entity_type, $selection_handler = 'default', array $selection_handler_settings = [], $cardinality = 1, $user_method = 'user', $priority = 0) { + // Look for or add the specified field to the requested entity bundle. + if (!FieldStorageConfig::loadByName($entity_type, $field_name)) { + FieldStorageConfig::create([ + 'field_name' => $field_name, + 'type' => 'entity_reference', + 'entity_type' => $entity_type, + 'cardinality' => $cardinality, + 'settings' => [ + 'target_type' => $target_entity_type, + ], + ])->save(); + } + if (!FieldConfig::loadByName($entity_type, $bundle, $field_name)) { + FieldConfig::create([ + 'field_name' => $field_name, + 'entity_type' => $entity_type, + 'bundle' => $bundle, + 'label' => $field_label, + 'settings' => [ + 'handler' => $selection_handler, + 'handler_settings' => $selection_handler_settings, + ], + ])->save(); + } + $field = FieldConfig::loadByName($entity_type, $bundle, $field_name); + return $field; + } + + /** + * Set the widget for a component in a form display. + * + * @param string $form_display_id + * The form display id. + * @param string $entity_type + * The entity type name. + * @param string $bundle + * The bundle name. + * @param string $field_name + * The field name to set. + * @param string $widget_id + * The widget id to set. + * @param array $settings + * The settings of widget. + * @param string $mode + * The mode name. + */ + protected function setFormDisplay($form_display_id, $entity_type, $bundle, $field_name, $widget_id, array $settings, $mode = 'default') { + // Set article's form display. + $this->formDisplay = EntityFormDisplay::load($form_display_id); + + if (!$this->formDisplay) { + EntityFormDisplay::create([ + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'mode' => $mode, + 'status' => TRUE, + ])->save(); + $this->formDisplay = EntityFormDisplay::load($form_display_id); + } + if ($this->formDisplay instanceof EntityFormDisplayInterface) { + $this->formDisplay->setComponent($field_name, [ + 'type' => $widget_id, + 'settings' => $settings, + ])->save(); + } + } + + /** + * Set the widget for a component in a View display. + * + * @param string $form_display_id + * The form display id. + * @param string $entity_type + * The entity type name. + * @param string $bundle + * The bundle name. + * @param string $field_name + * The field name to set. + * @param string $formatter_id + * The formatter id to set. + * @param array $settings + * The settings of widget. + * @param string $mode + * The mode name. + */ + protected function setViewDisplay($form_display_id, $entity_type, $bundle, $field_name, $formatter_id, array $settings, $mode = 'default') { + // Set article's view display. + $this->viewDisplay = EntityViewDisplay::load($form_display_id); + if (!$this->viewDisplay) { + EntityViewDisplay::create([ + 'targetEntityType' => $entity_type, + 'bundle' => $bundle, + 'mode' => $mode, + 'status' => TRUE, + ])->save(); + $this->viewDisplay = EntityViewDisplay::load($form_display_id); + } + if ($this->viewDisplay instanceof EntityViewDisplayInterface) { + $this->viewDisplay->setComponent($field_name, [ + 'type' => $formatter_id, + 'settings' => $settings, + ])->save(); + } + } + + /** + * Helper function to create and attach a field to a node. + * + * @param string $field_name + * The field name to create and attach. + */ + protected function attachFields($field_name) { + // Add a field to the article content type which reference term. + $handler_settings = [ + 'target_bundles' => [ + $this->vocabulary->id() => $this->vocabulary->id(), + ], + 'auto_create' => FALSE, + ]; + + $this->createField('node', 'article', $field_name, 'Term referenced', 'taxonomy_term', 'default', $handler_settings); + + // Set the form display. + $settings = [ + 'match_operator' => 'CONTAINS', + 'size' => 30, + 'placeholder' => '', + ]; + $this->setFormDisplay('node.article.default', 'node', 'article', $field_name, 'entity_reference_autocomplete', $settings); + + // Set the view display. + $settings = [ + 'link' => TRUE, + ]; + $this->setViewDisplay('node.article.default', 'node', 'article', $field_name, 'entity_reference_label', $settings); + + } + + /** + * Create an article with value for field field_term. + * + * @param string $title + * The content title. + * @param string $field_name + * The Pbf field name to populate. + * @param int|string $target_id + * The target id of taxonomy term. + * + * @return \Drupal\node\NodeInterface + * The node created. + */ + protected function createSimpleArticle($title, $field_name = '', $target_id = NULL) { + $values = [ + 'type' => 'article', + 'title' => $title, + 'body' => [ + 'value' => 'Content body for ' . $title, + ], + ]; + if ($field_name) { + $values[$field_name] = [ + 'target_id' => $target_id, + ]; + } + return $this->drupalCreateNode($values); + } + +}