diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index dd6ca13..2a41eab 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -305,7 +305,7 @@ function comment_field_instance_delete(FieldInstanceInterface $instance) { * Implements hook_permission(). */ function comment_permission() { - return array( + $permissions = array( 'administer comments' => array( 'title' => t('Administer comments and comment settings'), ), @@ -322,6 +322,31 @@ function comment_permission() { 'title' => t('Edit own comments'), ), ); + $manager = \Drupal::service('comment.manager'); + $fields = $manager->loadFields(); + foreach ($fields as $field) { + if ($field->getFieldSetting('custom_permissions')) { + $replacements = array( + '@entity_type' => $field->entity_type, + '@field_name' => $field->name, + ); + $permissions += array( + 'access comments ' . $field->id() => array( + 'title' => t('View comments for the @field_name field on @entity_type', $replacements), + ), + 'post comments ' . $field->id() => array( + 'title' => t('Post comments for the @field_name field on @entity_type', $replacements), + ), + 'skip comment approval ' . $field->id() => array( + 'title' => t('Skip comment approval for the @field_name field on @entity_type', $replacements), + ), + 'edit own comments ' . $field->id() => array( + 'title' => t('Edit own comments for the @field_name field on @entity_type', $replacements), + ), + ); + } + } + return $permissions; } /** @@ -475,8 +500,10 @@ function comment_entity_view(EntityInterface $entity, EntityDisplay $display, $v // http://drupal.org/node/1901110 return; } - $fields = \Drupal::service('comment.manager')->getFields('node'); + $comment_manager = \Drupal::service('comment.manager'); + $fields = $comment_manager->getFields('node'); foreach ($fields as $field_name => $detail) { + $field = $comment_manager->loadField($field_name, 'node'); // Skip fields that entity does not have. if (!$entity->getPropertyDefinition($field_name)) { continue; @@ -502,7 +529,7 @@ function comment_entity_view(EntityInterface $entity, EntityDisplay $display, $v // Teaser view: display the number of comments that have been posted, // or a link to add new comments if the user has permission, the node // is open to new comments, and there currently are none. - if (user_access('access comments')) { + if ($comment_manager->checkPermission('access comments', $field, \Drupal::currentUser())) { if (!empty($entity->get($field_name)->comment_count)) { $links['comment-comments'] = array( 'title' => format_plural($entity->get($field_name)->comment_count, '1 comment', '@count comments'), @@ -529,7 +556,7 @@ function comment_entity_view(EntityInterface $entity, EntityDisplay $display, $v // Provide a link to new comment form. if ($commenting_status == COMMENT_OPEN) { $comment_form_location = $instance->getFieldSetting('form_location'); - if (user_access('post comments')) { + if ($comment_manager->checkPermission('post comments', $field, \Drupal::currentUser())) { $links['comment-add'] = array( 'title' => t('Add new comment'), 'href' => $uri['path'], @@ -560,10 +587,11 @@ function comment_entity_view(EntityInterface $entity, EntityDisplay $display, $v // indexing or constructing a search result excerpt. if ($commenting_status == COMMENT_OPEN) { $comment_form_location = $instance->getFieldSetting('form_location'); - if (user_access('post comments')) { + if ($comment_manager->checkPermission('post comments', $field, \Drupal::currentUser())) { // 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 == COMMENT_FORM_SEPARATE_PAGE || (!empty($entity->get($field_name)->comment_count) && user_access('access comments'))) { + if ($comment_form_location == COMMENT_FORM_SEPARATE_PAGE || (!empty($entity->get($field_name)->comment_count) && + $comment_manager->checkPermission('access comments', $field, \Drupal::currentUser()) { $links['comment-add'] = array( 'title' => t('Add new comment'), 'attributes' => array('title' => t('Share your thoughts and opinions related to this posting.')), @@ -1134,7 +1162,8 @@ function comment_update_index() { * results. */ function comment_node_search_result(EntityInterface $node) { - $comment_fields = \Drupal::service('comment.manager')->getFields('node'); + $comment_manager = \Drupal::service('comment.manager'); + $comment_fields = $comment_manager->getFields('node'); $comments = 0; $open = FALSE; foreach ($comment_fields as $field_name => $info) { @@ -1142,9 +1171,10 @@ function comment_node_search_result(EntityInterface $node) { if (!$node->getPropertyDefinition($field_name)) { continue; } + $field = $comment_manager->loadField($field_name, 'node'); // Do not make a string if comments are hidden. $status = $node->get($field_name)->status; - if (\Drupal::currentUser()->hasPermission('access comments') && $status != COMMENT_HIDDEN) { + if ($comment_manager->checkPermission('access comments', $field, \Drupal::currentUser()) && $status != COMMENT_HIDDEN) { if ($status == COMMENT_OPEN) { // At least one comment field is open. $open = TRUE; @@ -1735,6 +1765,7 @@ function comment_ranking() { */ function comment_file_download_access($field, EntityInterface $entity, FileInterface $file) { if ($entity->entityType() == 'comment') { + // @todo - How to evaluate custom permissions here? if (user_access('access comments') && $entity->status->value == COMMENT_PUBLISHED || user_access('administer comments')) { $commented_entity = entity_load($entity->entity_type->value, $entity->entity_id->value); // Check access to parent entity. diff --git a/core/modules/comment/lib/Drupal/comment/CommentManager.php b/core/modules/comment/lib/Drupal/comment/CommentManager.php index 5454a1b..12a12da 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentManager.php +++ b/core/modules/comment/lib/Drupal/comment/CommentManager.php @@ -8,8 +8,10 @@ namespace Drupal\comment; use Drupal\Component\Utility\String; +use Drupal\field\Entity\Field; use Drupal\field\FieldInfo; use Drupal\Core\Entity\EntityManager; +use Drupal\Core\Session\AccountInterface; /** * Comment manager contains common functions to manage comment fields. @@ -199,4 +201,39 @@ public function getFieldUIPageTitle($field_name) { return String::checkPlain($sample_instance->label); } + /** + * {@inheritdoc} + */ + public function checkPermission($permission, Field $field, AccountInterface $account) { + if ($field->getFieldSetting('custom_permissions')) { + $permission .= ' ' . $field->id(); + } + return $account->hasPermission($permission); + } + + /** + * {@inheritdoc} + */ + public function loadField($field_name, $entity_type) { + // We don't bother with static caching as it is present in the storage + // controller. + return $this->entityManager->getStorageController('field_entity')->loadMultiple("$entity_type.$field_name"); + } + + /** + * {@inheritdoc} + */ + public function loadFields() { + $field_ids = array(); + foreach ($this->getAllFields() as $entity_type => $fields) { + foreach (array_keys($fields) as $field_name) { + $field_ids [] = "$entity_type.$field_name"; + } + } + // We don't bother with static caching as it is present in the storage + // controller. + $fields = $this->entityManager->getStorageController('field_entity')->loadMultiple($field_ids); + return $fields; + } + } diff --git a/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php b/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php index b4c16e3..7b4fe07 100644 --- a/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php +++ b/core/modules/comment/lib/Drupal/comment/CommentManagerInterface.php @@ -7,6 +7,9 @@ namespace Drupal\comment; +use Drupal\Core\Session\AccountInterface; +use Drupal\field\Entity\Field; + /** * Comment manager contains common functions to manage comment fields. */ @@ -46,6 +49,25 @@ public function getFields($entity_type = NULL); public function getAllFields(); /** + * Utility function to return field entities. + * + * @return \Drupal\field\Entity\Field[] + */ + public function loadFields(); + + /** + * Utility function to return a field entity. + * + * @param string $field_name + * The comment field to load. + * @param string $entity_type + * The entity type the field is attached to. + * + * @return \Drupal\field\Entity\Field + */ + public function loadField($field_name, $entity_type); + + /** * Utility method to add the default comment field to an entity. * * Attaches a comment field named 'comment' to the given entity type and @@ -84,4 +106,21 @@ public function addBodyField($entity_type, $field_name); */ public function getFieldUIPageTitle($field_name); + /** + * Utility function to check permission for a given comment field. + * + * Comment permissions depend on whether the field has been configured for + * custom permissions or not. If a field requires custom permissions then this + * utility checks if the custom permission is granted. If the field does not + * require custom permissions then the generic ones are used instead. + * + * @param string $permission + * The permission to check for, eg. 'post comments'. + * @param \Drupal\field\Entity\Field $field + * The field for which the comment permission is being checked. + * @param \Drupal\Core\Session\AccountInterface $account + * The user account being tested. + */ + public function checkPermission($permission, Field $field, AccountInterface $account); + } diff --git a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php index 1c2ffa9..7318d27 100644 --- a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php +++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php @@ -241,13 +241,14 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_ if (empty($fields[$field_name]) || !($entity = $this->entityManager()->getStorageController($entity_type)->load($entity_id))) { throw new NotFoundHttpException(); } + $field = $this->entityManager()->getStorageController('field_entity')->load("$entity_type.$field_name"); $account = $this->currentUser(); $uri = $entity->uri(); $build = array(); // Check if the user has the proper permissions. - if (!$account->hasPermission('post comments')) { + if (!$this->commentManager->checkPermission('post comments', $field, $account)) { drupal_set_message($this->t('You are not authorized to post comments.'), 'error'); return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); } @@ -263,7 +264,7 @@ public function getReplyForm(Request $request, $entity_type, $entity_id, $field_ // $pid indicates that this is a reply to a comment. if ($pid) { // Check if the user has the proper permissions. - if (!$account->hasPermission('access comments')) { + if (!$this->commentManager->checkPermission('access comments', $field, $account)) { drupal_set_message($this->t('You are not authorized to view comments.'), 'error'); return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); } diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/field/field_type/CommentItem.php b/core/modules/comment/lib/Drupal/comment/Plugin/field/field_type/CommentItem.php index 0ffcae8..75a0ff4 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/field/field_type/CommentItem.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/field/field_type/CommentItem.php @@ -25,6 +25,9 @@ * "subject" = 1, * "preview" = DRUPAL_OPTIONAL, * }, + * settings = { + * "custom_permissions" = 0, + * }, * default_widget = "comment_default", * default_formatter = "comment_default" * ) @@ -212,4 +215,17 @@ public static function processSettingsElement($element) { return $element; } + /** + * {@inheritdoc} + */ + public function settingsForm(array $form, array &$form_state, $has_data) { + $element = array(); + $element['custom_permissions'] = array( + '#title' => t('Use custom permissions'), + '#description' => t('Create custom permissions for this comment field'), + '#default_value' => $this->getFieldSetting('custom_permissions'), + ); + return $element; + } + }