From b6f3584dbe666b4a8e7a2a7ab51707fb7f90fab0 Mon Sep 17 00:00:00 2001 From: Daniel Bachhuber Date: Mon, 7 May 2018 15:54:11 -0700 Subject: [PATCH] Query for all authors with an unbounded `per_page=-1` request --- core-data/resolvers.js | 2 +- lib/rest-api.php | 32 +++++++++++++++++------ phpunit/class-gutenberg-rest-api-test.php | 18 +++++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/core-data/resolvers.js b/core-data/resolvers.js index 071e4ce951846..39c2a5abb9e9a 100644 --- a/core-data/resolvers.js +++ b/core-data/resolvers.js @@ -29,7 +29,7 @@ export async function* getCategories() { * Requests authors from the REST API. */ export async function* getAuthors() { - const users = await apiRequest( { path: '/wp/v2/users/?who=authors' } ); + const users = await apiRequest( { path: '/wp/v2/users/?who=authors&per_page=-1' } ); yield receiveUserQuery( 'authors', users ); } diff --git a/lib/rest-api.php b/lib/rest-api.php index d7f1f5b3ef0d8..76aaa093e8328 100644 --- a/lib/rest-api.php +++ b/lib/rest-api.php @@ -427,16 +427,24 @@ function gutenberg_ensure_wp_json_has_theme_supports( $response ) { */ function gutenberg_handle_early_callback_checks( $response, $handler, $request ) { if ( '/wp/v2/users' === $request->get_route() ) { - if ( ! empty( $request['who'] ) && 'authors' === $request['who'] ) { - $can_view = false; - $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); - foreach ( $types as $type ) { - if ( post_type_supports( $type->name, 'author' ) - && current_user_can( $type->cap->edit_posts ) ) { - $can_view = true; + $can_view_authors = false; + $can_unbounded_query = false; + $types = get_post_types( array( 'show_in_rest' => true ), 'objects' ); + foreach ( $types as $type ) { + if ( current_user_can( $type->cap->edit_posts ) ) { + $can_unbounded_query = true; + if ( post_type_supports( $type->name, 'author' ) ) { + $can_view_authors = true; } } - if ( ! $can_view ) { + } + if ( $request['per_page'] < 0 ) { + if ( ! $can_unbounded_query ) { + return new WP_Error( 'rest_forbidden_per_page', __( 'Sorry, you are not allowed make unbounded queries.', 'gutenberg' ), array( 'status' => rest_authorization_required_code() ) ); + } + } + if ( ! empty( $request['who'] ) && 'authors' === $request['who'] ) { + if ( ! $can_view_authors ) { return new WP_Error( 'rest_forbidden_who', __( 'Sorry, you are not allowed to query users by this parameter.', 'gutenberg' ), array( 'status' => rest_authorization_required_code() ) ); } } @@ -449,11 +457,19 @@ function gutenberg_handle_early_callback_checks( $response, $handler, $request ) * Include additional query parameters on the user query endpoint. * * @see https://core.trac.wordpress.org/ticket/42202 + * @see https://core.trac.wordpress.org/ticket/43998 * * @param array $query_params JSON Schema-formatted collection parameters. * @return array */ function gutenberg_filter_user_collection_parameters( $query_params ) { + if ( isset( $query_params['per_page'] ) ) { + // Change from '1' to '-1', which means unlimited. + $query_params['per_page']['minimum'] = -1; + // Default sanitize callback is 'absint', which won't work in our case. + $query_params['per_page']['sanitize_callback'] = 'rest_sanitize_request_arg'; + } + // Support for 'who' query param. $query_params['who'] = array( 'description' => __( 'Limit result set to users who are considered authors.', 'gutenberg' ), 'type' => 'string', diff --git a/phpunit/class-gutenberg-rest-api-test.php b/phpunit/class-gutenberg-rest-api-test.php index b53a9c496c71f..2d6f142702e58 100644 --- a/phpunit/class-gutenberg-rest-api-test.php +++ b/phpunit/class-gutenberg-rest-api-test.php @@ -198,4 +198,22 @@ public function test_get_items_who_unauthorized_query() { $data = $response->get_data(); $this->assertEquals( 'rest_forbidden_who', $data['code'] ); } + + public function test_get_items_unbounded_per_page() { + wp_set_current_user( $this->author ); + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'per_page', '-1' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + } + + public function test_get_items_unbounded_per_page_unauthorized() { + wp_set_current_user( $this->subscriber ); + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'per_page', '-1' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 403, $response->get_status() ); + $data = $response->get_data(); + $this->assertEquals( 'rest_forbidden_per_page', $data['code'] ); + } }