Loading core/modules/comment/comment.routing.yml +1 −1 Changes for core/modules/comment/comment.routing.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ comment.reply: _title: 'Add new comment' pid: ~ requirements: _access: 'TRUE' _custom_access: '\Drupal\comment\Controller\CommentController::replyFormAccess' options: parameters: entity: Loading core/modules/comment/src/Controller/CommentController.php +48 −36 Changes for core/modules/comment/src/Controller/CommentController.php: 48 added lines, 36 removed lines. Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ use Drupal\comment\CommentInterface; use Drupal\comment\CommentManagerInterface; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; Loading Loading @@ -185,9 +186,6 @@ public function redirectNode(EntityInterface $node) { * There are several cases that have to be handled, including: * - replies to comments * - replies to entities * - attempts to reply to entities that can no longer accept comments * - respecting access permissions ('access comments', 'post comments', * etc.) * * @param \Symfony\Component\HttpFoundation\Request $request * The current request object. Loading @@ -201,57 +199,24 @@ public function redirectNode(EntityInterface $node) { * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * @return array|\Symfony\Component\HttpFoundation\RedirectResponse * One of the following: * An associative array containing: * - An array for rendering the entity or parent comment. * - comment_entity: If the comment is a reply to the entity. * - comment_parent: If the comment is a reply to another comment. * - comment_form: The comment form as a renderable array. * - A redirect response to current node: * - If user is not authorized to post comments. * - If parent comment doesn't belong to current entity. * - If user is not authorized to view comments. * - If current entity comments are disable. */ public function getReplyForm(Request $request, EntityInterface $entity, $field_name, $pid = NULL) { // Check if entity and field exists. $fields = $this->commentManager->getFields($entity->getEntityTypeId()); if (empty($fields[$field_name])) { throw new NotFoundHttpException(); } $account = $this->currentUser(); $uri = $entity->urlInfo()->setAbsolute(); $build = array(); // Check if the user has the proper permissions. if (!$account->hasPermission('post comments')) { drupal_set_message($this->t('You are not authorized to post comments.'), 'error'); return new RedirectResponse($uri->toString()); } // The user is not just previewing a comment. if ($request->request->get('op') != $this->t('Preview')) { $status = $entity->{$field_name}->status; if ($status != CommentItemInterface::OPEN) { drupal_set_message($this->t("This discussion is closed: you can't post new comments."), 'error'); return new RedirectResponse($uri->toString()); } // $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')) { drupal_set_message($this->t('You are not authorized to view comments.'), 'error'); return new RedirectResponse($uri->toString()); } // Load the parent comment. $comment = $this->entityManager()->getStorage('comment')->load($pid); // Check if the parent comment is published and belongs to the entity. if (!$comment->isPublished() || ($comment->getCommentedEntityId() != $entity->id())) { drupal_set_message($this->t('The comment you are replying to does not exist.'), 'error'); return new RedirectResponse($uri->toString()); } // Display the parent comment. $build['comment_parent'] = $this->entityManager()->getViewBuilder('comment')->view($comment); } Loading Loading @@ -283,6 +248,53 @@ public function getReplyForm(Request $request, EntityInterface $entity, $field_n return $build; } /** * Access check for the reply form. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity this comment belongs to. * @param string $field_name * The field_name to which the comment belongs. * @param int $pid * (optional) Some comments are replies to other comments. In those cases, * $pid is the parent comment's comment ID. Defaults to NULL. * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * @return \Drupal\Core\Access\AccessResultInterface * An access result */ public function replyFormAccess(EntityInterface $entity, $field_name, $pid = NULL) { // Check if entity and field exists. $fields = $this->commentManager->getFields($entity->getEntityTypeId()); if (empty($fields[$field_name])) { throw new NotFoundHttpException(); } $account = $this->currentUser(); // Check if the user has the proper permissions. $access = AccessResult::allowedIfHasPermission($account, 'post comments'); $status = $entity->{$field_name}->status; $access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN) ->cacheUntilEntityChanges($entity)); // $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')); /// Load the parent comment. $comment = $this->entityManager()->getStorage('comment')->load($pid); // Check if the parent comment is published and belongs to the entity. $access = $access->andIf(AccessResult::allowedIf($comment && $comment->isPublished() && $comment->getCommentedEntityId() == $entity->id())); if ($comment) { $access->cacheUntilEntityChanges($comment); } } return $access; } /** * Returns a set of nodes' last read timestamps. * Loading core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php +1 −1 Changes for core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ public function viewElements(FieldItemListInterface $items) { // Unpublished comments are not included in // $entity->get($field_name)->comment_count, but unpublished comments // should display if the user is an administrator. $elements['#cache']['contexts'][] = 'user.roles'; $elements['#cache']['contexts'][] = 'user.permissions'; if ($this->currentUser->hasPermission('access comments') || $this->currentUser->hasPermission('administer comments')) { // This is a listing of Comment entities, so associate its list cache // tag for correct invalidation. Loading core/modules/comment/src/Tests/CommentAnonymousTest.php +7 −6 Changes for core/modules/comment/src/Tests/CommentAnonymousTest.php: 7 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -122,6 +122,10 @@ function testAnonymous() { $this->assertNoRaw('comments[' . $anonymous_comment3->id() . ']', 'Comment was deleted.'); $this->drupalLogout(); // Comment 3 was deleted. $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment3->id()); $this->assertResponse(403); // Reset. user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'access comments' => FALSE, Loading @@ -138,9 +142,7 @@ function testAnonymous() { // Attempt to view node-comment form while disallowed. $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('You are not authorized to post comments', 'Error attempting to post comment.'); $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.'); $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field not found.'); $this->assertResponse(403); user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'access comments' => TRUE, Loading @@ -162,8 +164,7 @@ function testAnonymous() { $this->assertFieldByName('subject[0][value]', '', 'Subject field found.'); $this->assertFieldByName('comment_body[0][value]', '', 'Comment field found.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment3->id()); $this->assertText('You are not authorized to view comments', 'Error attempting to post reply.'); $this->assertNoText($author_name, 'Comment not displayed.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment2->id()); $this->assertResponse(403); } } core/modules/comment/src/Tests/CommentInterfaceTest.php +3 −3 Changes for core/modules/comment/src/Tests/CommentInterfaceTest.php: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -155,20 +155,20 @@ public function testCommentInterface() { $reply_loaded->setPublished(FALSE); $reply_loaded->save(); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $reply_loaded->id()); $this->assertText(t('The comment you are replying to does not exist.'), 'Replying to an unpublished comment'); $this->assertResponse(403); // Attempt to post to node with comments disabled. $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => array(array('status' => CommentItemInterface::HIDDEN)))); $this->assertTrue($this->node, 'Article node created.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('This discussion is closed', 'Posting to node with comments disabled'); $this->assertResponse(403); $this->assertNoField('edit-comment', 'Comment body field found.'); // Attempt to post to node with read-only comments. $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => array(array('status' => CommentItemInterface::CLOSED)))); $this->assertTrue($this->node, 'Article node created.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('This discussion is closed', 'Posting to node with comments read-only'); $this->assertResponse(403); $this->assertNoField('edit-comment', 'Comment body field found.'); // Attempt to post to node with comments enabled (check field names etc). Loading Loading
core/modules/comment/comment.routing.yml +1 −1 Changes for core/modules/comment/comment.routing.yml: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -57,7 +57,7 @@ comment.reply: _title: 'Add new comment' pid: ~ requirements: _access: 'TRUE' _custom_access: '\Drupal\comment\Controller\CommentController::replyFormAccess' options: parameters: entity: Loading
core/modules/comment/src/Controller/CommentController.php +48 −36 Changes for core/modules/comment/src/Controller/CommentController.php: 48 added lines, 36 removed lines. Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ use Drupal\comment\CommentInterface; use Drupal\comment\CommentManagerInterface; use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityManagerInterface; Loading Loading @@ -185,9 +186,6 @@ public function redirectNode(EntityInterface $node) { * There are several cases that have to be handled, including: * - replies to comments * - replies to entities * - attempts to reply to entities that can no longer accept comments * - respecting access permissions ('access comments', 'post comments', * etc.) * * @param \Symfony\Component\HttpFoundation\Request $request * The current request object. Loading @@ -201,57 +199,24 @@ public function redirectNode(EntityInterface $node) { * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * @return array|\Symfony\Component\HttpFoundation\RedirectResponse * One of the following: * An associative array containing: * - An array for rendering the entity or parent comment. * - comment_entity: If the comment is a reply to the entity. * - comment_parent: If the comment is a reply to another comment. * - comment_form: The comment form as a renderable array. * - A redirect response to current node: * - If user is not authorized to post comments. * - If parent comment doesn't belong to current entity. * - If user is not authorized to view comments. * - If current entity comments are disable. */ public function getReplyForm(Request $request, EntityInterface $entity, $field_name, $pid = NULL) { // Check if entity and field exists. $fields = $this->commentManager->getFields($entity->getEntityTypeId()); if (empty($fields[$field_name])) { throw new NotFoundHttpException(); } $account = $this->currentUser(); $uri = $entity->urlInfo()->setAbsolute(); $build = array(); // Check if the user has the proper permissions. if (!$account->hasPermission('post comments')) { drupal_set_message($this->t('You are not authorized to post comments.'), 'error'); return new RedirectResponse($uri->toString()); } // The user is not just previewing a comment. if ($request->request->get('op') != $this->t('Preview')) { $status = $entity->{$field_name}->status; if ($status != CommentItemInterface::OPEN) { drupal_set_message($this->t("This discussion is closed: you can't post new comments."), 'error'); return new RedirectResponse($uri->toString()); } // $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')) { drupal_set_message($this->t('You are not authorized to view comments.'), 'error'); return new RedirectResponse($uri->toString()); } // Load the parent comment. $comment = $this->entityManager()->getStorage('comment')->load($pid); // Check if the parent comment is published and belongs to the entity. if (!$comment->isPublished() || ($comment->getCommentedEntityId() != $entity->id())) { drupal_set_message($this->t('The comment you are replying to does not exist.'), 'error'); return new RedirectResponse($uri->toString()); } // Display the parent comment. $build['comment_parent'] = $this->entityManager()->getViewBuilder('comment')->view($comment); } Loading Loading @@ -283,6 +248,53 @@ public function getReplyForm(Request $request, EntityInterface $entity, $field_n return $build; } /** * Access check for the reply form. * * @param \Drupal\Core\Entity\EntityInterface $entity * The entity this comment belongs to. * @param string $field_name * The field_name to which the comment belongs. * @param int $pid * (optional) Some comments are replies to other comments. In those cases, * $pid is the parent comment's comment ID. Defaults to NULL. * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException * @return \Drupal\Core\Access\AccessResultInterface * An access result */ public function replyFormAccess(EntityInterface $entity, $field_name, $pid = NULL) { // Check if entity and field exists. $fields = $this->commentManager->getFields($entity->getEntityTypeId()); if (empty($fields[$field_name])) { throw new NotFoundHttpException(); } $account = $this->currentUser(); // Check if the user has the proper permissions. $access = AccessResult::allowedIfHasPermission($account, 'post comments'); $status = $entity->{$field_name}->status; $access = $access->andIf(AccessResult::allowedIf($status == CommentItemInterface::OPEN) ->cacheUntilEntityChanges($entity)); // $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')); /// Load the parent comment. $comment = $this->entityManager()->getStorage('comment')->load($pid); // Check if the parent comment is published and belongs to the entity. $access = $access->andIf(AccessResult::allowedIf($comment && $comment->isPublished() && $comment->getCommentedEntityId() == $entity->id())); if ($comment) { $access->cacheUntilEntityChanges($comment); } } return $access; } /** * Returns a set of nodes' last read timestamps. * Loading
core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php +1 −1 Changes for core/modules/comment/src/Plugin/Field/FieldFormatter/CommentDefaultFormatter.php: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -157,7 +157,7 @@ public function viewElements(FieldItemListInterface $items) { // Unpublished comments are not included in // $entity->get($field_name)->comment_count, but unpublished comments // should display if the user is an administrator. $elements['#cache']['contexts'][] = 'user.roles'; $elements['#cache']['contexts'][] = 'user.permissions'; if ($this->currentUser->hasPermission('access comments') || $this->currentUser->hasPermission('administer comments')) { // This is a listing of Comment entities, so associate its list cache // tag for correct invalidation. Loading
core/modules/comment/src/Tests/CommentAnonymousTest.php +7 −6 Changes for core/modules/comment/src/Tests/CommentAnonymousTest.php: 7 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -122,6 +122,10 @@ function testAnonymous() { $this->assertNoRaw('comments[' . $anonymous_comment3->id() . ']', 'Comment was deleted.'); $this->drupalLogout(); // Comment 3 was deleted. $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment3->id()); $this->assertResponse(403); // Reset. user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'access comments' => FALSE, Loading @@ -138,9 +142,7 @@ function testAnonymous() { // Attempt to view node-comment form while disallowed. $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('You are not authorized to post comments', 'Error attempting to post comment.'); $this->assertNoFieldByName('subject[0][value]', '', 'Subject field not found.'); $this->assertNoFieldByName('comment_body[0][value]', '', 'Comment field not found.'); $this->assertResponse(403); user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array( 'access comments' => TRUE, Loading @@ -162,8 +164,7 @@ function testAnonymous() { $this->assertFieldByName('subject[0][value]', '', 'Subject field found.'); $this->assertFieldByName('comment_body[0][value]', '', 'Comment field found.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment3->id()); $this->assertText('You are not authorized to view comments', 'Error attempting to post reply.'); $this->assertNoText($author_name, 'Comment not displayed.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $anonymous_comment2->id()); $this->assertResponse(403); } }
core/modules/comment/src/Tests/CommentInterfaceTest.php +3 −3 Changes for core/modules/comment/src/Tests/CommentInterfaceTest.php: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -155,20 +155,20 @@ public function testCommentInterface() { $reply_loaded->setPublished(FALSE); $reply_loaded->save(); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment/' . $reply_loaded->id()); $this->assertText(t('The comment you are replying to does not exist.'), 'Replying to an unpublished comment'); $this->assertResponse(403); // Attempt to post to node with comments disabled. $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => array(array('status' => CommentItemInterface::HIDDEN)))); $this->assertTrue($this->node, 'Article node created.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('This discussion is closed', 'Posting to node with comments disabled'); $this->assertResponse(403); $this->assertNoField('edit-comment', 'Comment body field found.'); // Attempt to post to node with read-only comments. $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => array(array('status' => CommentItemInterface::CLOSED)))); $this->assertTrue($this->node, 'Article node created.'); $this->drupalGet('comment/reply/node/' . $this->node->id() . '/comment'); $this->assertText('This discussion is closed', 'Posting to node with comments read-only'); $this->assertResponse(403); $this->assertNoField('edit-comment', 'Comment body field found.'); // Attempt to post to node with comments enabled (check field names etc). Loading