Plugin Directory

source: jetpack/trunk/jetpack_vendor/automattic/jetpack-videopress/src/class-wpcom-rest-api-v2-endpoint-videopress.php @ 3068647

Last change on this file since 3068647 was 3068647, checked in by zinigor, 3 months ago

Updating trunk to version 13.3.1

File size: 17.2 KB
Line 
1<?php
2/**
3 * REST API endpoint for managing VideoPress metadata.
4 *
5 * @package automattic/jetpack
6 * @since-jetpack 9.3.0
7 * @since 0.1.3
8 */
9
10namespace Automattic\Jetpack\VideoPress;
11
12use Automattic\Jetpack\Connection\Client;
13use Automattic\Jetpack\Constants;
14use WP_Error;
15use WP_REST_Controller;
16use WP_REST_Response;
17use WP_REST_Server;
18
19/**
20 * VideoPress wpcom api v2 endpoint
21 */
22class WPCOM_REST_API_V2_Endpoint_VideoPress extends WP_REST_Controller {
23        /**
24         * Constructor.
25         */
26        public function __construct() {
27                $this->namespace = 'wpcom/v2';
28                $this->rest_base = 'videopress';
29
30                add_action( 'rest_api_init', array( $this, 'register_routes' ) );
31        }
32
33        /**
34         * Register the route.
35         */
36        public function register_routes() {
37                // Meta Route.
38                register_rest_route(
39                        $this->namespace,
40                        $this->rest_base . '/meta',
41                        array(
42                                'args'                => array(
43                                        'id'              => array(
44                                                'description'       => __( 'The post id for the attachment.', 'jetpack-videopress-pkg' ),
45                                                'type'              => 'int',
46                                                'required'          => true,
47                                                'validate_callback' => function ( $param ) {
48                                                        return is_numeric( $param );
49                                                },
50                                        ),
51                                        'title'           => array(
52                                                'description'       => __( 'The title of the video.', 'jetpack-videopress-pkg' ),
53                                                'type'              => 'string',
54                                                'required'          => false,
55                                                'sanitize_callback' => 'sanitize_text_field',
56                                        ),
57                                        'description'     => array(
58                                                'description'       => __( 'The description of the video.', 'jetpack-videopress-pkg' ),
59                                                'type'              => 'string',
60                                                'required'          => false,
61                                                'sanitize_callback' => 'sanitize_textarea_field',
62                                        ),
63                                        'caption'         => array(
64                                                'description'       => __( 'The caption of the video.', 'jetpack-videopress-pkg' ),
65                                                'type'              => 'string',
66                                                'required'          => false,
67                                                'sanitize_callback' => 'sanitize_textarea_field',
68                                        ),
69                                        'rating'          => array(
70                                                'description'       => __( 'The video content rating. One of G, PG-13 or R-17', 'jetpack-videopress-pkg' ),
71                                                'type'              => 'string',
72                                                'required'          => false,
73                                                'sanitize_callback' => 'sanitize_text_field',
74                                        ),
75                                        'display_embed'   => array(
76                                                'description'       => __( 'Display the share menu in the player.', 'jetpack-videopress-pkg' ),
77                                                'type'              => 'boolean',
78                                                'required'          => false,
79                                                'sanitize_callback' => 'rest_sanitize_boolean',
80                                        ),
81                                        'allow_download'  => array(
82                                                'description'       => __( 'Display download option and allow viewers to download this video', 'jetpack-videopress-pkg' ),
83                                                'type'              => 'boolean',
84                                                'required'          => false,
85                                                'sanitize_callback' => 'rest_sanitize_boolean',
86                                        ),
87                                        'privacy_setting' => array(
88                                                'description'       => __( 'How to determine if the video should be public or private', 'jetpack-videopress-pkg' ),
89                                                'type'              => 'int',
90                                                'required'          => false,
91                                                'validate_callback' => function ( $param ) {
92                                                        return is_numeric( $param );
93                                                },
94                                        ),
95                                ),
96                                'methods'             => WP_REST_Server::EDITABLE,
97                                'callback'            => array( $this, 'videopress_block_update_meta' ),
98                                'permission_callback' => function () {
99                                        return Data::can_perform_action() && current_user_can( 'edit_posts' );
100                                },
101                        )
102                );
103
104                // Poster Route.
105                register_rest_route(
106                        $this->namespace,
107                        $this->rest_base . '/(?P<video_guid>\w+)/poster',
108                        array(
109                                array(
110                                        'methods'             => WP_REST_Server::READABLE,
111                                        'callback'            => array( $this, 'videopress_block_get_poster' ),
112                                        'permission_callback' => function () {
113                                                return current_user_can( 'read' );
114                                        },
115                                ),
116                                array(
117                                        'args'                => array(
118                                                'at_time'              => array(
119                                                        'description'       => __( 'The time in the video to use as the poster frame.', 'jetpack-videopress-pkg' ),
120                                                        'type'              => 'int',
121                                                        'required'          => false,
122                                                        'validate_callback' => function ( $param ) {
123                                                                return is_numeric( $param );
124                                                        },
125                                                ),
126                                                'is_millisec'          => array(
127                                                        'description'       => __( 'Whether the time is in milliseconds or seconds.', 'jetpack-videopress-pkg' ),
128                                                        'type'              => 'boolean',
129                                                        'required'          => false,
130                                                        'sanitize_callback' => 'rest_sanitize_boolean',
131                                                ),
132                                                'poster_attachment_id' => array(
133                                                        'description'       => __( 'The attachment id of the poster image.', 'jetpack-videopress-pkg' ),
134                                                        'type'              => 'int',
135                                                        'required'          => false,
136                                                        'validate_callback' => function ( $param ) {
137                                                                return is_numeric( $param );
138                                                        },
139                                                ),
140                                        ),
141                                        'methods'             => WP_REST_Server::EDITABLE,
142                                        'callback'            => array( $this, 'videopress_block_update_poster' ),
143                                        'permission_callback' => function () {
144                                                return Data::can_perform_action() && current_user_can( 'upload_files' );
145                                        },
146                                ),
147                        )
148                );
149
150                // Endpoint to know if the video metadata is editable.
151                register_rest_route(
152                        $this->namespace,
153                        $this->rest_base . '/(?P<video_guid>\w+)/check-ownership/(?P<post_id>\d+)/',
154                        array(
155                                array(
156                                        'methods'             => WP_REST_Server::READABLE,
157                                        'callback'            => array( $this, 'videopress_video_belong_to_site' ),
158                                        'permission_callback' => function () {
159                                                return Data::can_perform_action() && current_user_can( 'upload_files' );
160                                        },
161                                ),
162                        )
163                );
164
165                // Token Route
166                register_rest_route(
167                        $this->namespace,
168                        $this->rest_base . '/upload-jwt',
169                        array(
170                                'methods'             => \WP_REST_Server::EDITABLE,
171                                'callback'            => array( $this, 'videopress_upload_jwt' ),
172                                'permission_callback' => function () {
173                                        return Data::can_perform_action() && current_user_can( 'upload_files' );
174                                },
175                        )
176                );
177
178                // Playback Token Route
179                register_rest_route(
180                        $this->namespace,
181                        $this->rest_base . '/playback-jwt/(?P<video_guid>\w+)',
182                        array(
183                                'methods'             => \WP_REST_Server::EDITABLE,
184                                'callback'            => array( $this, 'videopress_playback_jwt' ),
185                                'permission_callback' => function () {
186                                        return current_user_can( 'read' );
187                                },
188                        )
189                );
190        }
191
192        /**
193         * Check whether the video belongs to the current site,
194         * considering the given post_id and the video_guid.
195         *
196         * @param WP_REST_Request $request The request object.
197         * @return WP_REST_Response True if the video belongs to the current site, false otherwise.
198         */
199        public function videopress_video_belong_to_site( $request ) {
200                $post_id    = $request->get_param( 'post_id' );
201                $video_guid = $request->get_param( 'video_guid' );
202
203                if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
204                        $found_guid = get_post_meta( $post_id, 'videopress_guid', true );
205                } else {
206                        $blog_id    = get_current_blog_id();
207                        $info       = video_get_info_by_blogpostid( $blog_id, $post_id );
208                        $found_guid = $info->guid;
209                }
210
211                if ( ! $found_guid ) {
212                        return rest_ensure_response( array( 'video-belong-to-site' => false ) );
213                }
214
215                return rest_ensure_response( array( 'video-belong-to-site' => $found_guid === $video_guid ) );
216        }
217
218        /**
219         * Hit WPCOM poster endpoint.
220         *
221         * @param string $video_guid  The VideoPress GUID.
222         * @param array  $args        Request args.
223         * @param array  $body        Request body.
224         * @param string $query       Request query.
225         * @return WP_REST_Response|WP_Error
226         */
227        public function wpcom_poster_request( $video_guid, $args, $body = null, $query = '' ) {
228                $query    = $query !== '' ? '?' . $query : '';
229                $endpoint = 'videos/' . $video_guid . '/poster' . $query;
230
231                $url = sprintf(
232                        '%s/%s/v%s/%s',
233                        Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ),
234                        'rest',
235                        '1.1',
236                        $endpoint
237                );
238
239                $request_args = array_merge( $args, array( 'body' => $body ) );
240
241                $result = Client::_wp_remote_request( $url, $request_args );
242
243                if ( is_wp_error( $result ) ) {
244                        return rest_ensure_response( $result );
245                }
246
247                $response = $result['http_response'];
248
249                $status = $response->get_status();
250
251                $data = array(
252                        'code' => $status,
253                        'data' => json_decode( $response->get_data(), true ),
254                );
255
256                return rest_ensure_response(
257                        new WP_REST_Response( $data, $status )
258                );
259        }
260
261        /**
262         * Update the a poster image via the WPCOM REST API.
263         *
264         * @param WP_REST_Request $request The request object.
265         * @return WP_REST_Response|WP_Error
266         */
267        public function videopress_block_update_poster( $request ) {
268                try {
269                        $blog_id     = VideoPressToken::blog_id();
270                        $token       = VideoPressToken::videopress_onetime_upload_token();
271                        $video_guid  = $request->get_param( 'video_guid' );
272                        $json_params = $request->get_json_params();
273
274                        $args = array(
275                                'method'  => 'POST',
276                                'headers' => array(
277                                        'content-type'  => 'application/json',
278                                        'Authorization' => 'X_UPLOAD_TOKEN token="' . $token . '" blog_id="' . $blog_id . '"',
279                                ),
280                        );
281
282                        return $this->wpcom_poster_request(
283                                $video_guid,
284                                $args,
285                                wp_json_encode( $json_params )
286                        );
287                } catch ( \Exception $e ) {
288                        return rest_ensure_response( new WP_Error( 'videopress_block_update_poster_error', $e->getMessage() ) );
289                }
290        }
291
292        /**
293         * Retrieves a poster image via the WPCOM REST API.
294         *
295         * @param WP_REST_Request $request the request object.
296         * @return object|WP_Error Success object or WP_Error with error details.
297         */
298        public function videopress_block_get_poster( $request ) {
299                $video_guid = $request->get_param( 'video_guid' );
300                $jwt        = VideoPressToken::videopress_playback_jwt( $video_guid );
301
302                $args = array(
303                        'method' => 'GET',
304                );
305
306                return $this->wpcom_poster_request(
307                        $video_guid,
308                        $args,
309                        null,
310                        'metadata_token=' . $jwt
311                );
312        }
313
314        /**
315         * Endpoint for getting the VideoPress Upload JWT
316         *
317         * @return WP_Rest_Response - The response object.
318         */
319        public static function videopress_upload_jwt() {
320                $has_connected_owner = Data::has_connected_owner();
321                if ( ! $has_connected_owner ) {
322                        return rest_ensure_response(
323                                new WP_Error(
324                                        'owner_not_connected',
325                                        'User not connected.',
326                                        array(
327                                                'code'        => 503,
328                                                'connect_url' => Admin_UI::get_admin_page_url(),
329                                        )
330                                )
331                        );
332                }
333
334                $blog_id = Data::get_blog_id();
335                if ( ! $blog_id ) {
336                        return rest_ensure_response(
337                                new WP_Error( 'site_not_registered', 'Site not registered.', 503 )
338                        );
339                }
340
341                try {
342                        $token  = VideoPressToken::videopress_upload_jwt();
343                        $status = 200;
344                        $data   = array(
345                                'upload_token'   => $token,
346                                'upload_url'     => videopress_make_resumable_upload_path( $blog_id ),
347                                'upload_blog_id' => $blog_id,
348                        );
349                } catch ( \Exception $e ) {
350                        $status = 500;
351                        $data   = array(
352                                'error' => $e->getMessage(),
353                        );
354
355                }
356
357                return rest_ensure_response(
358                        new WP_REST_Response( $data, $status )
359                );
360        }
361
362        /**
363         * Endpoint for generating a VideoPress Playback JWT
364         *
365         * @param WP_REST_Request $request the request object.
366         * @return WP_Rest_Response - The response object.
367         */
368        public static function videopress_playback_jwt( $request ) {
369                $has_connected_owner = Data::has_connected_owner();
370                if ( ! $has_connected_owner ) {
371                        return rest_ensure_response(
372                                new WP_Error(
373                                        'owner_not_connected',
374                                        'User not connected.',
375                                        array(
376                                                'code'        => 503,
377                                                'connect_url' => Admin_UI::get_admin_page_url(),
378                                        )
379                                )
380                        );
381                }
382
383                $blog_id = Data::get_blog_id();
384                if ( ! $blog_id ) {
385                        return rest_ensure_response(
386                                new WP_Error( 'site_not_registered', 'Site not registered.', 503 )
387                        );
388                }
389
390                try {
391                        $video_guid = $request->get_param( 'video_guid' );
392                        $token      = VideoPressToken::videopress_playback_jwt( $video_guid );
393                        $status     = 200;
394                        $data       = array(
395                                'playback_token' => $token,
396                        );
397                } catch ( \Exception $e ) {
398                        $status = 500;
399                        $data   = array(
400                                'error' => $e->getMessage(),
401                        );
402
403                }
404
405                return rest_ensure_response(
406                        new WP_REST_Response( $data, $status )
407                );
408        }
409
410        /**
411         * Updates attachment meta and video metadata via the WPCOM REST API.
412         *
413         * @param WP_REST_Request $request the request object.
414         * @return object|WP_Error Success object or WP_Error with error details.
415         */
416        public function videopress_block_update_meta( $request ) {
417                $json_params = $request->get_json_params();
418                $post_id     = $json_params['id'];
419
420                if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
421                        $guid = get_post_meta( $post_id, 'videopress_guid', true );
422                } else {
423                        $blog_id = get_current_blog_id();
424                        $info    = video_get_info_by_blogpostid( $blog_id, $post_id );
425                        $guid    = $info->guid;
426                }
427
428                if ( ! $guid ) {
429                        return rest_ensure_response(
430                                new WP_Error(
431                                        'error',
432                                        __( 'This attachment cannot be updated yet.', 'jetpack-videopress-pkg' )
433                                )
434                        );
435                }
436
437                $video_request_params = $json_params;
438                unset( $video_request_params['id'] );
439                $video_request_params['guid'] = $guid;
440
441                $endpoint = 'videos';
442                $args     = array(
443                        'method'  => 'POST',
444                        'headers' => array( 'content-type' => 'application/json' ),
445                );
446
447                $result = Client::wpcom_json_api_request_as_blog(
448                        $endpoint,
449                        '2',
450                        $args,
451                        wp_json_encode( $video_request_params ),
452                        'wpcom'
453                );
454
455                if ( is_wp_error( $result ) ) {
456                        return rest_ensure_response( $result );
457                }
458
459                $response_body = json_decode( wp_remote_retrieve_body( $result ) );
460                if ( is_bool( $response_body ) && $response_body ) {
461                        /*
462                         * Title, description and caption of the video are not stored as metadata on the attachment,
463                         * but as post_content, post_title and post_excerpt on the attachment's post object.
464                         * We need to update those fields here, too.
465                         */
466                        $post_title = null;
467                        if ( isset( $json_params['title'] ) ) {
468                                $post_title = sanitize_text_field( $json_params['title'] );
469                                wp_update_post(
470                                        array(
471                                                'ID'         => $post_id,
472                                                'post_title' => $post_title,
473                                        )
474                                );
475                        }
476
477                        $post_content = null;
478                        if ( isset( $json_params['description'] ) ) {
479                                $post_content = sanitize_textarea_field( $json_params['description'] );
480                                wp_update_post(
481                                        array(
482                                                'ID'           => $post_id,
483                                                'post_content' => $post_content,
484                                        )
485                                );
486                        }
487
488                        $post_excerpt = null;
489                        if ( isset( $json_params['caption'] ) ) {
490                                $post_excerpt = sanitize_textarea_field( $json_params['caption'] );
491                                wp_update_post(
492                                        array(
493                                                'ID'           => $post_id,
494                                                'post_excerpt' => $post_excerpt,
495                                        )
496                                );
497                        }
498
499                        // VideoPress data is stored in attachment meta for Jetpack sites, but not on wpcom.
500                        if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
501                                $meta               = wp_get_attachment_metadata( $post_id );
502                                $should_update_meta = false;
503
504                                if ( ! $meta ) {
505                                        return rest_ensure_response(
506                                                new WP_Error(
507                                                        'error',
508                                                        __( 'Attachment meta was not found.', 'jetpack-videopress-pkg' )
509                                                )
510                                        );
511                                }
512
513                                if ( isset( $json_params['display_embed'] ) && isset( $meta['videopress']['display_embed'] ) ) {
514                                        $meta['videopress']['display_embed'] = $json_params['display_embed'];
515                                        $should_update_meta                  = true;
516                                }
517
518                                if ( isset( $json_params['rating'] ) && isset( $meta['videopress']['rating'] ) && videopress_is_valid_video_rating( $json_params['rating'] ) ) {
519                                        $meta['videopress']['rating'] = $json_params['rating'];
520                                        $should_update_meta           = true;
521
522                                        /** Set a new meta field so we can filter using it directly */
523                                        update_post_meta( $post_id, 'videopress_rating', $json_params['rating'] );
524                                }
525
526                                if ( isset( $json_params['title'] ) ) {
527                                        $meta['videopress']['title'] = $post_title;
528                                        $should_update_meta          = true;
529                                }
530
531                                if ( isset( $json_params['description'] ) ) {
532                                        $meta['videopress']['description'] = $post_content;
533                                        $should_update_meta                = true;
534                                }
535
536                                if ( isset( $json_params['caption'] ) ) {
537                                        $meta['videopress']['caption'] = $post_excerpt;
538                                        $should_update_meta            = true;
539                                }
540
541                                if ( isset( $json_params['poster'] ) ) {
542                                        $meta['videopress']['poster'] = $json_params['poster'];
543                                        $should_update_meta           = true;
544                                }
545
546                                if ( isset( $json_params['allow_download'] ) ) {
547                                        $allow_download = (bool) $json_params['allow_download'];
548                                        if ( ! isset( $meta['videopress']['allow_download'] ) || $meta['videopress']['allow_download'] !== $allow_download ) {
549                                                $meta['videopress']['allow_download'] = $allow_download;
550                                                $should_update_meta                   = true;
551                                        }
552                                }
553
554                                if ( isset( $json_params['privacy_setting'] ) ) {
555                                        $privacy_setting = $json_params['privacy_setting'];
556                                        if ( ! isset( $meta['videopress']['privacy_setting'] ) || $meta['videopress']['privacy_setting'] !== $privacy_setting ) {
557                                                $meta['videopress']['privacy_setting'] = $privacy_setting;
558                                                $should_update_meta                    = true;
559
560                                                /** Set a new meta field so we can filter using it directly */
561                                                update_post_meta( $post_id, 'videopress_privacy_setting', $privacy_setting );
562                                        }
563                                }
564
565                                if ( $should_update_meta ) {
566                                        wp_update_attachment_metadata( $post_id, $meta );
567                                }
568                        }
569
570                        return rest_ensure_response(
571                                array(
572                                        'code'    => 'success',
573                                        'message' => __( 'Video meta updated successfully.', 'jetpack-videopress-pkg' ),
574                                        'data'    => 200,
575                                )
576                        );
577                } else {
578                        return rest_ensure_response(
579                                new WP_Error(
580                                        $response_body->code,
581                                        $response_body->message,
582                                        $response_body->data
583                                )
584                        );
585                }
586        }
587}
588
589if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
590        wpcom_rest_api_v2_load_plugin( 'Automattic\Jetpack\VideoPress\WPCOM_REST_API_V2_Endpoint_VideoPress' );
591}
Note: See TracBrowser for help on using the repository browser.