diff --git a/gutenberg.php b/gutenberg.php index eda6be3fc80027..8770e9fc597e6a 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -22,6 +22,8 @@ require_once dirname( __FILE__ ) . '/lib/i18n.php'; require_once dirname( __FILE__ ) . '/lib/parser.php'; require_once dirname( __FILE__ ) . '/lib/register.php'; + require_once dirname( __FILE__ ) . '/lib/class-gutenberg-user-preferences.php'; + require_once dirname( __FILE__ ) . '/lib/api.php'; // Register server-side code for individual blocks. require_once dirname( __FILE__ ) . '/lib/blocks/latest-posts.php'; diff --git a/lib/api.php b/lib/api.php new file mode 100644 index 00000000000000..9b9470110fee88 --- /dev/null +++ b/lib/api.php @@ -0,0 +1,21 @@ + $value ) { + if ( ! self::is_valid_preference_name( $preference_name ) ) { + return false; + } + } + return true; + } + + /** + * Checks that the user has the needd permissions to store and read preferences. + * + * @return bool + */ + public static function check_permissions() { + $user_id = get_current_user_id(); + return user_can( $user_id, 'edit_posts' ); + } + + /** + * Gets all preferences for a user. + * + * @param WP_REST_Request $request The REST request. + * @return mixed Stored preference values indexed by preference name. + */ + public static function get_preferences( $request ) { + $user_id = get_current_user_id(); + $preferences = array(); + foreach ( self::$valid_preferences as $preference_name ) { + $preferences[ $preference_name ] = get_user_meta( $user_id, 'gutenberg_' . $preference_name ); + } + return $preferences; + } + + /** + * Sets preferences for a user. + * + * Expects an array of preferences to store, indexed by the preference name. + * + * @param WP_REST_Request $request The REST request. + * @return bool If the store was successful. + */ + public static function set_preferences( $request ) { + $params = $request->get_params(); + $user_id = get_current_user_id(); + + foreach ( $params['preferences'] as $preference_name => $value ) { + if ( ! self::is_valid_preference_name( $preference_name ) ) { + return false; + } + } + + foreach ( $params['preferences'] as $preference_name => $value ) { + update_user_meta( $user_id, 'gutenberg_' . $preference_name, $value ); + } + + return true; + } + + /** + * Registers preferences API routes. + * + * @return void + */ + public static function register_routes() { + register_rest_route( 'gutenberg/v1', '/user-preferences', array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => 'Gutenberg_User_Preferences::get_preferences', + 'permission_callback' => 'Gutenberg_User_Preferences::check_permissions', + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => 'Gutenberg_User_Preferences::set_preferences', + 'permission_callback' => 'Gutenberg_User_Preferences::check_permissions', + 'args' => array( + 'preferences' => array( + 'required' => true, + 'validate_callback' => 'Gutenberg_User_Preferences::validate_preferences', + ), + ), + ), + ) ); + } +} diff --git a/phpunit/class-user-preferences-api-test.php b/phpunit/class-user-preferences-api-test.php new file mode 100644 index 00000000000000..459d9f074f1747 --- /dev/null +++ b/phpunit/class-user-preferences-api-test.php @@ -0,0 +1,146 @@ +user->create( array( + 'role' => 'editor', + 'user_email' => 'editor@example.com', + ) ); + self::$user = $factory->user->create( array( + 'role' => 'subscriber', + 'user_email' => 'user@example.com', + ) ); + } + + public static function wpTearDownAfterClass() { + self::delete_user( self::$user ); + self::delete_user( self::$editor ); + } + + public function test_register_routes() { + $routes = $this->server->get_routes(); + $this->assertArrayHasKey( '/gutenberg/v1/user-preferences', $routes ); + $this->assertCount( 2, $routes['/gutenberg/v1/user-preferences'] ); + } + + public function test_get_item() { + wp_set_current_user( self::$editor ); + + $request = new WP_REST_Request( 'GET', '/gutenberg/v1/user-preferences' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 200, $response->get_status() ); + + // Each valid preference should be present. + foreach ( Gutenberg_User_Preferences::$valid_preferences as $preference ) { + $this->assertArrayHasKey( $preference, $response->data ); + } + } + + public function test_get_item_without_permission() { + wp_set_current_user( self::$user ); + + $request = new WP_REST_Request( 'GET', '/gutenberg/v1/user-preferences' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 403, $response->get_status() ); + } + + /** + * Should fail with invalid preferences + */ + function test_set_item_with_invalid_preferences() { + wp_set_current_user( self::$editor ); + + $params = array( + 'preferences' => array( + 'bad_pref_name' => 42, + ), + ); + + $request = new WP_REST_Request( 'POST', '/gutenberg/v1/user-preferences' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 'rest_invalid_param', $response->data['code'] ); + $this->assertEquals( 400, $response->get_status() ); + } + + /** + * Should set an individual preference + */ + function test_update_item() { + wp_set_current_user( self::$editor ); + + $params = array( + 'preferences' => array( + 'block_usage' => array( 'core/text' ), + ), + ); + + $request = new WP_REST_Request( 'POST', '/gutenberg/v1/user-preferences' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 200, $response->get_status() ); + + $request = new WP_REST_Request( 'GET', '/gutenberg/v1/user-preferences' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( array( 'core/text' ), $response->data['block_usage'][0] ); + + } + + /** + * Should set multiple preferences + */ + function test_update_item_multiple_preferences() { + wp_set_current_user( self::$editor ); + + $params = array( + 'preferences' => array( + 'block_usage' => array( 'core/text' ), + 'layout_config' => array( + 'things' => 'awesome', + ), + ), + ); + + $request = new WP_REST_Request( 'POST', '/gutenberg/v1/user-preferences' ); + $request->add_header( 'content-type', 'application/x-www-form-urlencoded' ); + $request->set_body_params( $params ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 200, $response->get_status() ); + + $request = new WP_REST_Request( 'GET', '/gutenberg/v1/user-preferences' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( array( 'core/text' ), $response->data['block_usage'][0] ); + $this->assertEquals( array( + 'things' => 'awesome', + ), $response->data['layout_config'][0] ); + + } + + /** API does not implement these. */ + public function test_get_items() {} + public function test_create_item() {} + public function test_delete_item() {} + public function test_prepare_item() {} + public function test_context_param() {} + public function test_get_item_schema() {} + +}