Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.25% covered (warning)
85.25%
208 / 244
33.33% covered (danger)
33.33%
2 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
WP_REST_Help_Center_Odie
85.25% covered (warning)
85.25%
208 / 244
33.33% covered (danger)
33.33%
2 / 6
12.46
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 register_rest_route
100.00% covered (success)
100.00%
163 / 163
100.00% covered (success)
100.00%
1 / 1
1
 send_chat_message
95.65% covered (success)
95.65%
22 / 23
0.00% covered (danger)
0.00%
0 / 1
4
 get_chat
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
2
 save_chat_message_feedback
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 get_conversations
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * WP_REST_Help_Center_Odie file.
4 *
5 * @package automattic/jetpack-help-center
6 */
7
8namespace Automattic\Jetpack\Help_Center;
9
10/**
11 * Class WP_REST_Help_Center_Odie.
12 */
13class WP_REST_Help_Center_Odie extends WP_REST_Help_Center_Controller {
14
15    /**
16     * WP_REST_Help_Center_Odie constructor.
17     *
18     * @param Wpcom_Request_Client|null $wpcom_request_client WP.com request client.
19     */
20    public function __construct( ?Wpcom_Request_Client $wpcom_request_client = null ) {
21        parent::__construct( $wpcom_request_client );
22        $this->namespace = 'help-center';
23        $this->rest_base = '/odie';
24    }
25
26    /**
27     * Register available routes.
28     */
29    public function register_rest_route() {
30        register_rest_route(
31            $this->namespace,
32            $this->rest_base . '/chat/(?P<bot_id>[a-zA-Z0-9-_]+)/(?P<chat_id>\d+)',
33            array(
34                // Get a chat. Supports pagination of messages.
35                array(
36                    'methods'             => \WP_REST_Server::READABLE,
37                    'callback'            => array( $this, 'get_chat' ),
38                    'permission_callback' => '__return_true',
39                    'args'                => array(
40                        'bot_id'           => array(
41                            'description' => __( 'The bot id to get the chat for.', 'jetpack-help-center' ),
42                            'type'        => 'string',
43                            'required'    => true,
44                        ),
45                        'chat_id'          => array(
46                            'description' => __( 'The chat id to get the chat for.', 'jetpack-help-center' ),
47                            'type'        => 'integer',
48                            'required'    => true,
49                        ),
50                        'page_number'      => array(
51                            'description' => __( 'The number of the page to retrieve, limited to 100', 'jetpack-help-center' ),
52                            'type'        => 'integer',
53                            'required'    => false,
54                            'default'     => 1,
55                        ),
56                        'items_per_page'   => array(
57                            'description' => __( 'The number of items per page.', 'jetpack-help-center' ),
58                            'type'        => 'integer',
59                            'required'    => false,
60                            'default'     => 10,
61                        ),
62                        'include_feedback' => array(
63                            'required'    => false,
64                            'type'        => 'boolean',
65                            'description' => __( 'If true, include the feedback rating value for each message in the response.', 'jetpack-help-center' ),
66                        ),
67                    ),
68                ),
69                // Add a message to a chat.
70                array(
71                    'methods'             => \WP_REST_Server::CREATABLE,
72                    'callback'            => array( $this, 'send_chat_message' ),
73                    'permission_callback' => '__return_true',
74                    'args'                => array(
75                        'bot_id'  => array(
76                            'description' => __( 'The bot id to chat with.', 'jetpack-help-center' ),
77                            'type'        => 'string',
78                            'required'    => true,
79                        ),
80                        'chat_id' => array(
81                            'description' => __( 'The chat id for the existing chat.', 'jetpack-help-center' ),
82                            'type'        => 'integer',
83                            'required'    => true,
84                        ),
85                        'message' => array(
86                            'description' => __( 'The message to add to the chat', 'jetpack-help-center' ),
87                            'type'        => 'string',
88                            'required'    => true,
89                        ),
90                        // an arbitray key/value object of data to pass to the bot
91                        'context' => array(
92                            'description' => __( 'The context to continue the chat with.', 'jetpack-help-center' ),
93                            'type'        => 'object',
94                            'required'    => false,
95                        ),
96                    ),
97                ),
98            )
99        );
100
101        register_rest_route(
102            $this->namespace,
103            $this->rest_base . '/chat/(?P<bot_id>[a-zA-Z0-9-_]+)/(?P<chat_id>\d+)/(?P<message_id>\d+)/feedback',
104            array(
105                array(
106                    'methods'             => \WP_REST_Server::CREATABLE,
107                    'callback'            => array( $this, 'save_chat_message_feedback' ),
108                    'permission_callback' => '__return_true',
109                    'args'                => array(
110                        'bot_id'       => array(
111                            'description' => __( 'The bot id to chat with.', 'jetpack-help-center' ),
112                            'type'        => 'string',
113                            'required'    => true,
114                        ),
115                        'chat_id'      => array(
116                            'description' => __( 'The chat id for the existing chat.', 'jetpack-help-center' ),
117                            'type'        => 'integer',
118                            'required'    => true,
119                        ),
120                        'message_id'   => array(
121                            'description' => __( 'The message id for the existing message.', 'jetpack-help-center' ),
122                            'type'        => 'integer',
123                            'required'    => true,
124                        ),
125                        'rating_value' => array(
126                            'description' => __( 'The feedback rating value.', 'jetpack-help-center' ),
127                            'type'        => 'integer',
128                            'required'    => true,
129                        ),
130                    ),
131                ),
132            )
133        );
134
135        register_rest_route(
136            $this->namespace,
137            $this->rest_base . '/chat/(?P<bot_id>[a-zA-Z0-9-_]+)',
138            array(
139                array(
140                    'methods'             => \WP_REST_Server::CREATABLE,
141                    'callback'            => array( $this, 'send_chat_message' ),
142                    'permission_callback' => '__return_true',
143                    'args'                => array(
144                        'bot_id'  => array(
145                            'description' => __( 'The bot id to chat with.', 'jetpack-help-center' ),
146                            'type'        => 'string',
147                            'required'    => true,
148                        ),
149                        'context' => array(
150                            'description' => __( 'The context to continue the chat with.', 'jetpack-help-center' ),
151                            'type'        => 'object',
152                            'required'    => false,
153                        ),
154                        'message' => array(
155                            'description' => __( 'The message to add to the chat', 'jetpack-help-center' ),
156                            'type'        => 'string',
157                            'required'    => true,
158                        ),
159                        'test'    => array(
160                            'description' => __( 'Whether to mark this as a test chat (a11n-only).', 'jetpack-help-center' ),
161                            'type'        => 'boolean',
162                            'required'    => false,
163                        ),
164                    ),
165                ),
166            )
167        );
168
169        register_rest_route(
170            $this->namespace,
171            $this->rest_base . '/conversations/(?P<bot_ids>[a-zA-Z0-9-_,\@]+)',
172            // Retrieve the latest conversations of a user with the specified bot (i.e. the last messages from each chat)
173            array(
174                array(
175                    'methods'             => \WP_REST_Server::READABLE,
176                    'callback'            => array( $this, 'get_conversations' ),
177                    'permission_callback' => '__return_true',
178                    'args'                => array(
179                        'bot_ids'        => array(
180                            'description' => __( 'The bot id(s) to get the conversations for, separated by commas.', 'jetpack-help-center' ),
181                            'type'        => 'string',
182                            'required'    => true,
183                        ),
184                        'page_number'    => array(
185                            'description' => __( 'The number of the page to retrieve, limited to 100', 'jetpack-help-center' ),
186                            'type'        => 'integer',
187                            'required'    => false,
188                            'default'     => 1,
189                        ),
190                        'items_per_page' => array(
191                            'description' => __( 'The number of items per page.', 'jetpack-help-center' ),
192                            'type'        => 'integer',
193                            'required'    => false,
194                            'default'     => 10,
195                        ),
196                    ),
197                ),
198            )
199        );
200    }
201
202    /**
203     * Send a message to the support chat.
204     *
205     * @param \WP_REST_Request $request The request sent to the API.
206     */
207    public function send_chat_message( \WP_REST_Request $request ) {
208        $bot_name_slug = $request->get_param( 'bot_id' );
209        $chat_id       = $request->get_param( 'chat_id' );
210        $request_body  = array(
211            'message' => $request->get_param( 'message' ),
212            'context' => $request->get_param( 'context' ) ?? array(),
213        );
214
215        foreach ( array( 'version', 'session_id', 'external_chat_provider', 'external_chat_id' ) as $optional_param ) {
216            $value = $request->get_param( $optional_param );
217            if ( null !== $value ) {
218                $request_body[ $optional_param ] = $value;
219            }
220        }
221
222        // Forward the request body to the support chat endpoint.
223        $body = $this->wpcom_request_client->request(
224            '/odie/chat/' . $bot_name_slug . '/' . $chat_id,
225            '2',
226            array(
227                'method'  => 'POST',
228                'timeout' => 60,
229            ),
230            $request_body
231        );
232
233        if ( is_wp_error( $body ) ) {
234            return $body;
235        }
236
237        $response = json_decode( wp_remote_retrieve_body( $body ) );
238
239        return rest_ensure_response( $response );
240    }
241
242    /**
243     * Get the chat messages.
244     *
245     * @param \WP_REST_Request $request The request sent to the API.
246     */
247    public function get_chat( \WP_REST_Request $request ) {
248        $bot_name_slug    = $request->get_param( 'bot_id' );
249        $chat_id          = $request->get_param( 'chat_id' );
250        $page_number      = $request['page_number'];
251        $items_per_page   = $request['items_per_page'];
252        $include_feedback = $request['include_feedback'];
253
254        $url_query_params = http_build_query(
255            array(
256                'page_number'      => $page_number,
257                'items_per_page'   => $items_per_page,
258                'include_feedback' => $include_feedback,
259                'version'          => $request->get_param( 'version' ),
260                'session_id'       => $request->get_param( 'session_id' ),
261            )
262        );
263
264        $body = $this->wpcom_request_client->request(
265            '/odie/chat/' . $bot_name_slug . '/' . $chat_id . '?' . $url_query_params
266        );
267
268        if ( is_wp_error( $body ) ) {
269            return $body;
270        }
271
272        $response = json_decode( wp_remote_retrieve_body( $body ) );
273
274        return rest_ensure_response( $response );
275    }
276
277    /**
278     * Save feedback for a chat message.
279     *
280     * @param \WP_REST_Request $request The request sent to the API.
281     */
282    public function save_chat_message_feedback( \WP_REST_Request $request ) {
283        $bot_id       = $request->get_param( 'bot_id' );
284        $chat_id      = $request->get_param( 'chat_id' );
285        $message_id   = $request->get_param( 'message_id' );
286        $rating_value = $request->get_param( 'rating_value' );
287
288        // Forward the request body to the feedback endpoint.
289        $body = $this->wpcom_request_client->request(
290            '/odie/chat/' . $bot_id . '/' . $chat_id . '/' . $message_id . '/feedback',
291            '2',
292            array( 'method' => 'POST' ),
293            array(
294                'rating_value' => $rating_value,
295            )
296        );
297
298        if ( is_wp_error( $body ) ) {
299            return $body;
300        }
301
302        $response = json_decode( wp_remote_retrieve_body( $body ) );
303
304        return rest_ensure_response( $response );
305    }
306
307    /**
308     * Get list of AI conversations.
309     *
310     * @param \WP_REST_Request $request The request sent to the API.
311     */
312    public function get_conversations( \WP_REST_Request $request ) {
313        $bot_ids           = $request->get_param( 'bot_ids' );
314        $page_number       = $request['page_number'];
315        $items_per_page    = $request['items_per_page'];
316        $truncation_method = $request['truncation_method'];
317
318        $url_query_params = http_build_query(
319            array(
320                'page_number'       => $page_number,
321                'items_per_page'    => $items_per_page,
322                'truncation_method' => $truncation_method,
323            )
324        );
325
326        $body = $this->wpcom_request_client->request(
327            '/odie/conversations/' . $bot_ids . '?' . $url_query_params
328        );
329
330        if ( is_wp_error( $body ) ) {
331            return $body;
332        }
333
334        $response = json_decode( wp_remote_retrieve_body( $body ) );
335
336        return rest_ensure_response( $response );
337    }
338}