Make WordPress Core


Ignore:
Timestamp:
07/04/2020 04:13:17 AM (5 years ago)
Author:
TimothyBlynJacobs
Message:

REST API: Introduce endpoint for editing images.

To facilitate inline image editing in Gutenberg, a new endpoint at wp/v2/media/<id>/edit has been introduced. This is functionally similar to the existing ajax image editor, however the REST API editor creates a new attachment record instead of updating an existing attachment.

Fixes #44405.
Props ajlende, ellatrix, spacedmonkey, azaozz.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tests/phpunit/tests/rest-api/rest-attachments-controller.php

    r47261 r48291  
    2020    protected static $rest_insert_attachment_count;
    2121
     22    /**
     23     * @var string The path to a test file.
     24     */
     25    private $test_file;
     26
     27    /**
     28     * @var string The path to a second test file.
     29     */
     30    private $test_file2;
     31
    2232    public static function wpSetUpBeforeClass( $factory ) {
    2333        self::$superadmin_id  = $factory->user->create(
     
    7686        $this->test_file2 = '/tmp/codeispoetry.png';
    7787        copy( $orig_file2, $this->test_file2 );
     88    }
     89
     90    public function tearDown() {
     91        parent::tearDown();
     92
     93        if ( file_exists( $this->test_file ) ) {
     94            unlink( $this->test_file );
     95        }
     96        if ( file_exists( $this->test_file2 ) ) {
     97            unlink( $this->test_file2 );
     98        }
     99
     100        remove_action( 'rest_insert_attachment', array( $this, 'filter_rest_insert_attachment' ) );
     101        remove_action( 'rest_after_insert_attachment', array( $this, 'filter_rest_after_insert_attachment' ) );
     102
     103        $this->remove_added_uploads();
     104
     105        if ( class_exists( WP_Image_Editor_Mock::class ) ) {
     106            WP_Image_Editor_Mock::$spy         = array();
     107            WP_Image_Editor_Mock::$edit_return = array();
     108            WP_Image_Editor_Mock::$size_return = null;
     109        }
    78110    }
    79111
     
    15381570    }
    15391571
    1540     public function tearDown() {
    1541         parent::tearDown();
    1542         if ( file_exists( $this->test_file ) ) {
    1543             unlink( $this->test_file );
    1544         }
    1545         if ( file_exists( $this->test_file2 ) ) {
    1546             unlink( $this->test_file2 );
    1547         }
    1548 
    1549         remove_action( 'rest_insert_attachment', array( $this, 'filter_rest_insert_attachment' ) );
    1550         remove_action( 'rest_after_insert_attachment', array( $this, 'filter_rest_after_insert_attachment' ) );
    1551 
    1552         $this->remove_added_uploads();
    1553     }
    1554 
    15551572    protected function check_post_data( $attachment, $data, $context = 'view', $links ) {
    15561573        parent::check_post_data( $attachment, $data, $context, $links );
     
    17771794        self::$rest_after_insert_attachment_count++;
    17781795    }
     1796
     1797    /**
     1798     * @ticket 44405
     1799     */
     1800    public function test_edit_image_returns_error_if_logged_out() {
     1801        $attachment = self::factory()->attachment->create();
     1802
     1803        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1804        $response = rest_do_request( $request );
     1805        $this->assertErrorResponse( 'rest_cannot_edit_image', $response, 401 );
     1806    }
     1807
     1808    /**
     1809     * @ticket 44405
     1810     */
     1811    public function test_edit_image_returns_error_if_cannot_upload() {
     1812        $user = self::factory()->user->create_and_get( array( 'role' => 'editor' ) );
     1813        $user->add_cap( 'upload_files', false );
     1814
     1815        wp_set_current_user( $user->ID );
     1816        $attachment = self::factory()->attachment->create( array( 'post_author' => $user->ID ) );
     1817
     1818        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1819        $response = rest_do_request( $request );
     1820        $this->assertErrorResponse( 'rest_cannot_edit_image', $response, 403 );
     1821    }
     1822
     1823    /**
     1824     * @ticket 44405
     1825     */
     1826    public function test_edit_image_returns_error_if_cannot_edit() {
     1827        wp_set_current_user( self::$uploader_id );
     1828        $attachment = self::factory()->attachment->create();
     1829
     1830        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1831        $response = rest_do_request( $request );
     1832        $this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
     1833    }
     1834
     1835    /**
     1836     * @ticket 44405
     1837     */
     1838    public function test_edit_image_returns_error_if_no_attachment() {
     1839        wp_set_current_user( self::$superadmin_id );
     1840        $attachment = self::factory()->attachment->create();
     1841
     1842        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1843        $response = rest_do_request( $request );
     1844        $this->assertErrorResponse( 'rest_unknown_attachment', $response, 404 );
     1845    }
     1846
     1847    /**
     1848     * @ticket 44405
     1849     */
     1850    public function test_edit_image_returns_error_if_unsupported_mime_type() {
     1851        wp_set_current_user( self::$superadmin_id );
     1852        $attachment = self::factory()->attachment->create_upload_object( $this->test_file );
     1853        wp_update_post(
     1854            array(
     1855                'ID'             => $attachment,
     1856                'post_mime_type' => 'image/invalid',
     1857            )
     1858        );
     1859
     1860        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1861        $response = rest_do_request( $request );
     1862        $this->assertErrorResponse( 'rest_cannot_edit_file_type', $response, 400 );
     1863    }
     1864
     1865    /**
     1866     * @ticket 44405
     1867     */
     1868    public function test_edit_image_returns_error_if_no_edits() {
     1869        wp_set_current_user( self::$superadmin_id );
     1870        $attachment = self::factory()->attachment->create_upload_object( $this->test_file );
     1871
     1872        $request  = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1873        $response = rest_do_request( $request );
     1874        $this->assertErrorResponse( 'rest_image_not_edited', $response, 400 );
     1875    }
     1876
     1877    /**
     1878     * @ticket 44405
     1879     */
     1880    public function test_edit_image_rotate() {
     1881        wp_set_current_user( self::$superadmin_id );
     1882        $attachment = self::factory()->attachment->create_upload_object( $this->test_file );
     1883
     1884        $this->setup_mock_editor();
     1885        WP_Image_Editor_Mock::$edit_return['rotate'] = new WP_Error();
     1886
     1887        $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1888        $request->set_body_params( array( 'rotation' => 60 ) );
     1889        $response = rest_do_request( $request );
     1890        $this->assertErrorResponse( 'rest_image_rotation_failed', $response, 500 );
     1891
     1892        $this->assertCount( 1, WP_Image_Editor_Mock::$spy['rotate'] );
     1893        $this->assertEquals( array( -60 ), WP_Image_Editor_Mock::$spy['rotate'][0] );
     1894    }
     1895
     1896    /**
     1897     * @ticket 44405
     1898     */
     1899    public function test_edit_image_crop() {
     1900        wp_set_current_user( self::$superadmin_id );
     1901        $attachment = self::factory()->attachment->create_upload_object( $this->test_file );
     1902
     1903        $this->setup_mock_editor();
     1904        WP_Image_Editor_Mock::$size_return = array(
     1905            'width'  => 640,
     1906            'height' => 480,
     1907        );
     1908
     1909        WP_Image_Editor_Mock::$edit_return['crop'] = new WP_Error();
     1910
     1911        $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1912        $request->set_body_params(
     1913            array(
     1914                'x'      => 50,
     1915                'y'      => 10,
     1916                'width'  => 10,
     1917                'height' => 5,
     1918            )
     1919        );
     1920        $response = rest_do_request( $request );
     1921        $this->assertErrorResponse( 'rest_image_crop_failed', $response, 500 );
     1922
     1923        $this->assertCount( 1, WP_Image_Editor_Mock::$spy['crop'] );
     1924        $this->assertEquals(
     1925            array( 320.0, 48.0, 64.0, 24.0 ),
     1926            WP_Image_Editor_Mock::$spy['crop'][0]
     1927        );
     1928    }
     1929
     1930    /**
     1931     * @ticket 44405
     1932     */
     1933    public function test_edit_image() {
     1934        wp_set_current_user( self::$superadmin_id );
     1935        $attachment = self::factory()->attachment->create_upload_object( $this->test_file );
     1936
     1937        $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment}/edit" );
     1938        $request->set_body_params( array( 'rotation' => 60 ) );
     1939        $response = rest_do_request( $request );
     1940        $item     = $response->get_data();
     1941
     1942        $this->assertEquals( 201, $response->get_status() );
     1943        $this->assertEquals( rest_url( '/wp/v2/media/' . $item['id'] ), $response->get_headers()['Location'] );
     1944
     1945        $this->assertStringEndsWith( '-edited.jpg', $item['media_details']['file'] );
     1946        $this->assertArrayHasKey( 'parent_image', $item['media_details'] );
     1947        $this->assertEquals( $attachment, $item['media_details']['parent_image']['attachment_id'] );
     1948        $this->assertContains( 'canola', $item['media_details']['parent_image']['file'] );
     1949    }
     1950
     1951    /**
     1952     * Sets up the mock image editor.
     1953     *
     1954     * @since 5.5.0
     1955     */
     1956    protected function setup_mock_editor() {
     1957        require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
     1958        require_once DIR_TESTDATA . '/../includes/mock-image-editor.php';
     1959
     1960        add_filter(
     1961            'wp_image_editors',
     1962            static function () {
     1963                return array( 'WP_Image_Editor_Mock' );
     1964            }
     1965        );
     1966    }
    17791967}
Note: See TracChangeset for help on using the changeset viewer.