diff --git a/php/class-import.php b/php/class-import.php old mode 100644 new mode 100755 index f73321b4..54ae073d --- a/php/class-import.php +++ b/php/class-import.php @@ -209,14 +209,15 @@ public function create_attachment( $file ) { */ public function process_meta() { $map = [ - 'color' => 'color', - 'original_id' => 'original_id', - 'original_url' => 'original_url', - 'unsplash_location' => 'unsplash_location', - 'unsplash_sponsor' => 'unsplash_sponsor', - 'unsplash_exif' => 'unsplash_exif', - '_wp_attachment_metadata' => 'meta', - '_wp_attachment_image_alt' => 'alt', + 'color' => 'color', + 'original_id' => 'original_id', + 'original_url' => 'original_url', + 'unsplash_location' => 'unsplash_location', + 'unsplash_sponsor' => 'unsplash_sponsor', + 'unsplash_exif' => 'unsplash_exif', + '_wp_attachment_metadata' => 'meta', + 'unsplash_attachment_metadata' => 'meta', + '_wp_attachment_image_alt' => 'alt', ]; foreach ( $map as $key => $value ) { update_post_meta( $this->attachment_id, $key, $this->image->get_field( $value ), true ); diff --git a/php/class-rest-controller.php b/php/class-rest-controller.php old mode 100644 new mode 100755 index ec88ae33..4b63c84a --- a/php/class-rest-controller.php +++ b/php/class-rest-controller.php @@ -144,6 +144,29 @@ public function register_routes() { 'schema' => [ $this, 'get_public_item_schema' ], ] ); + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/post-process/(?P[\d]+)', + [ + 'args' => [ + 'id' => [ + 'description' => __( 'WordPress attachment ID.', 'unsplash' ), + 'type' => 'integer', + 'validate_callback' => [ $this, 'validate_get_attachment' ], + ], + ], + [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [ $this, 'post_process' ], + 'permission_callback' => [ $this, 'create_item_permissions_check' ], + 'args' => [ + 'context' => $this->get_context_param( [ 'default' => 'view' ] ), + ], + ], + 'schema' => [ $this, 'get_public_item_schema' ], + ] + ); } /** @@ -245,6 +268,46 @@ public function get_import( $request ) { return $response; } + /** + * Process image. + * + * @param WP_REST_Request $request Request. + * + * @return WP_REST_Response|WP_Error Single page of photo results. + */ + public function post_process( $request ) { + $attachment_id = $request->get_param( 'id' ); + try { + if ( ! function_exists( 'wp_generate_attachment_metadata' ) ) { + require_once ABSPATH . 'wp-admin/includes/media.php'; + require_once ABSPATH . 'wp-admin/includes/file.php'; + require_once ABSPATH . 'wp-admin/includes/image.php'; + } + $meta = (array) get_post_meta( $attachment_id, 'unsplash_attachment_metadata', true ); + $file = get_attached_file( $attachment_id ); + $new_meta = wp_generate_attachment_metadata( $attachment_id, $file ); + unset( $meta['sizes'], $new_meta['image_meta'] ); + $new_meta = wp_parse_args( $new_meta, $meta ); + $processed = wp_update_attachment_metadata( $attachment_id, $new_meta ); + $data = [ 'processed' => $processed ]; + } catch ( \Exception $e ) { + $response = new WP_Error( + 'single-photo-process', + /* translators: %d: attachment id */ + sprintf( __( 'Unable to process image attachment %d.', 'unsplash' ), $attachment_id ), + [ + 'attachment_id' => $attachment_id, + 'status' => '400', + ] + ); + $this->plugin->log_error( $e ); + return $response; + } + $response = new WP_REST_Response( $data ); + + return $response; + } + /** * Retrieve a page of photos filtered by a search term. * @@ -457,6 +520,34 @@ public static function validate_get_search_param( $value, $request, $param ) { return true; } + /** + * Check if attachment exists. + * + * @param int $param Attachment ID. + * @return bool|WP_Error + */ + public function validate_get_attachment( $param ) { + $attachment = get_post( (int) $param ); + + if ( empty( $attachment ) ) { + return new WP_Error( + 'rest_post_invalid_id', + __( 'Invalid attachment ID.', 'unsplash' ), + array( 'status' => 400 ) + ); + } + + if ( get_post_type( $attachment ) !== $this->post_type ) { + return new WP_Error( + 'rest_invalid_post_type_id', + __( 'Invalid attachment ID.', 'unsplash' ), + array( 'status' => 400 ) + ); + } + + return true; + } + /** * Retrieves the photo type's schema, conforming to JSON Schema. * diff --git a/tests/phpunit/php/class-test-rest-controller.php b/tests/phpunit/php/class-test-rest-controller.php old mode 100644 new mode 100755 index 03ac610b..309bcca3 --- a/tests/phpunit/php/class-test-rest-controller.php +++ b/tests/phpunit/php/class-test-rest-controller.php @@ -394,6 +394,86 @@ public function test_get_import() { remove_filter( 'upload_dir', [ $this, 'upload_dir_patch' ] ); } + /** + * Test post_process() auth. + * + * @covers \Unsplash\Rest_Controller::post_process() + * @covers \Unsplash\Rest_Controller::create_item_permissions_check() + */ + public function test_post_process() { + add_filter( 'upload_dir', [ $this, 'upload_dir_patch' ] ); + $orig_file = DIR_TESTDATA . '/images/test-image.jpg'; + $test_file = get_temp_dir() . 'test-image.jpg'; + copy( $orig_file, $test_file ); + $second_id = $this->factory->attachment->create_object( + $test_file, + 0, + [ + 'post_mime_type' => 'image/jpeg', + 'post_excerpt' => 'A sample caption 2', + ] + ); + update_post_meta( + $second_id, + 'unsplash_attachment_metadata', + [ + 'width' => 2, + 'foo' => 'bar', + 'image_meta' => [ 'aperture' => 1 ], + 'sizes' => null, + ] + ); + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', $this->get_route( '/post-process/' . $second_id ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( $response->get_data(), [ 'processed' => true ] ); + $meta = wp_get_attachment_metadata( $second_id ); + $this->assertArrayHasKey( 'foo', $meta ); + $this->assertArrayHasKey( 'sizes', $meta ); + $this->assertArrayHasKey( 'width', $meta ); + $this->assertSame( 50, $meta['width'] ); + $this->assertSame( [ 'aperture' => 1 ], $meta['image_meta'] ); + remove_filter( 'upload_dir', [ $this, 'upload_dir_patch' ] ); + } + + /** + * Test validate_get_attachment(). + * + * @covers \Unsplash\Rest_Controller::post_process() + * @covers \Unsplash\Rest_Controller::validate_get_attachment() + */ + public function test_post_process_invalid() { + $test_page = self::factory()->post->create( + [ + 'post_type' => 'page', + 'post_title' => 'About', + 'post_status' => 'publish', + 'post_content' => 'hello there', + ] + ); + + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', $this->get_route( '/post-process/' . $test_page ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); + } + + /** + * Test validate_get_attachment(). + * + * @covers \Unsplash\Rest_Controller::post_process() + * @covers \Unsplash\Rest_Controller::validate_get_attachment() + */ + public function test_post_process_invalid_2() { + $test_page = wp_rand(); + + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', $this->get_route( '/post-process/' . $test_page ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); + } + /** * Test get_item() auth. * @@ -433,6 +513,27 @@ public function test_get_import_auth() { $this->assertErrorResponse( 'rest_cannot_create', $response, 403 ); } + /** + * Test post_process() auth. + * + * @covers \Unsplash\Rest_Controller::post_process() + * @covers \Unsplash\Rest_Controller::create_item_permissions_check() + */ + public function test_post_process_auth() { + $second_id = $this->factory->attachment->create_object( + '/tmp/melon.jpg', + 0, + [ + 'post_mime_type' => 'image/jpeg', + 'post_excerpt' => 'A sample caption 2', + ] + ); + wp_set_current_user( self::$subscriber_id ); + $request = new WP_REST_Request( 'GET', $this->get_route( '/post-process/' . $second_id ) ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_create', $response, 403 ); + } + /** * Test arguments for get_item(). */