Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,15 @@ public function register_routes() {
* @return true|WP_Error True if the request has read access, error object otherwise.
*/
public function get_items_permissions_check( $request ) {
$is_note = 'note' === $request['type'];
$is_edit_context = 'edit' === $request['context'];
$is_note = 'note' === $request['type'];
$is_edit_context = 'edit' === $request['context'];
$protected_params = array( 'author', 'author_exclude', 'author_email', 'type', 'status' );
$forbidden_params = array();

if ( ! empty( $request['post'] ) ) {
foreach ( (array) $request['post'] as $post_id ) {
$post = get_post( $post_id );

if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
return new WP_Error(
'rest_comment_not_supported_post_type',
__( 'Sorry, this post type does not support notes.' ),
array( 'status' => 403 )
);
}

if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post, $request ) ) {
return new WP_Error(
'rest_cannot_read_post',
Expand All @@ -151,6 +145,36 @@ public function get_items_permissions_check( $request ) {
array( 'status' => rest_authorization_required_code() )
);
}

if ( $post && $is_note && ! $this->check_post_type_supports_notes( $post->post_type ) ) {
if ( current_user_can( 'edit_post', $post->ID ) ) {
return new WP_Error(
'rest_comment_not_supported_post_type',
__( 'Sorry, this post type does not support notes.' ),
array( 'status' => 403 )
);
}

foreach ( $protected_params as $param ) {
if ( 'status' === $param ) {
if ( 'approve' !== $request[ $param ] ) {
$forbidden_params[] = $param;
}
} elseif ( 'type' === $param ) {
if ( 'comment' !== $request[ $param ] ) {
$forbidden_params[] = $param;
}
} elseif ( ! empty( $request[ $param ] ) ) {
$forbidden_params[] = $param;
}
}
return new WP_Error(
'rest_forbidden_param',
/* translators: %s: List of forbidden parameters. */
sprintf( __( 'Query parameter not permitted: %s' ), implode( ', ', $forbidden_params ) ),
array( 'status' => rest_authorization_required_code() )
);
}
}
}

Expand All @@ -174,9 +198,6 @@ public function get_items_permissions_check( $request ) {
}

if ( ! current_user_can( 'edit_posts' ) ) {
$protected_params = array( 'author', 'author_exclude', 'author_email', 'type', 'status' );
$forbidden_params = array();

foreach ( $protected_params as $param ) {
if ( 'status' === $param ) {
if ( 'approve' !== $request[ $param ] ) {
Expand Down Expand Up @@ -1890,7 +1911,7 @@ protected function check_read_post_permission( $post, $request ) {
* @return bool Whether the comment can be read.
*/
protected function check_read_permission( $comment, $request ) {
if ( ! empty( $comment->comment_post_ID ) ) {
if ( 'note' !== $comment->comment_type && ! empty( $comment->comment_post_ID ) ) {
$post = get_post( $comment->comment_post_ID );
if ( $post ) {
if ( $this->check_read_post_permission( $post, $request ) && 1 === (int) $comment->comment_approved ) {
Expand Down
114 changes: 114 additions & 0 deletions tests/phpunit/tests/rest-api/rest-comments-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -4133,4 +4133,118 @@ public function test_get_note_with_children_link() {
$this->assertStringContainsString( 'status=all', $children[0]['href'] );
$this->assertStringContainsString( 'type=note', $children[0]['href'] );
}

/**
* Test retrieving comments by type as authenticated user.
*
* @dataProvider data_comment_type_provider
* @ticket 44157
*
* @param string $comment_type The comment type to test.
* @param int $count The number of comments to create.
*/
public function test_get_items_type_arg_authenticated( $comment_type, $count ) {
wp_set_current_user( self::$admin_id );

$args = array(
'comment_approved' => 1,
'comment_post_ID' => self::$post_id,
'user_id' => self::$author_id,
'comment_type' => $comment_type,
);

// Create comments of the specified type.
for ( $i = 0; $i < $count; $i++ ) {
self::factory()->comment->create( $args );
}

$request = new WP_REST_Request( 'GET', '/wp/v2/comments' );
$request->set_param( 'type', $comment_type );
$request->set_param( 'per_page', self::$per_page );

$response = rest_get_server()->dispatch( $request );
$this->assertSame( 200, $response->get_status(), 'Comments endpoint is expected to return a 200 status' );

$comments = $response->get_data();
$expected_count = 'comment' === $comment_type ? $count + self::$total_comments : $count;
$this->assertCount( $expected_count, $comments, "comment type '{$comment_type}' is expect to have {$expected_count} comments" );

// Next, test getting the individual comments.
foreach ( $comments as $comment ) {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', $comment['id'] ) );
$response = rest_get_server()->dispatch( $request );

$this->assertSame( 200, $response->get_status(), 'Individual comment endpoint is expected to return a 200 status' );
$data = $response->get_data();
$this->assertSame( $comment_type, $data['type'], "Individual comment is expected to have type '{$comment_type}'" );
}
}

/**
* Test retrieving comments by type as unauthenticated user.
*
* @dataProvider data_comment_type_provider
* @ticket 44157
*
* @param string $comment_type The comment type to test.
* @param int $count The number of comments to create.
*/
public function test_get_items_type_arg_unauthenticated( $comment_type, $count ) {
// First, create comments as admin.
wp_set_current_user( self::$admin_id );

$args = array(
'comment_approved' => 1,
'comment_post_ID' => self::$post_id,
'user_id' => self::$author_id,
'comment_type' => $comment_type,
);

$comments = array();

for ( $i = 0; $i < $count; $i++ ) {
$comments[] = self::factory()->comment->create( $args );
}

// Log out and test as unauthenticated user.
wp_logout();

$request = new WP_REST_Request( 'GET', '/wp/v2/comments' );
$request->set_param( 'type', $comment_type );
$request->set_param( 'per_page', self::$per_page );

$response = rest_get_server()->dispatch( $request );

// Only comments can be retrieved from the /comments (multiple) endpoint when unauthenticated.
$expected_status = 'comment' === $comment_type ? 200 : 401;
$this->assertSame( $expected_status, $response->get_status(), 'Comments endpoint did not return the expected status' );
if ( 'comment' !== $comment_type ) {
$this->assertErrorResponse( 'rest_forbidden_param', $response, 401, 'Comments endpoint did not return the expected error response for forbidden parameters' );
}

// Individual comments.
foreach ( $comments as $comment ) {
$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/comments/%d', $comment ) );
$response = rest_get_server()->dispatch( $request );

// Individual comments using the /comments/<id> endpoint can be retrieved by
// unauthenticated users - except for the 'note' type which is restricted.
// See https://core.trac.wordpress.org/ticket/44157.
$this->assertSame( 'note' === $comment_type ? 401 : 200, $response->get_status(), 'Individual comment endpoint did not return the expected status' );
}
}

/**
* Data provider for comment type tests.
*
* @return array[] Data provider.
*/
public function data_comment_type_provider() {
return array(
'comment type' => array( 'comment', 5 ),
'annotation type' => array( 'annotation', 5 ),
'discussion type' => array( 'discussion', 9 ),
'note type' => array( 'note', 3 ),
);
}
}
Loading