diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index b0f1550..889d760 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -420,51 +420,70 @@ function _comment_entity_uses_integer_id($entity_type_id) { } /** - * Implements hook_node_update_index(). - */ -function comment_node_update_index(EntityInterface $node) { - $index_comments = &drupal_static(__FUNCTION__); - - if ($index_comments === NULL) { - // Do not index in the following three cases: - // 1. 'Authenticated user' can search content but can't access comments. - // 2. 'Anonymous user' can search content but can't access comments. - // 3. Any role can search content but can't access comments and access - // comments is not granted by the 'authenticated user' role. In this case - // all users might have both permissions from various roles but it is also - // possible to set up a user to have only search content and so a user - // edit could change the security situation so it is not safe to index the - // comments. - $index_comments = TRUE; - $roles = \Drupal::entityManager()->getStorage('user_role')->loadMultiple(); - $authenticated_can_access = $roles[RoleInterface::AUTHENTICATED_ID]->hasPermission('access comments'); - foreach ($roles as $rid => $role) { - if ($role->hasPermission('search content') && !$role->hasPermission('access comments')) { - if ($rid == RoleInterface::AUTHENTICATED_ID || $rid == RoleInterface::ANONYMOUS_ID || !$authenticated_can_access) { - $index_comments = FALSE; - break; - } + * Check is accessible requested comment field name in requested node. + * + * @param \Drupal\Core\Entity\EntityInterface $node + * Node object for index. + * @param string $field_name + * Field machine name. + * + * @return bool + * Result of check. + */ +function _comment_node_update_index_check_access(EntityInterface $node, $field_name) { + $access = &drupal_static(__FUNCTION__, array()); + $comment_type = $node->{$field_name}->getSetting('comment_type'); + + if (array_key_exists($comment_type, $access)) { + return $access[$comment_type]; + } + + // Do not index in the following three cases: + // 1. 'Authenticated user' can search content but can't access comments. + // 2. 'Anonymous user' can search content but can't access comments. + // 3. Any role can search content but can't access comments and access + // comments is not granted by the 'authenticated user' role. In this case + // all users might have both permissions from various roles but it is also + // possible to set up a user to have only search content and so a user + // edit could change the security situation so it is not safe to index the + // comments. + $access[$comment_type] = TRUE; + $roles = \Drupal::entityManager()->getStorage('user_role')->loadMultiple(); + $authenticated_can_access = $roles[RoleInterface::AUTHENTICATED_ID]->hasPermission('access comments ' . $comment_type); + foreach ($roles as $rid => $role) { + if ($role->hasPermission('search content') && !$role->hasPermission('access comments ' . $comment_type)) { + if ($rid == RoleInterface::AUTHENTICATED_ID || $rid == RoleInterface::ANONYMOUS_ID || !$authenticated_can_access) { + $access[$comment_type] = FALSE; + break; } } } + return $access[$comment_type]; +} + +/** + * Implements hook_node_update_index(). + */ +function comment_node_update_index(EntityInterface $node) { $build = array(); - if ($index_comments) { - foreach (\Drupal::service('comment.manager')->getFields('node') as $field_name => $info) { - // Skip fields that entity does not have. - if (!$node->hasField($field_name)) { - continue; - } - $field_definition = $node->getFieldDefinition($field_name); - $mode = $field_definition->getSetting('default_mode'); - $comments_per_page = $field_definition->getSetting('per_page'); - if ($node->get($field_name)->status) { - $comments = \Drupal::entityManager()->getStorage('comment') - ->loadThread($node, $field_name, $mode, $comments_per_page); - if ($comments) { - $build[] = \Drupal::entityManager()->getViewBuilder('comment')->viewMultiple($comments); - } + foreach (\Drupal::service('comment.manager')->getFields('node') as $field_name => $info) { + // Skip fields that entity does not have. + if (!$node->hasField($field_name)) { + continue; + } + if (!_comment_node_update_index_check_access($node, $field_name)) { + continue; + } + $field_definition = $node->getFieldDefinition($field_name); + $mode = $field_definition->getSetting('default_mode'); + $comments_per_page = $field_definition->getSetting('per_page'); + if ($node->get($field_name)->status) { + $comments = \Drupal::entityManager()->getStorage('comment') + ->loadThread($node, $field_name, $mode, $comments_per_page); + if ($comments) { + $build[] = \Drupal::entityManager()->getViewBuilder('comment')->viewMultiple($comments); } } } @@ -497,7 +516,7 @@ function comment_node_search_result(EntityInterface $node) { } // Do not make a string if comments are hidden. $status = $node->get($field_name)->status; - if (\Drupal::currentUser()->hasPermission('access comments') && $status != CommentItemInterface::HIDDEN) { + if (\Drupal::currentUser()->hasPermission('access comments ' . $node->{$field_name}->getSetting('comment_type')) && $status != CommentItemInterface::HIDDEN) { if ($status == CommentItemInterface::OPEN) { // At least one comment field is open. $open = TRUE; diff --git a/core/modules/comment/comment.permissions.yml b/core/modules/comment/comment.permissions.yml index 664b5e1..8fcac65 100644 --- a/core/modules/comment/comment.permissions.yml +++ b/core/modules/comment/comment.permissions.yml @@ -11,3 +11,6 @@ skip comment approval: title: 'Skip comment approval' edit own comments: title: 'Edit own comments' + +permission_callbacks: + - \Drupal\comment\CommentPermissions::commentTypePermissions diff --git a/core/modules/comment/src/CommentAccessControlHandler.php b/core/modules/comment/src/CommentAccessControlHandler.php index ff6b3b9..16c1545 100644 --- a/core/modules/comment/src/CommentAccessControlHandler.php +++ b/core/modules/comment/src/CommentAccessControlHandler.php @@ -36,11 +36,11 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter switch ($operation) { case 'view': - return AccessResult::allowedIf($account->hasPermission('access comments') && $entity->isPublished())->cachePerPermissions()->addCacheableDependency($entity) + return AccessResult::allowedIf($account->hasPermission('access comments ' . $entity->bundle()) && $entity->isPublished())->cachePerPermissions()->addCacheableDependency($entity) ->andIf($entity->getCommentedEntity()->access($operation, $account, TRUE)); case 'update': - return AccessResult::allowedIf($account->id() && $account->id() == $entity->getOwnerId() && $entity->isPublished() && $account->hasPermission('edit own comments'))->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity); + return AccessResult::allowedIf($account->id() && $account->id() == $entity->getOwnerId() && $entity->isPublished() && $account->hasPermission('edit own comments ' . $entity->bundle()))->cachePerPermissions()->cachePerUser()->addCacheableDependency($entity); default: // No opinion. @@ -52,7 +52,7 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter * {@inheritdoc} */ protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { - return AccessResult::allowedIfHasPermission($account, 'post comments'); + return AccessResult::allowedIfHasPermission($account, 'post comments ' . $entity_bundle); } /** @@ -90,7 +90,7 @@ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_ ]; if ($items && ($entity = $items->getEntity()) && $entity->isNew() && in_array($field_definition->getName(), $create_only_fields, TRUE)) { // We are creating a new comment, user can edit create only fields. - return AccessResult::allowedIfHasPermission($account, 'post comments')->addCacheableDependency($entity); + return AccessResult::allowedIfHasPermission($account, 'post comments ' . $entity->bundle())->addCacheableDependency($entity); } // We are editing an existing comment - create only fields are now read // only. @@ -115,7 +115,7 @@ protected function checkFieldAccess($operation, FieldDefinitionInterface $field_ $commented_entity = $entity->getCommentedEntity(); $anonymous_contact = $commented_entity->get($entity->getFieldName())->getFieldDefinition()->getSetting('anonymous'); $admin_access = AccessResult::allowedIfHasPermission($account, 'administer comments'); - $anonymous_access = AccessResult::allowedIf($entity->isNew() && $account->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT && $account->hasPermission('post comments')) + $anonymous_access = AccessResult::allowedIf($entity->isNew() && $account->isAnonymous() && $anonymous_contact != COMMENT_ANONYMOUS_MAYNOT_CONTACT && $account->hasPermission('post comments ' . $entity->bundle())) ->cachePerPermissions() ->addCacheableDependency($entity) ->addCacheableDependency($field_definition->getConfig($commented_entity->bundle())) diff --git a/core/modules/comment/src/CommentFieldItemList.php b/core/modules/comment/src/CommentFieldItemList.php index 7a4cdad..7074799 100644 --- a/core/modules/comment/src/CommentFieldItemList.php +++ b/core/modules/comment/src/CommentFieldItemList.php @@ -56,8 +56,8 @@ public function access($operation = 'view', AccountInterface $account = NULL, $r // takes care of showing the thread and form based on individual // permissions, so if a user only has ‘post comments’ access, only the // form will be shown and not the comments. - $result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'access comments') - ->orIf(AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'post comments')); + $result = AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'access comments ' . $this->getSetting('comment_type')) + ->orIf(AccessResult::allowedIfHasPermission($account ?: \Drupal::currentUser(), 'post comments ' . $this->getSetting('comment_type'))); return $return_as_object ? $result : $result->isAllowed(); } return parent::access($operation, $account, $return_as_object); diff --git a/core/modules/comment/src/CommentForm.php b/core/modules/comment/src/CommentForm.php index 75191a3..1c7d02c 100644 --- a/core/modules/comment/src/CommentForm.php +++ b/core/modules/comment/src/CommentForm.php @@ -127,7 +127,7 @@ public function form(array $form, FormStateInterface $form_state) { } } else { - $status = ($this->currentUser->hasPermission('skip comment approval') ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED); + $status = ($this->currentUser->hasPermission('skip comment approval ' . $comment->bundle()) ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED); } $date = ''; @@ -352,7 +352,7 @@ public function save(array $form, FormStateInterface $form_state) { $uri = $entity->urlInfo(); $logger = $this->logger('content'); - if ($this->currentUser->hasPermission('post comments') && ($this->currentUser->hasPermission('administer comments') || $entity->{$field_name}->status == CommentItemInterface::OPEN)) { + if ($this->currentUser->hasPermission('post comments ' . $comment->bundle()) && ($this->currentUser->hasPermission('administer comments') || $entity->{$field_name}->status == CommentItemInterface::OPEN)) { $comment->save(); $form_state->setValue('cid', $comment->id()); diff --git a/core/modules/comment/src/CommentLinkBuilder.php b/core/modules/comment/src/CommentLinkBuilder.php index 9998e3f..c53a6b0 100644 --- a/core/modules/comment/src/CommentLinkBuilder.php +++ b/core/modules/comment/src/CommentLinkBuilder.php @@ -101,7 +101,7 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra // Teaser view: display the number of comments that have been posted, // or a link to add new comments if the user has permission, the // entity is open to new comments, and there currently are none. - if ($this->currentUser->hasPermission('access comments')) { + if ($this->currentUser->hasPermission('access comments ' . $field_definition->getSetting('comment_type'))) { if (!empty($entity->get($field_name)->comment_count)) { $links['comment-comments'] = array( 'title' => $this->formatPlural($entity->get($field_name)->comment_count, '1 comment', '@count comments'), @@ -126,7 +126,7 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra // Provide a link to new comment form. if ($commenting_status == CommentItemInterface::OPEN) { $comment_form_location = $field_definition->getSetting('form_location'); - if ($this->currentUser->hasPermission('post comments')) { + if ($this->currentUser->hasPermission('post comments ' . $field_definition->getSetting('comment_type'))) { $links['comment-add'] = array( 'title' => $this->t('Add new comment'), 'language' => $entity->language(), @@ -157,10 +157,10 @@ public function buildCommentedEntityLinks(FieldableEntityInterface $entity, arra // comments. if ($commenting_status == CommentItemInterface::OPEN) { $comment_form_location = $field_definition->getSetting('form_location'); - if ($this->currentUser->hasPermission('post comments')) { + if ($this->currentUser->hasPermission('post comments ' . $field_definition->getSetting('comment_type'))) { // Show the "post comment" link if the form is on another page, or // if there are existing comments that the link will skip past. - if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE || (!empty($entity->get($field_name)->comment_count) && $this->currentUser->hasPermission('access comments'))) { + if ($comment_form_location == CommentItemInterface::FORM_SEPARATE_PAGE || (!empty($entity->get($field_name)->comment_count) && $this->currentUser->hasPermission('access comments ' . $field_definition->getSetting('comment_type')))) { $links['comment-add'] = array( 'title' => $this->t('Add new comment'), 'attributes' => array('title' => $this->t('Share your thoughts and opinions.')), diff --git a/core/modules/comment/src/CommentManager.php b/core/modules/comment/src/CommentManager.php index fcec230..2d7d630 100644 --- a/core/modules/comment/src/CommentManager.php +++ b/core/modules/comment/src/CommentManager.php @@ -149,7 +149,7 @@ public function forbiddenMessage(EntityInterface $entity, $field_name) { $this->authenticatedCanPostComments = $this->entityManager ->getStorage('user_role') ->load(RoleInterface::AUTHENTICATED_ID) - ->hasPermission('post comments'); + ->hasPermission('post comments ' . $entity->{$field_name}->getSetting('comment_type')); } if ($this->authenticatedCanPostComments) { diff --git a/core/modules/comment/src/CommentPermissions.php b/core/modules/comment/src/CommentPermissions.php new file mode 100644 index 0000000..bbf2578 --- /dev/null +++ b/core/modules/comment/src/CommentPermissions.php @@ -0,0 +1,60 @@ +buildPermissions($type); + } + return $perms; + } + + /** + * Returns a list of comment permissions for a given comment type. + * + * @param \Drupal\comment\Entity\CommentType $type + * The comment type. + * + * @return array + * An associative array of permission names and descriptions. + */ + protected function buildPermissions(CommentType $type) { + $type_id = $type->id(); + $args = array('%type_name' => $type->label()); + + return array( + 'access comments ' . $type_id => array( + 'title' => $this->t('%type_name: View comments', $args), + ), + 'post comments ' . $type_id => array( + 'title' => $this->t('%type_name: Post comments', $args), + ), + 'skip comment approval ' . $type_id => array( + 'title' => $this->t('%type_name: Skip comment approval', $args), + ), + 'edit own comments ' . $type_id => array( + 'title' => $this->t('%type_name: Edit own comments', $args), + ), + ); + } + +} diff --git a/core/modules/comment/src/Controller/CommentController.php b/core/modules/comment/src/Controller/CommentController.php index 5f1b504..d1650ba 100644 --- a/core/modules/comment/src/Controller/CommentController.php +++ b/core/modules/comment/src/Controller/CommentController.php @@ -277,7 +277,8 @@ public function replyFormAccess(EntityInterface $entity, $field_name, $pid = NUL $account = $this->currentUser(); // Check if the user has the proper permissions. - $access = AccessResult::allowedIfHasPermission($account, 'post comments'); + $comment_type = $entity->{$field_name}->getSetting('comment_type'); + $access = AccessResult::allowedIfHasPermission($account, 'post comments ' . $comment_type); $status = $entity->{$field_name}->status; $access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN) @@ -286,7 +287,7 @@ public function replyFormAccess(EntityInterface $entity, $field_name, $pid = NUL // $pid indicates that this is a reply to a comment. if ($pid) { // Check if the user has the proper permissions. - $access = $access->andIf(AccessResult::allowedIfHasPermission($account, 'access comments')); + $access = $access->andIf(AccessResult::allowedIfHasPermission($account, 'access comments ' . $comment_type)); /// Load the parent comment. $comment = $this->entityManager()->getStorage('comment')->load($pid); diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php index d626be3..90c8ed9 100644 --- a/core/modules/comment/src/Entity/Comment.php +++ b/core/modules/comment/src/Entity/Comment.php @@ -73,7 +73,7 @@ public function preSave(EntityStorageInterface $storage) { parent::preSave($storage); if (is_null($this->get('status')->value)) { - $published = \Drupal::currentUser()->hasPermission('skip comment approval') ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED; + $published = \Drupal::currentUser()->hasPermission('skip comment approval ' . $this->bundle()) ? CommentInterface::PUBLISHED : CommentInterface::NOT_PUBLISHED; $this->setPublished($published); } if ($this->isNew()) { diff --git a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php index c7d9bba..5884e38 100644 --- a/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php +++ b/core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php @@ -161,7 +161,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { // $entity->get($field_name)->comment_count, but unpublished comments // should display if the user is an administrator. $elements['#cache']['contexts'][] = 'user.permissions'; - if ($this->currentUser->hasPermission('access comments') || $this->currentUser->hasPermission('administer comments')) { + if ($this->currentUser->hasPermission('access comments ' . $this->getFieldSetting('comment_type')) || $this->currentUser->hasPermission('administer comments')) { $output['comments'] = []; if ($entity->get($field_name)->comment_count || $this->currentUser->hasPermission('administer comments')) { @@ -190,7 +190,7 @@ public function viewElements(FieldItemListInterface $items, $langcode) { if ($status == CommentItemInterface::OPEN && $comment_settings['form_location'] == CommentItemInterface::FORM_BELOW && $this->viewMode != 'print') { // Only show the add comment form if the user has permission. $elements['#cache']['contexts'][] = 'user.roles'; - if ($this->currentUser->hasPermission('post comments')) { + if ($this->currentUser->hasPermission('post comments ' . $this->getFieldSetting('comment_type'))) { $output['comment_form'] = [ '#lazy_builder' => ['comment.lazy_builders:renderForm', [ $entity->getEntityTypeId(), diff --git a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php index 888b64b..3146afa 100644 --- a/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php +++ b/core/modules/comment/src/Plugin/Field/FieldType/CommentItem.php @@ -129,7 +129,7 @@ public function fieldSettingsForm(array $form, FormStateInterface $form_state) { COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'), COMMENT_ANONYMOUS_MUST_CONTACT => t('Anonymous posters must leave their contact information'), ), - '#access' => $anonymous_user->hasPermission('post comments'), + '#access' => $anonymous_user->hasPermission('post comments ' . $this->getSetting('comment_type')), ); $element['form_location'] = array( '#type' => 'checkbox',