Plugin Directory

source: jetpack/trunk/jetpack_vendor/automattic/jetpack-blaze/src/class-dashboard-rest-controller.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: 27.3 KB
Line 
1<?php
2/**
3 * The Blaze Rest Controller class.
4 * Registers the REST routes for Blaze Dashboard.
5 *
6 * @package automattic/jetpack-blaze
7 */
8
9namespace Automattic\Jetpack\Blaze;
10
11use Automattic\Jetpack\Connection\Client;
12use Automattic\Jetpack\Connection\Manager as Connection_Manager;
13use Automattic\Jetpack\Status\Host;
14use WC_Product;
15use WP_Error;
16use WP_REST_Server;
17
18/**
19 * Registers the REST routes for Blaze Dashboard.
20 * It bascially forwards the requests to the WordPress.com REST API.
21 */
22class Dashboard_REST_Controller {
23        /**
24         * Namespace for the REST API.
25         *
26         * @var string
27         */
28        public static $namespace = 'jetpack/v4/blaze-app';
29
30        /**
31         * Registers the REST routes for Blaze Dashboard.
32         *
33         * Blaze Dashboard is built from `wp-calypso`, which leverages the `public-api.wordpress.com` API.
34         * The current Site ID is added as part of the route, so that the front end doesn't have to handle the differences.
35         *
36         * @access public
37         * @static
38         */
39        public function register_rest_routes() {
40                $site_id = $this->get_site_id();
41                if ( is_wp_error( $site_id ) ) {
42                        return;
43                }
44
45                // WPCOM API routes
46                register_rest_route(
47                        static::$namespace,
48                        sprintf( '/sites/%d/blaze/posts(\?.*)?', $site_id ),
49                        array(
50                                'methods'             => WP_REST_Server::READABLE,
51                                'callback'            => array( $this, 'get_blaze_posts' ),
52                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
53                        )
54                );
55
56                // WordAds DSP API Posts routes
57                register_rest_route(
58                        static::$namespace,
59                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/wpcom/sites/%1$d/blaze/posts(\?.*)?', $site_id ),
60                        array(
61                                'methods'             => WP_REST_Server::READABLE,
62                                'callback'            => array( $this, 'get_dsp_blaze_posts' ),
63                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
64                        )
65                );
66
67                // WordAds DSP API Checkout route
68                register_rest_route(
69                        static::$namespace,
70                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/wpcom/checkout', $site_id ),
71                        array(
72                                'methods'             => WP_REST_Server::EDITABLE,
73                                'callback'            => array( $this, 'edit_wpcom_checkout' ),
74                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
75                        )
76                );
77
78                // WordAds DSP API Credits routes
79                register_rest_route(
80                        static::$namespace,
81                        sprintf( '/sites/%d/wordads/dsp/api/v1/credits(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
82                        array(
83                                'methods'             => WP_REST_Server::READABLE,
84                                'callback'            => array( $this, 'get_dsp_credits' ),
85                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
86                        )
87                );
88
89                // WordAds DSP API media query routes
90                register_rest_route(
91                        static::$namespace,
92                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/wpcom/sites/%1$d/media(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
93                        array(
94                                'methods'             => WP_REST_Server::READABLE,
95                                'callback'            => array( $this, 'get_dsp_media' ),
96                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
97                        )
98                );
99
100                // WordAds DSP API upload to WP Media Library routes
101                register_rest_route(
102                        static::$namespace,
103                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/wpcom/sites/%1$d/media', $site_id ),
104                        array(
105                                'methods'             => WP_REST_Server::CREATABLE,
106                                'callback'            => array( $this, 'upload_image_to_current_website' ),
107                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
108                        )
109                );
110
111                // WordAds DSP API media openverse query routes
112                register_rest_route(
113                        static::$namespace,
114                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/wpcom/media(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
115                        array(
116                                'methods'             => WP_REST_Server::READABLE,
117                                'callback'            => array( $this, 'get_dsp_openverse' ),
118                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
119                        )
120                );
121
122                // WordAds DSP API Experiment route
123                register_rest_route(
124                        static::$namespace,
125                        sprintf( '/sites/%d/wordads/dsp/api/v1/experiments(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
126                        array(
127                                'methods'             => WP_REST_Server::READABLE,
128                                'callback'            => array( $this, 'get_dsp_experiments' ),
129                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
130                        )
131                );
132
133                // WordAds DSP API Campaigns routes
134                register_rest_route(
135                        static::$namespace,
136                        sprintf( '/sites/%d/wordads/dsp/api/v1/campaigns(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
137                        array(
138                                'methods'             => WP_REST_Server::READABLE,
139                                'callback'            => array( $this, 'get_dsp_campaigns' ),
140                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
141                        )
142                );
143                register_rest_route(
144                        static::$namespace,
145                        sprintf( '/sites/%d/wordads/dsp/api/(?P<api_version>v[0-9]+\.?[0-9]*)/campaigns(?P<sub_path>[a-zA-Z0-9-_\/]*)', $site_id ),
146                        array(
147                                'methods'             => WP_REST_Server::EDITABLE,
148                                'callback'            => array( $this, 'edit_dsp_campaigns' ),
149                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
150                        )
151                );
152
153                // WordAds DSP API Site Campaigns routes
154                register_rest_route(
155                        static::$namespace,
156                        sprintf( '/sites/%1$d/wordads/dsp/api/v1/sites/%1$d/campaigns(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
157                        array(
158                                'methods'             => WP_REST_Server::READABLE,
159                                'callback'            => array( $this, 'get_dsp_site_campaigns' ),
160                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
161                        )
162                );
163
164                // WordAds DSP API Search routes
165                register_rest_route(
166                        static::$namespace,
167                        sprintf( '/sites/%d/wordads/dsp/api/v1/search(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
168                        array(
169                                'methods'             => WP_REST_Server::READABLE,
170                                'callback'            => array( $this, 'get_dsp_search' ),
171                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
172                        )
173                );
174
175                // WordAds DSP API Users routes
176                register_rest_route(
177                        static::$namespace,
178                        sprintf( '/sites/%d/wordads/dsp/api/v1/user(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
179                        array(
180                                'methods'             => WP_REST_Server::READABLE,
181                                'callback'            => array( $this, 'get_dsp_user' ),
182                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
183                        )
184                );
185
186                // WordAds DSP API Templates routes
187                register_rest_route(
188                        static::$namespace,
189                        sprintf( '/sites/%d/wordads/dsp/api/v1/templates(?P<sub_path>[a-zA-Z0-9-_\/:]*)(\?.*)?', $site_id ),
190                        array(
191                                'methods'             => WP_REST_Server::READABLE,
192                                'callback'            => array( $this, 'get_dsp_templates' ),
193                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
194                        )
195                );
196
197                // WordAds DSP API Subscriptions routes
198                register_rest_route(
199                        static::$namespace,
200                        sprintf( '/sites/%d/wordads/dsp/api/v1/subscriptions(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
201                        array(
202                                'methods'             => WP_REST_Server::READABLE,
203                                'callback'            => array( $this, 'get_dsp_subscriptions' ),
204                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
205                        )
206                );
207                register_rest_route(
208                        static::$namespace,
209                        sprintf( '/sites/%d/wordads/dsp/api/v1/subscriptions(?P<sub_path>[a-zA-Z0-9-_\/]*)', $site_id ),
210                        array(
211                                'methods'             => WP_REST_Server::EDITABLE,
212                                'callback'            => array( $this, 'edit_dsp_subscriptions' ),
213                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
214                        )
215                );
216
217                // WordAds DSP API Payments routes
218                register_rest_route(
219                        static::$namespace,
220                        sprintf( '/sites/%d/wordads/dsp/api/v1/payments(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
221                        array(
222                                'methods'             => WP_REST_Server::READABLE,
223                                'callback'            => array( $this, 'get_dsp_payments' ),
224                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
225                        )
226                );
227                register_rest_route(
228                        static::$namespace,
229                        sprintf( '/sites/%d/wordads/dsp/api/v1/payments(?P<sub_path>[a-zA-Z0-9-_\/]*)', $site_id ),
230                        array(
231                                'methods'             => WP_REST_Server::EDITABLE,
232                                'callback'            => array( $this, 'edit_dsp_payments' ),
233                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
234                        )
235                );
236
237                // WordAds DSP API Smart routes
238                register_rest_route(
239                        static::$namespace,
240                        sprintf( '/sites/%d/wordads/dsp/api/v1/smart(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
241                        array(
242                                'methods'             => WP_REST_Server::READABLE,
243                                'callback'            => array( $this, 'get_dsp_smart' ),
244                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
245                        )
246                );
247                register_rest_route(
248                        static::$namespace,
249                        sprintf( '/sites/%d/wordads/dsp/api/v1/smart(?P<sub_path>[a-zA-Z0-9-_\/]*)', $site_id ),
250                        array(
251                                'methods'             => WP_REST_Server::EDITABLE,
252                                'callback'            => array( $this, 'edit_dsp_smart' ),
253                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
254                        )
255                );
256
257                // WordAds DSP API Locations routes
258                register_rest_route(
259                        static::$namespace,
260                        sprintf( '/sites/%d/wordads/dsp/api/v1/locations(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
261                        array(
262                                'methods'             => WP_REST_Server::READABLE,
263                                'callback'            => array( $this, 'get_dsp_locations' ),
264                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
265                        )
266                );
267
268                // WordAds DSP API Woo routes
269                register_rest_route(
270                        static::$namespace,
271                        sprintf( '/sites/%d/wordads/dsp/api/v1/woo(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
272                        array(
273                                'methods'             => WP_REST_Server::READABLE,
274                                'callback'            => array( $this, 'get_dsp_woo' ),
275                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
276                        )
277                );
278
279                // WordAds DSP API Image routes
280                register_rest_route(
281                        static::$namespace,
282                        sprintf( '/sites/%d/wordads/dsp/api/v1/image(?P<sub_path>[a-zA-Z0-9-_\/]*)(\?.*)?', $site_id ),
283                        array(
284                                'methods'             => WP_REST_Server::READABLE,
285                                'callback'            => array( $this, 'get_dsp_image' ),
286                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
287                        )
288                );
289
290                // WordAds DSP API Logs routes
291                register_rest_route(
292                        static::$namespace,
293                        sprintf( '/sites/%d/wordads/dsp/api/v1/logs', $site_id ),
294                        array(
295                                'methods'             => WP_REST_Server::EDITABLE,
296                                'callback'            => array( $this, 'edit_dsp_logs' ),
297                                'permission_callback' => array( $this, 'can_user_view_dsp_callback' ),
298                        )
299                );
300        }
301
302        /**
303         * Only administrators can access the API.
304         *
305         * @return bool|WP_Error True if a blog token was used to sign the request, WP_Error otherwise.
306         */
307        public function can_user_view_dsp_callback() {
308                if (
309                        $this->is_user_connected()
310                        && current_user_can( 'manage_options' )
311                ) {
312                        return true;
313                }
314
315                return $this->get_forbidden_error();
316        }
317
318        /**
319         * Redirect GET requests to WordAds DSP for the site.
320         *
321         * @param WP_REST_Request $req The request object.
322         * @return array|WP_Error
323         */
324        public function get_blaze_posts( $req ) {
325                $site_id = $this->get_site_id();
326                if ( is_wp_error( $site_id ) ) {
327                        return array();
328                }
329
330                // We don't use sub_path in the blaze posts, only query strings
331                if ( isset( $req['sub_path'] ) ) {
332                        unset( $req['sub_path'] );
333                }
334
335                $response = $this->request_as_user(
336                        sprintf( '/sites/%d/blaze/posts%s', $site_id, $this->build_subpath_with_query_strings( $req->get_params() ) ),
337                        'v2',
338                        array( 'method' => 'GET' )
339                );
340
341                if ( is_wp_error( $response ) ) {
342                        return $response;
343                }
344
345                if ( isset( $response['posts'] ) && count( $response['posts'] ) > 0 ) {
346                        $response['posts'] = $this->add_prices_in_posts( $response['posts'] );
347                }
348
349                return $response;
350        }
351
352        /**
353         * Builds the subpath including the query string to be used in the DSP call
354         *
355         * @param array $params The request object parameters.
356         * @return string
357         */
358        private function build_subpath_with_query_strings( $params ) {
359                $sub_path = '';
360                if ( isset( $params['sub_path'] ) ) {
361                        $sub_path = $params['sub_path'];
362                        unset( $params['sub_path'] );
363                }
364
365                if ( isset( $params['rest_route'] ) ) {
366                        unset( $params['rest_route'] );
367                }
368
369                if ( ! empty( $params ) ) {
370                        $sub_path = $sub_path . '?' . http_build_query( stripslashes_deep( $params ) );
371                }
372
373                return $sub_path;
374        }
375
376        /**
377         * Redirect GET requests to WordAds DSP Blaze Posts endpoint for the site.
378         *
379         * @param WP_REST_Request $req The request object.
380         * @return array|WP_Error
381         */
382        public function get_dsp_blaze_posts( $req ) {
383                $site_id = $this->get_site_id();
384                if ( is_wp_error( $site_id ) ) {
385                        return array();
386                }
387
388                // We don't use sub_path in the blaze posts, only query strings
389                if ( isset( $req['sub_path'] ) ) {
390                        unset( $req['sub_path'] );
391                }
392
393                $response = $this->get_dsp_generic( sprintf( 'v1/wpcom/sites/%d/blaze/posts', $site_id ), $req );
394
395                if ( is_wp_error( $response ) ) {
396                        return $response;
397                }
398
399                if ( isset( $response['results'] ) && count( $response['results'] ) > 0 ) {
400                        $response['results'] = $this->add_prices_in_posts( $response['results'] );
401                }
402
403                return $response;
404        }
405
406        /**
407         * Redirect GET requests to WordAds DSP Blaze media endpoint for the site.
408         *
409         * @param WP_REST_Request $req The request object.
410         * @return array|WP_Error
411         */
412        public function get_dsp_media( $req ) {
413                $site_id = $this->get_site_id();
414                if ( is_wp_error( $site_id ) ) {
415                        return array();
416                }
417                return $this->get_dsp_generic( sprintf( 'v1/wpcom/sites/%d/media', $site_id ), $req );
418        }
419
420        /**
421         * Redirect POST requests to WordAds DSP Blaze media endpoint for the site.
422         *
423         * @return array|WP_Error
424         */
425        public function upload_image_to_current_website() {
426                $site_id = $this->get_site_id();
427                if ( is_wp_error( $site_id ) ) {
428                        return array( 'error' => $site_id->get_error_message() );
429                }
430
431                if ( empty( $_FILES['image'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
432                        return array( 'error' => 'File is missed' );
433                }
434                $file      = $_FILES['image']; // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
435                $temp_name = $file['tmp_name'] ?? ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
436                if ( ! $temp_name || ! is_uploaded_file( $temp_name ) ) {
437                        return array( 'error' => 'Specified file was not uploaded' );
438                }
439
440                // Getting the original file name.
441                $filename = sanitize_file_name( basename( $file['name'] ) );
442                // Upload contents to the Upload folder locally.
443                $upload = wp_upload_bits(
444                        $filename,
445                        null,
446                        file_get_contents( $temp_name ) // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
447                );
448
449                if ( ! empty( $upload['error'] ) ) {
450                        return array( 'error' => $upload['error'] );
451                }
452
453                // Check the type of file. We'll use this as the 'post_mime_type'.
454                $filetype = wp_check_filetype( $filename, null );
455
456                // Prepare an array of post data for the attachment.
457                $attachment = array(
458                        'guid'           => wp_upload_dir()['url'] . '/' . $filename,
459                        'post_mime_type' => $filetype['type'],
460                        'post_title'     => preg_replace( '/\.[^.]+$/', '', $filename ),
461                        'post_content'   => '',
462                        'post_status'    => 'inherit',
463                );
464
465                // Insert the attachment.
466                $attach_id = wp_insert_attachment( $attachment, $upload['file'] );
467
468                // Make sure wp_generate_attachment_metadata() has all requirement dependencies.
469                require_once ABSPATH . 'wp-admin/includes/image.php';
470
471                // Generate the metadata for the attachment, and update the database record.
472                $attach_data = wp_generate_attachment_metadata( $attach_id, $upload['file'] );
473                // Store metadata in the local DB.
474                wp_update_attachment_metadata( $attach_id, $attach_data );
475
476                return array( 'url' => $upload['url'] );
477        }
478
479        /**
480         * Redirect GET requests to WordAds DSP Blaze openverse endpoint.
481         *
482         * @param WP_REST_Request $req The request object.
483         * @return array|WP_Error
484         */
485        public function get_dsp_openverse( $req ) {
486                return $this->get_dsp_generic( 'v1/wpcom/media', $req );
487        }
488
489        /**
490         * Redirect GET requests to WordAds DSP Credits endpoint for the site.
491         *
492         * @param WP_REST_Request $req The request object.
493         * @return array|WP_Error
494         */
495        public function get_dsp_credits( $req ) {
496                return $this->get_dsp_generic( 'v1/credits', $req );
497        }
498
499        /**
500         * Redirect GET requests to WordAds DSP Experiments endpoint for the site.
501         *
502         * @param WP_REST_Request $req The request object.
503         * @return array|WP_Error
504         */
505        public function get_dsp_experiments( $req ) {
506                return $this->get_dsp_generic( 'v1/experiments', $req );
507        }
508
509        /**
510         * Redirect GET requests to WordAds DSP Campaigns endpoint for the site.
511         *
512         * @param WP_REST_Request $req The request object.
513         * @return array|WP_Error
514         */
515        public function get_dsp_campaigns( $req ) {
516                return $this->get_dsp_generic( 'v1/campaigns', $req );
517        }
518
519        /**
520         * Redirect GET requests to WordAds DSP Site Campaigns endpoint for the site.
521         *
522         * @param WP_REST_Request $req The request object.
523         * @return array|WP_Error
524         */
525        public function get_dsp_site_campaigns( $req ) {
526                $site_id = $this->get_site_id();
527                if ( is_wp_error( $site_id ) ) {
528                        return array();
529                }
530
531                return $this->get_dsp_generic( sprintf( 'v1/sites/%d/campaigns', $site_id ), $req );
532        }
533
534        /**
535         * Redirect GET requests to WordAds DSP Search endpoint for the site.
536         *
537         * @param WP_REST_Request $req The request object.
538         * @return array|WP_Error
539         */
540        public function get_dsp_search( $req ) {
541                return $this->get_dsp_generic( 'v1/search', $req );
542        }
543
544        /**
545         * Redirect GET requests to WordAds DSP User endpoint for the site.
546         *
547         * @param WP_REST_Request $req The request object.
548         * @return array|WP_Error
549         */
550        public function get_dsp_user( $req ) {
551                return $this->get_dsp_generic( 'v1/user', $req );
552        }
553
554        /**
555         * Redirect GET requests to WordAds DSP Search endpoint for the site.
556         *
557         * @param WP_REST_Request $req The request object.
558         * @return array|WP_Error
559         */
560        public function get_dsp_templates( $req ) {
561                return $this->get_dsp_generic( 'v1/templates', $req );
562        }
563
564        /**
565         * Redirect GET requests to WordAds DSP Subscriptions endpoint for the site.
566         *
567         * @param WP_REST_Request $req The request object.
568         * @return array|WP_Error
569         */
570        public function get_dsp_subscriptions( $req ) {
571                return $this->get_dsp_generic( 'v1/subscriptions', $req );
572        }
573
574        /**
575         * Redirect GET requests to WordAds DSP Payments endpoint for the site.
576         *
577         * @param WP_REST_Request $req The request object.
578         * @return array|WP_Error
579         */
580        public function get_dsp_payments( $req ) {
581                return $this->get_dsp_generic( 'v1/payments', $req );
582        }
583
584        /**
585         * Redirect GET requests to WordAds DSP Subscriptions endpoint for the site.
586         *
587         * @param WP_REST_Request $req The request object.
588         * @return array|WP_Error
589         */
590        public function get_dsp_smart( $req ) {
591                return $this->get_dsp_generic( 'v1/smart', $req );
592        }
593
594        /**
595         * Redirect GET requests to WordAds DSP Locations endpoint for the site.
596         *
597         * @param WP_REST_Request $req The request object.
598         * @return array|WP_Error
599         */
600        public function get_dsp_locations( $req ) {
601                return $this->get_dsp_generic( 'v1/locations', $req );
602        }
603
604        /**
605         * Redirect GET requests to WordAds DSP Woo endpoint for the site.
606         *
607         * @param WP_REST_Request $req The request object.
608         * @return array|WP_Error
609         */
610        public function get_dsp_woo( $req ) {
611                return $this->get_dsp_generic( 'v1/woo', $req );
612        }
613
614      �� /**
615         * Redirect GET requests to WordAds DSP Countries endpoint for the site.
616         *
617         * @param WP_REST_Request $req The request object.
618         * @return array|WP_Error
619         */
620        public function get_dsp_image( $req ) {
621                return $this->get_dsp_generic( 'v1/image', $req );
622        }
623
624        /**
625         * Redirect GET requests to WordAds DSP for the site.
626         *
627         * @param String          $path The Root API endpoint.
628         * @param WP_REST_Request $req The request object.
629         * @param array           $args Request arguments.
630         * @return array|WP_Error
631         */
632        public function get_dsp_generic( $path, $req, $args = array() ) {
633                $site_id = $this->get_site_id();
634                if ( is_wp_error( $site_id ) ) {
635                        return array();
636                }
637
638                return $this->request_as_user(
639                        sprintf( '/sites/%d/wordads/dsp/api/%s%s', $site_id, $path, $this->build_subpath_with_query_strings( $req->get_params() ) ),
640                        'v2',
641                        array_merge(
642                                $args,
643                                array( 'method' => 'GET' )
644                        )
645                );
646        }
647
648        /**
649         * Redirect POST/PUT/PATCH requests to WordAds DSP WPCOM Checkout endpoint for the site.
650         *
651         * @param WP_REST_Request $req The request object.
652         * @return array|WP_Error
653         */
654        public function edit_wpcom_checkout( $req ) {
655                return $this->edit_dsp_generic( 'v1/wpcom/checkout', $req, array( 'timeout' => 20 ) );
656        }
657
658        /**
659         * Redirect POST/PUT/PATCH requests to WordAds DSP Campaigns endpoint for the site.
660         *
661         * @param WP_REST_Request $req The request object.
662         * @return array|WP_Error
663         */
664        public function edit_dsp_campaigns( $req ) {
665                $version = $req->get_param( 'api_version' ) ?? 'v1';
666                return $this->edit_dsp_generic( "{$version}/campaigns", $req, array( 'timeout' => 20 ) );
667        }
668
669        /**
670         * Redirect POST/PUT/PATCH requests to WordAds DSP Subscriptions endpoint for the site.
671         *
672         * @param WP_REST_Request $req The request object.
673         * @return array|WP_Error
674         */
675        public function edit_dsp_subscriptions( $req ) {
676                return $this->edit_dsp_generic( 'v1/subscriptions', $req, array( 'timeout' => 20 ) );
677        }
678
679        /**
680         * Redirect POST/PUT/PATCH requests to WordAds DSP Payments endpoint for the site.
681         *
682         * @param WP_REST_Request $req The request object.
683         * @return array|WP_Error
684         */
685        public function edit_dsp_payments( $req ) {
686                return $this->edit_dsp_generic( 'v1/payments', $req, array( 'timeout' => 20 ) );
687        }
688
689        /**
690         * Redirect POST/PUT/PATCH requests to WordAds DSP Logs endpoint for the site.
691         *
692         * @param WP_REST_Request $req The request object.
693         * @return array|WP_Error
694         */
695        public function edit_dsp_logs( $req ) {
696                return $this->edit_dsp_generic( 'v1/logs', $req );
697        }
698
699        /**
700         * Redirect POST/PUT/PATCH requests to WordAds DSP Smart endpoint for the site.
701         *
702         * @param WP_REST_Request $req The request object.
703         * @return array|WP_Error
704         */
705        public function edit_dsp_smart( $req ) {
706                return $this->edit_dsp_generic( 'v1/smart', $req );
707        }
708
709        /**
710         * Redirect POST/PUT/PATCH requests to WordAds DSP for the site.
711         *
712         * @param String          $path The Root API endpoint.
713         * @param WP_REST_Request $req The request object.
714         * @param array           $args Request arguments.
715         * @return array|WP_Error
716         */
717        public function edit_dsp_generic( $path, $req, $args = array() ) {
718                $site_id = $this->get_site_id();
719                if ( is_wp_error( $site_id ) ) {
720                        return array();
721                }
722
723                return $this->request_as_user(
724                        sprintf( '/sites/%d/wordads/dsp/api/%s%s', $site_id, $path, $req->get_param( 'sub_path' ) ),
725                        'v2',
726                        array_merge(
727                                $args,
728                                array( 'method' => $req->get_method() )
729                        ),
730                        $req->get_body()
731                );
732        }
733
734        /**
735         * Will check the posts for prices and add them to the posts array
736         *
737         * @param WP_REST_Request $posts The posts object.
738         * @return array|WP_Error
739         */
740        protected function add_prices_in_posts( $posts ) {
741
742                if ( ! function_exists( 'wc_get_product' ) ||
743                        ! function_exists( 'wc_get_price_decimal_separator' ) ||
744                        ! function_exists( 'wc_get_price_thousand_separator' ) ||
745                        ! function_exists( 'wc_get_price_decimals' ) ||
746                        ! function_exists( 'get_woocommerce_price_format' ) ||
747                        ! function_exists( 'get_woocommerce_currency_symbol' )
748                ) {
749                        return $posts;
750                }
751
752                foreach ( $posts as $key => $item ) {
753                        if ( ! isset( $item['ID'] ) ) {
754                                $posts[ $key ]['price'] = '';
755                                continue;
756                        }
757                        $product = wc_get_product( $item['ID'] );
758                        if ( ! $product || ! $product instanceof WC_Product ) {
759                                $posts[ $key ]['price'] = '';
760                        } else {
761                                $price              = $product->get_price();
762                                $decimal_separator  = wc_get_price_decimal_separator();
763                                $thousand_separator = wc_get_price_thousand_separator();
764                                $decimals           = wc_get_price_decimals();
765                                $price_format       = get_woocommerce_price_format();
766                                $currency_symbol    = get_woocommerce_currency_symbol();
767
768                                // Convert to float to avoid issues on PHP 8.
769                                $price           = (float) $price;
770                                $negative        = $price < 0;
771                                $price           = $negative ? $price * -1 : $price;
772                                $price           = number_format( $price, $decimals, $decimal_separator, $thousand_separator );
773                                $formatted_price = sprintf( $price_format, $currency_symbol, $price );
774
775                                $posts[ $key ]['price'] = html_entity_decode( $formatted_price, ENT_COMPAT );
776                        }
777                }
778                return $posts;
779        }
780
781        /**
782         * Queries the WordPress.com REST API with a user token.
783         *
784         * @param String $path The API endpoint relative path.
785         * @param String $version The API version.
786         * @param array  $args Request arguments.
787         * @param String $body Request body.
788         * @param String $base_api_path (optional) the API base path override, defaults to 'rest'.
789         * @param bool   $use_cache (optional) default to true.
790         * @return array|WP_Error $response Data.
791         */
792        protected function request_as_user( $path, $version = '2', $args = array(), $body = null, $base_api_path = 'wpcom', $use_cache = false ) {
793                // Arrays are serialized without considering the order of objects, but it's okay atm.
794                $cache_key = 'BLAZE_REST_RESP_' . md5( implode( '|', array( $path, $version, wp_json_encode( $args ), wp_json_encode( $body ), $base_api_path ) ) );
795
796                if ( $use_cache ) {
797                        $response_body_content = get_transient( $cache_key );
798                        if ( false !== $response_body_content ) {
799                                return json_decode( $response_body_content, true );
800                        }
801                }
802
803                $response = Client::wpcom_json_api_request_as_user(
804                        $path,
805                        $version,
806                        $args,
807                        $body,
808                        $base_api_path
809                );
810
811                if ( is_wp_error( $response ) ) {
812                        return $response;
813                }
814
815                $response_code         = wp_remote_retrieve_response_code( $response );
816                $response_body_content = wp_remote_retrieve_body( $response );
817                $response_body         = json_decode( $response_body_content, true );
818
819                if ( 200 !== $response_code ) {
820                        return $this->get_blaze_error( $response_body, $response_code );
821                }
822
823                // Cache the successful JSON response for 5 minutes.
824                set_transient( $cache_key, $response_body_content, 5 * MINUTE_IN_SECONDS );
825                return $response_body;
826        }
827
828        /**
829         * Return a WP_Error object with a forbidden error.
830         */
831        protected function get_forbidden_error() {
832                $error_msg = esc_html__(
833                        'You are not allowed to perform this action.',
834                        'jetpack-blaze'
835                );
836
837                return new WP_Error( 'rest_forbidden', $error_msg, array( 'status' => rest_authorization_required_code() ) );
838        }
839
840        /**
841         * Build error object from remote response body and status code.
842         *
843         * @param array $response_body Remote response body.
844         * @param int   $response_code Http response code.
845         * @return WP_Error
846         */
847        protected function get_blaze_error( $response_body, $response_code = 500 ) {
848                if ( ! is_array( $response_body ) ) {
849                        $response_body = array(
850                                'errorMessage' => $response_body,
851                        );
852                }
853
854                $error_code = 'remote-error';
855                foreach ( array( 'code', 'error' ) as $error_code_key ) {
856                        if ( isset( $response_body[ $error_code_key ] ) ) {
857                                $error_code = $response_body[ $error_code_key ];
858                                break;
859                        }
860                }
861
862                $response_body['code']         = $error_code;
863                $response_body['status']       = $response_code;
864                $response_body['errorMessage'] = $response_body['errorMessage'] ?? 'Unknown remote error';
865
866                return new \WP_REST_Response( $response_body, $response_code );
867        }
868
869        /**
870         * Check if the current user is connected.
871         * On WordPress.com Simple, it is always connected.
872         *
873         * @return true
874         */
875        private function is_user_connected() {
876                if ( ( new Host() )->is_wpcom_simple() ) {
877                        return true;
878                }
879
880                $connection = new Connection_Manager();
881                return $connection->is_connected() && $connection->is_user_connected();
882        }
883
884        /**
885         * Get the site ID.
886         *
887         * @return int|WP_Error
888         */
889        private function get_site_id() {
890                return Connection_Manager::get_site_id();
891        }
892}
Note: See TracBrowser for help on using the repository browser.