PluginProbe
Code Snippets / 4.0.0-beta.1
Code Snippets v4.0.0-beta.1
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / php / REST_API / Cloud / Cloud_Snippets_REST_Controller.php

Cloud_Snippets_REST_Controller.php in Code Snippets 4.0.0-beta.1, at php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php

368 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Code_Snippets\REST_API\Cloud;
4
5 use Code_Snippets\Client\Cloud_API;
6 use Code_Snippets\Model\Cloud_Link;
7 use Code_Snippets\Model\Snippet;
8 use Code_Snippets\REST_API\REST_Collection_Controller;
9 use WP_Error;
10 use WP_REST_Request;
11 use WP_REST_Response;
12 use WP_REST_Server;
13 use function Code_Snippets\save_snippet;
14
15 /**
16 * Allows fetching cloud snippets through the WordPress REST API.
17 *
18 * @package Code_Snippets
19 */
20 final class Cloud_Snippets_REST_Controller extends Cloud_Collection_REST_Controller {
21
22 /**
23 * Current API version.
24 */
25 public const VERSION = 1;
26
27 /**
28 * The base of this controller's route.
29 */
30 public const BASE_ROUTE = 'cloud/snippets';
31
32 /**
33 * Common filter args shared across search and featured endpoints.
34 *
35 * Each filter accepts a single numeric ID (e.g. category=12). The cloud API
36 * resolves IDs to the underlying name/slug.
37 *
38 * @return array<string, array<string, mixed>>
39 */
40 private function get_filter_args(): array {
41 return [
42 'category' => [
43 'description' => esc_html__( 'Filter by category ID.', 'code-snippets' ),
44 'type' => 'string',
45 'default' => '',
46 ],
47 'type' => [
48 'description' => esc_html__( 'Filter by language/type ID.', 'code-snippets' ),
49 'type' => 'string',
50 'default' => '',
51 ],
52 'status' => [
53 'description' => esc_html__( 'Filter by status ID.', 'code-snippets' ),
54 'type' => 'string',
55 'default' => '',
56 ],
57 ];
58 }
59
60 /**
61 * Extract filter values from a request.
62 *
63 * @param WP_REST_Request $request Request object.
64 *
65 * @return array<string, string>
66 */
67 private function extract_filters( WP_REST_Request $request ): array {
68 return array_filter(
69 [
70 'category' => $request->get_param( 'category' ) ?? '',
71 'type' => $request->get_param( 'type' ) ?? '',
72 'status' => $request->get_param( 'status' ) ?? '',
73 ]
74 );
75 }
76
77 /**
78 * Register REST routes.
79 */
80 public function register_routes() {
81 $collection_args = $this->get_collection_params();
82 $collection_args['per_page']['default'] = $this->get_snippets_per_page();
83 $filter_args = $this->get_filter_args();
84
85 register_rest_route(
86 $this->namespace,
87 $this->rest_base,
88 [
89 [
90 'methods' => WP_REST_Server::READABLE,
91 'callback' => [ $this, 'get_items' ],
92 'permission_callback' => [ $this, 'get_items_permissions_check' ],
93 'args' => array_merge(
94 $collection_args,
95 $filter_args,
96 [
97 'query' => [
98 'description' => esc_html__( 'Search query.', 'code-snippets' ),
99 'type' => 'string',
100 'required' => true,
101 ],
102 'searchByCodevault' => [
103 'description' => esc_html__( 'Treat the search query as the name of a CodeVault instead of a search term.', 'code-snippets' ),
104 'type' => 'boolean',
105 'default' => false,
106 ],
107 'page' => [
108 'description' => esc_html__( 'Page number.', 'code-snippets' ),
109 'type' => 'integer',
110 'default' => 1,
111 ],
112 ]
113 ),
114 ],
115 'schema' => [ $this, 'get_item_schema' ],
116 ]
117 );
118
119 register_rest_route(
120 $this->namespace,
121 $this->rest_base,
122 [
123 [
124 'methods' => WP_REST_Server::CREATABLE,
125 'callback' => [ $this, 'create_item_from_cloud' ],
126 'permission_callback' => [ $this, 'create_item_permissions_check' ],
127 'args' => rest_get_endpoint_args_for_schema( $this->get_cloud_snippet_schema() ),
128 ],
129 'schema' => [ $this, 'get_cloud_snippet_schema' ],
130 ]
131 );
132
133 register_rest_route(
134 $this->namespace,
135 $this->rest_base . '/featured',
136 [
137 [
138 'methods' => WP_REST_Server::READABLE,
139 'callback' => [ $this, 'get_featured_items' ],
140 'permission_callback' => [ $this, 'get_items_permissions_check' ],
141 'args' => array_merge(
142 $filter_args,
143 [
144 'page' => [
145 'description' => esc_html__( 'Page number.', 'code-snippets' ),
146 'type' => 'integer',
147 'default' => 1,
148 ],
149 'per_page' => [
150 'description' => esc_html__( 'Results per page.', 'code-snippets' ),
151 'type' => 'integer',
152 'default' => $this->get_snippets_per_page(),
153 ],
154 ]
155 ),
156 ],
157 'schema' => [ $this, 'get_item_schema' ],
158 ]
159 );
160
161 register_rest_route(
162 $this->namespace,
163 $this->rest_base . '/(?P<id>\d+)/download',
164 [
165 [
166 'methods' => WP_REST_Server::CREATABLE,
167 'callback' => [ $this, 'download_item' ],
168 'permission_callback' => [ $this, 'create_item_permissions_check' ],
169 'args' => [
170 'id' => [
171 'description' => esc_html__( 'Cloud snippet ID.', 'code-snippets' ),
172 'type' => 'number',
173 'required' => true,
174 ],
175 ],
176 ],
177 ]
178 );
179 }
180
181 /**
182 * Retrieve cloud snippets using a search query.
183 *
184 * @param WP_REST_Request $request The request object containing the search parameters.
185 *
186 * @return WP_REST_Response
187 */
188 public function get_items( $request ): WP_REST_Response {
189 $method = $request->get_param( 'searchByCodevault' ) ? 'codevault' : 'term';
190 $query = $request->get_param( 'query' );
191 $query_params = $request->get_query_params();
192 $page = max( 1, (int) $request->get_param( 'page' ) );
193 $per_page = isset( $query_params['per_page'] )
194 ? min( Cloud_API::MAX_RESULTS_PER_PAGE, max( 1, (int) $request->get_param( 'per_page' ) ) )
195 : $this->get_snippets_per_page();
196
197 $filters = $this->extract_filters( $request );
198 $cloud_snippets = $this->cloud_api->fetch_search_results( $method, $query, $page, $per_page, $filters );
199 return $cloud_snippets->to_rest_response();
200 }
201
202 /**
203 * Retrieve featured snippets from the cloud API.
204 *
205 * @param WP_REST_Request $request The request object.
206 *
207 * @return WP_REST_Response
208 */
209 public function get_featured_items( WP_REST_Request $request ): WP_REST_Response {
210 $page = max( 1, (int) $request->get_param( 'page' ) );
211 $query_params = $request->get_query_params();
212
213 $per_page = isset( $query_params['per_page'] )
214 ? min( Cloud_API::MAX_RESULTS_PER_PAGE, max( 1, (int) $request->get_param( 'per_page' ) ) )
215 : $this->get_snippets_per_page();
216
217 $filters = $this->extract_filters( $request );
218 $cloud_snippets = $this->cloud_api->get_featured_snippets( $page, $per_page, $filters );
219 return $cloud_snippets->to_rest_response();
220 }
221
222 /**
223 * Retrieve available snippet types (languages) from the cloud API.
224 *
225 * @return WP_REST_Response
226 */
227 public function get_types(): WP_REST_Response {
228 return rest_ensure_response( $this->cloud_api->get_cloud_types() );
229 }
230
231 /**
232 * Retrieve available snippet categories from the cloud API.
233 *
234 * @return WP_REST_Response
235 */
236 public function get_categories(): WP_REST_Response {
237 return rest_ensure_response( $this->cloud_api->get_cloud_categories() );
238 }
239
240 /**
241 * Get the user's snippets per-page preference for Screen Options pagination.
242 *
243 * @return int
244 */
245 private function get_snippets_per_page(): int {
246 $per_page = (int) get_user_option( 'snippets_per_page' );
247
248 return $per_page > 0 ? min( Cloud_API::MAX_RESULTS_PER_PAGE, $per_page ) : 10;
249 }
250
251 /**
252 * Get the schema for a cloud snippet request body.
253 *
254 * @return array
255 */
256 public function get_cloud_snippet_schema(): array {
257 static $schema = null;
258
259 if ( ! is_null( $schema ) ) {
260 return $schema;
261 }
262
263 $schema = [
264 '$schema' => 'http://json-schema.org/draft-04/schema#',
265 'title' => 'cloud snippet',
266 'type' => 'object',
267 'properties' => [
268 'id' => [
269 'description' => esc_html__( 'Cloud snippet identifier.', 'code-snippets' ),
270 'type' => 'string',
271 ],
272 'name' => [
273 'description' => esc_html__( 'Title of cloud snippet.', 'code-snippets' ),
274 'type' => 'string',
275 ],
276 'description' => [
277 'description' => esc_html__( 'Descriptive text associated with snippet.', 'code-snippets' ),
278 'type' => 'string',
279 ],
280 'code' => [
281 'description' => esc_html__( 'Executable snippet code.', 'code-snippets' ),
282 'type' => 'string',
283 ],
284 'scope' => [
285 'description' => esc_html__( 'Context in which the snippet is executable.', 'code-snippets' ),
286 'type' => 'string',
287 ],
288 'created' => [
289 'description' => esc_html__( 'Date and time when the snippet was last created, in ISO format.', 'code-snippets' ),
290 'type' => 'string',
291 ],
292 'revision' => [
293 'description' => esc_html__( 'Snippet revision number.', 'code-snippets' ),
294 'type' => 'integer',
295 ],
296 ],
297 ];
298
299 return $schema;
300 }
301
302 /**
303 * Create one item from the collection
304 *
305 * @param WP_REST_Request $request Full data about the request.
306 *
307 * @return WP_REST_Response|WP_Error
308 */
309 public function create_item( $request ) {
310 $body = json_decode( $request->get_body() );
311 $snippet_data = json_decode( $body[0], true );
312
313 $snippet = new Snippet();
314
315 $snippet->name = $snippet_data['name'];
316 $snippet->desc = $snippet_data['description'];
317 $snippet->code = $snippet_data['code'];
318 $snippet->scope = $snippet_data['scope'];
319 $snippet->modified = $snippet_data['created'];
320 $snippet->revision = $snippet_data['revision'] ?? 1;
321 $snippet->cloud_id = $snippet_data['id'] . '_0'; // Set to not owner.
322 $snippet->shared_network = false;
323 $snippet->network = false;
324 $snippet->active = false;
325
326 $result = save_snippet( $snippet );
327
328 if ( ! $result ) {
329 return new WP_Error(
330 'rest_cannot_create',
331 __( 'The snippet could not be created.', 'code-snippets' ),
332 [ 'status' => 500 ]
333 );
334 }
335
336 $link = new Cloud_Link();
337 $link->local_id = $snippet_data['id'];
338 $link->cloud_id = $snippet->cloud_id;
339 $link->is_owner = false;
340 $link->in_codevault = false;
341 $link->update_available = false;
342
343 $this->cloud_api->add_cloud_link( $link );
344
345 $response = [
346 'status' => 'success',
347 'message' => __( 'Snippet created', 'code-snippets' ),
348 ];
349
350 return rest_ensure_response( $response );
351 }
352
353 /**
354 * Download a single cloud snippet.
355 *
356 * @param WP_REST_Request $request The request object containing the search parameters.
357 *
358 * @return WP_REST_Response
359 */
360 public function download_item( WP_REST_Request $request ): WP_REST_Response {
361 $id = $request->get_param( 'id' );
362 $in_codevault = $request->get_param( 'in_codevault' );
363
364 $cloud_snippet = $this->cloud_api->get_single_snippet_from_cloud( $id );
365 return rest_ensure_response( $this->cloud_api->download_snippet_from_cloud( $cloud_snippet, $in_codevault ) );
366 }
367 }
368