Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 163
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Share_Status_Controller
0.00% covered (danger)
0.00%
0 / 161
0.00% covered (danger)
0.00%
0 / 7
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 register_routes
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 1
2
 get_items
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
12
 get_items_permissions_check
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_share_item_schema
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
2
 get_item_schema
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
2
 receive_share_status
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
72
1<?php
2/**
3 * The Jetpack Social Controller class.
4 *
5 * @package automattic/jetpack-publicize
6 */
7
8namespace Automattic\Jetpack\Publicize\REST_API;
9
10use Automattic\Jetpack\Connection\Rest_Authentication;
11use Automattic\Jetpack\Connection\Traits\WPCOM_REST_API_Proxy_Request;
12use Automattic\Jetpack\Publicize\Share_Status;
13use WP_Error;
14use WP_REST_Request;
15use WP_REST_Response;
16use WP_REST_Server;
17
18if ( ! defined( 'ABSPATH' ) ) {
19    exit( 0 );
20}
21
22/**
23 * Jetpack Social Controller class.
24 *
25 * @phan-constructor-used-for-side-effects
26 */
27class Share_Status_Controller extends Base_Controller {
28
29    use WPCOM_REST_API_Proxy_Request;
30
31    /**
32     * Constructor.
33     */
34    public function __construct() {
35        parent::__construct();
36
37        $this->base_api_path = 'wpcom';
38        $this->version       = 'v2';
39
40        $this->namespace = "{$this->base_api_path}/{$this->version}";
41        $this->rest_base = 'publicize/share-status';
42
43        add_action( 'rest_api_init', array( $this, 'register_routes' ) );
44    }
45
46    /**
47     * Register the routes.
48     */
49    public function register_routes() {
50        register_rest_route(
51            $this->namespace,
52            '/' . $this->rest_base,
53            array(
54                array(
55                    'methods'             => WP_REST_Server::READABLE,
56                    'callback'            => array( $this, 'get_items' ),
57                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
58                    'args'                => array(
59                        'post_id' => array(
60                            'type'        => 'integer',
61                            'required'    => true,
62                            'description' => __( 'The post ID to filter the items by.', 'jetpack-publicize-pkg' ),
63                        ),
64                    ),
65                ),
66                'schema' => array( $this, 'get_public_item_schema' ),
67            )
68        );
69        register_rest_route(
70            $this->namespace,
71            '/' . $this->rest_base . '/sync',
72            array(
73                array(
74                    'methods'             => WP_REST_Server::CREATABLE,
75                    'callback'            => array( $this, 'receive_share_status' ),
76                    'permission_callback' => array( Rest_Authentication::class, 'is_signed_with_blog_token' ),
77                    'args'                => array(
78                        'post_id' => array(
79                            'type'        => 'integer',
80                            'required'    => true,
81                            'description' => __( 'The post ID to update the data for.', 'jetpack-publicize-pkg' ),
82                        ),
83                        'shares'  => array(
84                            'type'        => 'array',
85                            'required'    => true,
86                            'description' => __( 'The share status items.', 'jetpack-publicize-pkg' ),
87                            'items'       => array(
88                                'type'       => 'object',
89                                'properties' => $this->get_share_item_schema(),
90                            ),
91                        ),
92                    ),
93                ),
94            )
95        );
96    }
97
98    /**
99     * Get Jetpack Social data.
100     *
101     * @param WP_REST_Request $request Full details about the request.
102     * @return WP_REST_Response|WP_Error
103     */
104    public function get_items( $request ) {
105        $post_id = $request->get_param( 'post_id' );
106
107        $post = get_post( $post_id );
108
109        if ( empty( $post ) ) {
110            return new WP_Error(
111                'post_not_found',
112                __( 'Cannot find that post.', 'jetpack-publicize-pkg' ),
113                array( 'status' => 404 )
114            );
115        }
116
117        if ( 'publish' !== $post->post_status ) {
118            return new WP_Error(
119                'post_not_published',
120                __( 'Cannot get share status for an unpublished post', 'jetpack-publicize-pkg' ),
121                array( 'status' => 400 )
122            );
123        }
124
125        return rest_ensure_response( Share_Status::get_post_share_status( $post_id ) );
126    }
127
128    /**
129     * Verify that the request has access to Jetpack Social data.
130     *
131     * @param WP_REST_Request $request Full details about the request.
132     * @return true|WP_Error
133     */
134    public function get_items_permissions_check( $request ) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
135        return $this->publicize_permissions_check();
136    }
137
138    /**
139     * Schema for a share item.
140     *
141     * @return array
142     */
143    public function get_share_item_schema() {
144        return array(
145            'status'          => array(
146                'description' => __( 'Status of the share.', 'jetpack-publicize-pkg' ),
147                'type'        => 'string',
148            ),
149            'message'         => array(
150                'description' => __( 'Share message or link.', 'jetpack-publicize-pkg' ),
151                'type'        => 'string',
152            ),
153            'timestamp'       => array(
154                'description' => __( 'Timestamp of the share.', 'jetpack-publicize-pkg' ),
155                'type'        => 'integer',
156            ),
157            'service'         => array(
158                'description' => __( 'The service to which it was shared.', 'jetpack-publicize-pkg' ),
159                'type'        => 'string',
160            ),
161            'connection_id'   => array(
162                'description' => __( 'Connection ID for the share.', 'jetpack-publicize-pkg' ),
163                'type'        => 'integer',
164            ),
165            'external_id'     => array(
166                'description' => __( 'External ID of the shared post.', 'jetpack-publicize-pkg' ),
167                'type'        => 'string',
168            ),
169            'external_name'   => array(
170                'description' => __( 'External name of the shared post.', 'jetpack-publicize-pkg' ),
171                'type'        => 'string',
172            ),
173            'profile_picture' => array(
174                'description' => __( 'Profile picture URL of the account sharing.', 'jetpack-publicize-pkg' ),
175                'type'        => 'string',
176            ),
177            'profile_link'    => array(
178                'description' => __( 'Profile link of the sharing account.', 'jetpack-publicize-pkg' ),
179                'type'        => 'string',
180            ),
181            'wpcom_user_id'   => array(
182                'type'        => 'integer',
183                'description' => __( 'wordpress.com ID of the user the connection belongs to.', 'jetpack-publicize-pkg' ),
184            ),
185        );
186    }
187
188    /**
189     * Schema for the endpoint.
190     *
191     * @return array
192     */
193    public function get_item_schema() {
194        $schema = array(
195            '$schema'    => 'http://json-schema.org/draft-04/schema#',
196            'title'      => 'jetpack-social-share-status',
197            'type'       => 'object',
198            'properties' => array(
199                'shares' => array(
200                    'description' => __( 'List of shares.', 'jetpack-publicize-pkg' ),
201                    'type'        => 'array',
202                    'items'       => array(
203                        'type'       => 'object',
204                        'properties' => $this->get_share_item_schema(),
205                    ),
206                ),
207                'done'   => array(
208                    'description' => __( 'Indicates if the process is completed.', 'jetpack-publicize-pkg' ),
209                    'type'        => 'boolean',
210                ),
211            ),
212        );
213
214        return $this->add_additional_fields_schema( $schema );
215    }
216
217    /**
218     * Receive share status from WPCOM.
219     *
220     * @param WP_REST_Request $request Full details about the request.
221     * @return WP_REST_Response|WP_Error
222     */
223    public function receive_share_status( $request ) {
224
225        $post_id = $request->get_param( 'post_id' );
226        $post    = get_post( $post_id );
227
228        if ( empty( $post ) ) {
229            return new WP_Error(
230                'post_not_found',
231                __( 'Cannot find that post.', 'jetpack-publicize-pkg' ),
232                array( 'status' => 404 )
233            );
234        }
235
236        if ( 'publish' !== $post->post_status ) {
237            return new WP_Error(
238                'post_not_published',
239                __( 'Cannot update share status for an unpublished post.', 'jetpack-publicize-pkg' ),
240                array( 'status' => 400 )
241            );
242        }
243
244        $shares = $request->get_param( 'shares' );
245
246        // This check ensures that the shares data is in the expected format.
247        if ( ! empty( $shares ) && empty( $shares[0]['status'] ) ) {
248            return new WP_Error(
249                'invalid_shares',
250                __( 'Invalid shares data.', 'jetpack-publicize-pkg' ),
251                array( 'status' => 400 )
252            );
253        }
254
255        update_post_meta( $post_id, Share_Status::SHARES_META_KEY, $shares );
256
257        $urls = array();
258
259        foreach ( $shares as $share ) {
260            if ( isset( $share['status'] ) && 'success' === $share['status'] ) {
261                $urls[] = array(
262                    'url'     => $share['message'],
263                    'service' => $share['service'],
264                );
265            }
266        }
267
268        /**
269         * Fires after Publicize Shares post meta has been saved.
270         *
271         * @param array $urls {
272         *     An array of social media shares.
273         *     @type array $url URL to the social media post.
274         *     @type string $service Social media service shared to.
275         * }
276         */
277        do_action( 'jetpack_publicize_share_urls_saved', $urls );
278
279        return rest_ensure_response( new WP_REST_Response() );
280    }
281}