Completed
Push — update/sync-v4-endpoints ( 847d73 )
by
unknown
30:45 queued 19:43
created

Endpoints::validate_queue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 10
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
/**
3
 * Sync package.
4
 *
5
 * @package  automattic/jetpack-sync
6
 */
7
8
namespace Automattic\Jetpack\Sync;
9
10
use WP_Error;
11
12
/**
13
 * This class will handle Sync v4 REST Endpoints.
14
 *
15
 * @since 9.9.0
16
 */
17
class Endpoints {
18
19
	/**
20
	 * Initialize REST routes.
21
	 */
22
	public function initialize_rest_api() {
23
24
		// Request a Full Sync.
25
		register_rest_route(
26
			'jetpack/v4',
27
			'/sync/full-sync',
28
			array(
29
				'methods'             => WP_REST_Server::EDITABLE,
30
				'callback'            => __CLASS__ . '::full_sync_start',
31
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
32
				'args'                => array(
33
					'modules'  => array(
34
						'description' => __( 'Data Modules that should be included in Full Sync', 'jetpack' ),
35
						'type'        => 'array',
36
						'required'    => false,
37
					),
38
					'users'    => array(
39
						'description' => __( 'User IDs to include in Full Sync or "initial"', 'jetpack' ),
40
						'required'    => false,
41
					),
42
					'posts'    => array(
43
						'description' => __( 'Post IDs to include in Full Sync', 'jetpack' ),
44
						'type'        => 'array',
45
						'required'    => false,
46
					),
47
					'comments' => array(
48
						'description' => __( 'Comment IDs to include in Full Sync', 'jetpack' ),
49
						'type'        => 'array',
50
						'required'    => false,
51
					),
52
				),
53
			)
54
		);
55
56
		// Obtain Sync status.
57
		register_rest_route(
58
			'jetpack/v4',
59
			'/sync/status',
60
			array(
61
				'methods'             => WP_REST_Server::READABLE,
62
				'callback'            => __CLASS__ . '::sync_status',
63
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
64
				'args'                => array(
65
					'fields' => array(
66
						'description' => __( 'Fields that should be included in status.', 'jetpack' ),
67
						'type'        => 'array',
68
						'required'    => false,
69
					),
70
				),
71
			)
72
		);
73
74
		// Obtain Sync settings.
75
		register_rest_route(
76
			'jetpack/v4',
77
			'/sync/settings',
78
			array(
79
				'methods'             => WP_REST_Server::READABLE,
80
				'callback'            => __CLASS__ . '::get_sync_settings',
81
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
82
			)
83
		);
84
85
		// Update Sync settings.
86
		register_rest_route(
87
			'jetpack/v4',
88
			'/sync/settings',
89
			array(
90
				'methods'             => WP_REST_Server::EDITABLE,
91
				'callback'            => __CLASS__ . '::get_sync_settings',
92
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
93
			)
94
		);
95
96
		// Update Sync health status.
97
		register_rest_route(
98
			'jetpack/v4',
99
			'/sync/status',
100
			array(
101
				'methods'             => WP_REST_Server::EDITABLE,
102
				'callback'            => __CLASS__ . '::sync_health',
103
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
104
				'args'                => array(
105
					'status' => array(
106
						'description' => __( 'New Sync health status', 'jetpack' ),
107
						'type'        => 'string',
108
						'required'    => false,
109
					),
110
				),
111
			)
112
		);
113
114
		// Obtain table checksums.
115
		register_rest_route(
116
			'jetpack/v4',
117
			'/sync/data-check',
118
			array(
119
				'methods'             => WP_REST_Server::READABLE,
120
				'callback'            => __CLASS__ . '::data_check',
121
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
122
			)
123
		);
124
125
		// Obtain histogram.
126
		register_rest_route(
127
			'jetpack/v4',
128
			'/sync/data-histogram',
129
			array(
130
				'methods'             => WP_REST_Server::EDITABLE,
131
				'callback'            => __CLASS__ . '::data_histogram',
132
				'permission_callback' => __CLASS__ . '::verify_default_permissions',
133
				'args'                => array(
134
					'columns'            => array(
135
						'description' => __( 'Column mappings', 'jetpack' ),
136
						'type'        => 'array',
137
						'required'    => false,
138
					),
139
					'object_type'        => array(
140
						'description' => __( 'Object Type', 'jetpack' ),
141
						'type'        => 'string',
142
						'required'    => false,
143
					),
144
					'buckets'            => array(
145
						'description' => __( 'Number of histogram buckets.', 'jetpack' ),
146
						'type'        => 'int',
147
						'required'    => false,
148
					),
149
					'start_id'           => array(
150
						'description' => __( 'Start ID for the histogram', 'jetpack' ),
151
						'type'        => 'int',
152
						'required'    => false,
153
					),
154
					'end_id'             => array(
155
						'description' => __( 'End ID for the histogram', 'jetpack' ),
156
						'type'        => 'int',
157
						'required'    => false,
158
					),
159
					'strip_non_ascii'    => array(
160
						'description' => __( 'Strip non-ascii characters?', 'jetpack' ),
161
						'type'        => 'boolean',
162
						'required'    => false,
163
					),
164
					'shared_salt'        => array(
165
						'description' => __( 'Shared Salt to use when generating checksum', 'jetpack' ),
166
						'type'        => 'string',
167
						'required'    => false,
168
					),
169
					'only_range_edges'   => array(
170
						'description' => __( 'Should only range endges be returned', 'jetpack' ),
171
						'type'        => 'boolean',
172
						'required'    => false,
173
					),
174
					'detailed_drilldown' => array(
175
						'description' => __( 'Do we want the checksum or object ids.', 'jetpack' ),
176
						'type'        => 'boolean',
177
						'required'    => false,
178
					),
179
				),
180
			)
181
		);
182
183
	}
184
185
	/**
186
	 * Trigger a Full Sync of specified modules.
187
	 *
188
	 * @since 9.9.0
189
	 *
190
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
191
	 *
192
	 * @return \WP_REST_Response|WP_Error
193
	 */
194
	public static function full_sync_start( $request ) {
195
196
		$modules = $request->get_param( 'modules' );
197
198
		// convert list of modules into array format of "$modulename => true".
199
		if ( ! empty( $modules ) ) {
200
			$modules = array_map( '__return_true', array_flip( $modules ) );
201
		}
202
203
		// Process additional options.
204
		foreach ( array( 'posts', 'comments', 'users' ) as $module_name ) {
205
			if ( 'users' === $module_name && 'initial' === $request->get_param( 'users' ) ) {
206
				$modules['users'] = 'initial';
207
			} elseif ( is_array( $request->get_param( $module_name ) ) ) {
208
				$ids = $request->get_param( $module_name );
209
				if ( count( $ids ) > 0 ) {
210
					$modules[ $module_name ] = $ids;
211
				}
212
			}
213
		}
214
215
		if ( empty( $modules ) ) {
216
			$modules = null;
217
		}
218
219
		return rest_ensure_response(
220
			array(
221
				'scheduled' => Actions::do_full_sync( $modules ),
222
			)
223
		);
224
	}
225
226
	/**
227
	 * Return Sync's status.
228
	 *
229
	 * @since 9.9.0
230
	 *
231
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
232
	 *
233
	 * @return \WP_REST_Response
234
	 */
235
	public static function sync_status( $request ) {
236
		$fields = $request->get_param( 'fields' );
237
		return rest_ensure_response( Actions::get_sync_status( $fields ) );
238
	}
239
240
	/**
241
	 * Return table checksums.
242
	 *
243
	 * @since 9.9.0
244
	 *
245
	 * @return \WP_REST_Response
246
	 */
247
	public static function data_check() {
248
		// Disable Sync during this call, so we can resolve faster.
249
		Actions::mark_sync_read_only();
250
		$store = new Replicastore();
251
		return rest_ensure_response( $store->checksum_all() );
252
	}
253
254
	/**
255
	 * Return Histogram.
256
	 *
257
	 * @since 9.9.0
258
	 *
259
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
260
	 *
261
	 * @return \WP_REST_Response
262
	 */
263
	public static function data_histogram( $request ) {
264
265
		// Disable Sync during this call, so we can resolve faster.
266
		Actions::mark_sync_read_only();
267
268
		$args = $request->get_params();
269
270
		if ( empty( $args['columns'] ) ) {
271
			$args['columns'] = null; // go with defaults.
272
		}
273
274
		if ( false !== $args['strip_non_ascii'] ) {
275
			$args['strip_non_ascii'] = true;
276
		}
277
278
		/**
279
		 * Hack: nullify the values of `start_id` and `end_id` if we're only requesting ranges.
280
		 *
281
		 * The endpoint doesn't support nullable values :(
282
		 */
283 View Code Duplication
		if ( true === $args['only_range_edges'] ) {
284
			if ( 0 === $args['start_id'] ) {
285
				$args['start_id'] = null;
286
			}
287
288
			if ( 0 === $args['end_id'] ) {
289
				$args['end_id'] = null;
290
			}
291
		}
292
293
		$store     = new Replicastore();
294
		$histogram = $store->checksum_histogram( $args['object_type'], $args['buckets'], $args['start_id'], $args['end_id'], $args['columns'], $args['strip_non_ascii'], $args['shared_salt'], $args['only_range_edges'], $args['detailed_drilldown'] );
295
296
		return rest_ensure_response(
297
			array(
298
				'histogram' => $histogram,
299
				'type'      => $store->get_checksum_type(),
300
			)
301
		);
302
	}
303
304
	/**
305
	 * Update Sync health.
306
	 *
307
	 * @since 9.9.0
308
	 *
309
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
310
	 *
311
	 * @return \WP_REST_Response
312
	 */
313
	public static function sync_health( $request ) {
314
315 View Code Duplication
		switch ( $request->get_param( 'status' ) ) {
316
			case Health::STATUS_IN_SYNC:
317
			case Health::STATUS_OUT_OF_SYNC:
318
				Health::update_status( $request->get_param( 'status' ) );
319
				break;
320
			default:
321
				return new WP_Error( 'invalid_status', 'Invalid Sync Status Provided.' );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_status'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
322
		}
323
324
		// re-fetch so we see what's really being stored.
325
		return rest_ensure_response(
326
			array(
327
				'success' => Health::get_status(),
328
			)
329
		);
330
	}
331
332
	/**
333
	 * Obtain Sync settings.
334
	 *
335
	 * @since 9.9.0
336
	 *
337
	 * @return \WP_REST_Response
338
	 */
339
	public static function get_sync_setings() {
340
		return rest_ensure_response( Settings::get_settings() );
341
	}
342
343
	/**
344
	 * Update Sync settings.
345
	 *
346
	 * @since 9.9.0
347
	 *
348
	 * @param \WP_REST_Request $request The request sent to the WP REST API.
349
	 *
350
	 * @return \WP_REST_Response
351
	 */
352 View Code Duplication
	public static function update_sync_settings( $request ) {
353
		$args = $request->get_params();
354
355
		$sync_settings = Settings::get_settings();
356
357
		foreach ( $args as $key => $value ) {
358
			if ( false !== $value ) {
359
				if ( is_numeric( $value ) ) {
360
					$value = (int) $value;
361
				}
362
363
				// special case for sending empty arrays - a string with value 'empty'.
364
				if ( 'empty' === $value ) {
365
					$value = array();
366
				}
367
368
				$sync_settings[ $key ] = $value;
369
			}
370
		}
371
372
		Settings::update_settings( $sync_settings );
373
374
		// re-fetch so we see what's really being stored.
375
		return rest_ensure_response( Settings::get_settings() );
376
	}
377
378
	/**
379
	 * Verify that request has default permissions to perform sync actions.
380
	 *
381
	 * @since 9.9.0
382
	 *
383
	 * @return bool Whether user has capability 'manage_options' or a blog token is used.
384
	 */
385 View Code Duplication
	public static function verify_default_permissions() {
386
		if ( current_user_can( 'manage_options' ) ) { // TODO || check for valid blog token.
387
			return true;
388
		}
389
390
		$error_msg = esc_html__(
391
			'You do not have the correct user permissions to perform this action.
392
			Please contact your site admin if you think this is a mistake.',
393
			'jetpack'
394
		);
395
396
		return new WP_Error( 'invalid_user_permission_sync', $error_msg, array( 'status' => rest_authorization_required_code() ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_user_permission_sync'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
397
	}
398
399
	/**
400
	 * Validate Queue name.
401
	 *
402
	 * @param string $value Queue Name.
403
	 *
404
	 * @return WP_Error
405
	 */
406 View Code Duplication
	protected function validate_queue( $value ) {
407
		if ( ! isset( $value ) ) {
408
			return new WP_Error( 'invalid_queue', 'Queue name is required', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
409
		}
410
411
		if ( ! in_array( $value, array( 'sync', 'full_sync', 'immediate' ), true ) ) {
412
			return new WP_Error( 'invalid_queue', 'Queue name should be sync, full_sync or immediate', 400 );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_queue'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
413
		}
414
		return $value;
415
	}
416
417
}
418