diff --git a/src/wp-includes/user.php b/src/wp-includes/user.php index 064f5144f3..eb8f0a13aa 100644 --- a/src/wp-includes/user.php +++ b/src/wp-includes/user.php @@ -3330,13 +3330,16 @@ function wp_create_user_request( $email_address = '', $action_name = '', $reques 'post_type' => 'user_request', 'post_name__in' => array( $action_name ), // Action name stored in post_name column. 'title' => $email_address, // Email address stored in post_title column. - 'post_status' => 'any', + 'post_status' => array( + 'request-pending', + 'request-confirmed', + ), 'fields' => 'ids', ) ); if ( $requests_query->found_posts ) { - return new WP_Error( 'duplicate_request', __( 'A request for this email address already exists.' ) ); + return new WP_Error( 'duplicate_request', __( 'An incomplete request for this email address already exists.' ) ); } $request_id = wp_insert_post( diff --git a/tests/phpunit/tests/privacy/wpCreateUserRequest.php b/tests/phpunit/tests/privacy/wpCreateUserRequest.php new file mode 100755 index 0000000000..17a20a587e --- /dev/null +++ b/tests/phpunit/tests/privacy/wpCreateUserRequest.php @@ -0,0 +1,298 @@ +user->create( + array( + 'user_email' => self::$registered_user_email, + ) + ); + + self::$request_id = $factory->post->create( + array( + 'post_type' => 'user_request', + 'post_author' => self::$user_id, + 'post_name' => 'export_personal_data', + 'post_status' => 'request-pending', + 'post_title' => self::$registered_user_email, + ) + ); + } + + /** + * Ensure a WP_Error is returned when an invalid email is passed. + * + * @ticket 44707 + */ + public function test_invalid_email() { + $actual = wp_create_user_request( 'not-a-valid-email', 'export_personal_data' ); + + $this->assertWPError( $actual ); + $this->assertSame( 'invalid_email', $actual->get_error_code() ); + } + + /** + * Ensure a WP_Error is returned when an invalid action is passed. + * + * @ticket 44707 + */ + public function test_invalid_action() { + $actual = wp_create_user_request( self::$registered_user_email, false ); + + $this->assertWPError( $actual ); + $this->assertSame( 'invalid_action', $actual->get_error_code() ); + } + + /** + * When there are incomplete requests for a registered user, a WP_Error should be returned. + * + * @ticket 44707 + */ + public function test_failure_due_to_incomplete_registered_user() { + // Second request (duplicated). + $actual = wp_create_user_request( self::$registered_user_email, 'export_personal_data' ); + + $this->assertWPError( $actual ); + $this->assertSame( 'duplicate_request', $actual->get_error_code() ); + } + + /** + * When there are incomplete requests for an non-registered user, a WP_Error should be returned. + * + * @ticket 44707 + */ + public function test_failure_due_to_incomplete_unregistered_user() { + // Update first request. + wp_update_post( + array( + 'ID' => self::$request_id, + 'post_author' => 0, + 'post_title' => self::$non_registered_user_email, + ) + ); + + // Second request (duplicated). + $actual = wp_create_user_request( self::$non_registered_user_email, 'export_personal_data' ); + + $this->assertWPError( $actual ); + $this->assertSame( 'duplicate_request', $actual->get_error_code() ); + } + + /** + * Ensure emails are properly sanitized. + * + * @ticket 44707 + */ + public function test_sanitized_email() { + $actual = wp_create_user_request( 'some(emailassertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( 'export_personal_data', $post->post_name ); + $this->assertSame( 'someemailwithinvalidcharacters@local.test', $post->post_title ); + } + + /** + * Ensure action names are properly sanitized. + * + * @ticket 44707 + */ + public function test_sanitized_action_name() { + $actual = wp_create_user_request( self::$non_registered_user_email, 'some[custom*action\name' ); + + $this->assertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( 'somecustomactionname', $post->post_name ); + $this->assertSame( self::$non_registered_user_email, $post->post_title ); + } + + /** + * Test a user request is created successfully for a registered user. + * + * @ticket 44707 + */ + public function test_create_request_registered_user() { + wp_delete_post( self::$request_id, true ); + + $test_data = array( + 'test-data' => 'test value here', + 'test index' => 'more privacy data', + ); + + $actual = wp_create_user_request( self::$registered_user_email, 'export_personal_data', $test_data ); + + $this->assertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( self::$user_id, (int) $post->post_author ); + $this->assertSame( 'export_personal_data', $post->post_name ); + $this->assertSame( self::$registered_user_email, $post->post_title ); + $this->assertSame( 'request-pending', $post->post_status ); + $this->assertSame( 'user_request', $post->post_type ); + $this->assertSame( wp_json_encode( $test_data ), $post->post_content ); + } + + /** + * Test a user request is created successfully for an non-registered user. + * + * @ticket 44707 + */ + public function test_create_request_unregistered_user() { + wp_delete_post( self::$request_id, true ); + + $test_data = array( + 'test-data' => 'test value here', + 'test index' => 'more privacy data', + ); + + $actual = wp_create_user_request( self::$non_registered_user_email, 'export_personal_data', $test_data ); + + $this->assertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( 0, (int) $post->post_author ); + $this->assertSame( 'export_personal_data', $post->post_name ); + $this->assertSame( self::$non_registered_user_email, $post->post_title ); + $this->assertSame( 'request-pending', $post->post_status ); + $this->assertSame( 'user_request', $post->post_type ); + $this->assertSame( wp_json_encode( $test_data ), $post->post_content ); + } + + /** + * Test that a pre-existing request for the same registered user that is not pending or confirmed status does not + * block a new request. + * + * @ticket 44707 + */ + public function test_completed_request_does_not_block_new_request() { + // Update first request. + wp_update_post( + array( + 'ID' => self::$request_id, + 'post_status' => 'request-completed', // Not 'request-pending' or 'request-confirmed'. + ) + ); + + // Second request. + $actual = wp_create_user_request( self::$registered_user_email, 'export_personal_data' ); + + $this->assertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( self::$registered_user_email, $post->post_title ); + $this->assertSame( 'request-pending', $post->post_status ); + $this->assertSame( 'user_request', $post->post_type ); + } + + /** + * Test that a pre-existing request for the same non-registered user that is not pending or confirmed status does not + * block a new request. + * + * @ticket 44707 + */ + public function test_completed_request_does_not_block_new_request_for_unregistered_user() { + wp_update_post( + array( + 'ID' => self::$request_id, + 'post_author' => 0, + 'post_title' => self::$non_registered_user_email, + 'post_status' => 'request-failed', // Not 'request-pending' or 'request-confirmed'. + ) + ); + + $actual = wp_create_user_request( self::$non_registered_user_email, 'export_personal_data' ); + + $this->assertNotWPError( $actual ); + + $post = get_post( $actual ); + + $this->assertSame( 0, (int) $post->post_author ); + $this->assertSame( 'export_personal_data', $post->post_name ); + $this->assertSame( self::$non_registered_user_email, $post->post_title ); + $this->assertSame( 'request-pending', $post->post_status ); + $this->assertSame( 'user_request', $post->post_type ); + } + + /** + * Test that an error from `wp_insert_post()` is returned. + * + * @ticket 44707 + */ + public function test_wp_error_returned_from_wp_insert_post() { + wp_delete_post( self::$request_id, true ); + + add_filter( 'wp_insert_post_empty_content', '__return_true' ); + $actual = wp_create_user_request( self::$registered_user_email, 'export_personal_data' ); + + $this->assertWPError( $actual ); + $this->assertSame( 'empty_content', $actual->get_error_code() ); + } +}