class-rest-api.php 3.7 KB
Newer Older
1
2
<?php

3
namespace Automattic\WP\Cron_Control;
4

5
class REST_API extends Singleton {
6
7
8
9
10
11
12
	/**
	 * API SETUP
	 */
	const API_NAMESPACE = 'cron-control/v1';
	const ENDPOINT_LIST = 'events';
	const ENDPOINT_RUN  = 'event';

13
14
15
16
17
18
19
	/**
	 * PLUGIN SETUP
	 */

	/**
	 * Register hooks
	 */
20
	protected function class_init() {
21
22
23
24
25
26
27
28
29
30
31
		add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
	}

	/**
	 * PLUGIN FUNCTIONALITY
	 */

	/**
	 * Register API routes
	 */
	public function rest_api_init() {
32
		register_rest_route( self::API_NAMESPACE, '/' . self::ENDPOINT_LIST, array(
33
34
35
36
37
38
			'methods'             => 'POST',
			'callback'            => array( $this, 'get_events' ),
			'permission_callback' => array( $this, 'check_secret' ),
			'show_in_index'       => false,
		) );

39
		register_rest_route( self::API_NAMESPACE, '/' . self::ENDPOINT_RUN, array(
40
41
42
43
44
45
46
47
48
			'methods'             => 'PUT',
			'callback'            => array( $this, 'run_event' ),
			'permission_callback' => array( $this, 'check_secret' ),
			'show_in_index'       => false,
		) );
	}

	/**
	 * List events pending for the current period
49
50
	 *
	 * For monitoring and alerting, also provides the total number of pending events
51
52
	 */
	public function get_events() {
53
54
55
56
57
58
59
60
61
62
63
		$response_array = array(
			'events'               => array(),
			'orchestrate_disabled' => Events::instance()->run_disabled(),
		);

		// Include events only when automatic execution is enabled
		if ( 0 === $response_array['orchestrate_disabled'] ) {
			$response_array = array_merge( $response_array, Events::instance()->get_events() );
		}

		$response_array['endpoint'] = get_rest_url( null, self::API_NAMESPACE . '/' . self::ENDPOINT_RUN );
64
65
66
67
68

		// Provide pending event count for monitoring etc
		$response_array['total_events_pending'] = count_events_by_status( Events_Store::STATUS_PENDING );

		return rest_ensure_response( $response_array );
69
70
71
72
73
74
	}

	/**
	 * Execute a specific event
	 */
	public function run_event( $request ) {
75
76
77
78
79
80
		// Stop if event execution is blocked
		$run_disabled = Events::instance()->run_disabled();
		if ( 0 !== $run_disabled ) {
			if ( 1 === $run_disabled ) {
				$message = __( 'Automatic event execution is disabled indefinitely.', 'automattic-cron-control' );
			} else {
81
				$message = sprintf( __( 'Automatic event execution is disabled until %s UTC (%d).', 'automattic-cron-control' ), date_i18n( TIME_FORMAT, $run_disabled ), $run_disabled );
82
83
84
85
86
			}

			return rest_ensure_response( new \WP_Error( 'automatic-execution-disabled', $message, array( 'status' => 403, ) ) );
		}

87
88
89
90
91
92
93
94
95
		// Parse request for details needed to identify the event to execute
		// `$timestamp` is, unsurprisingly, the Unix timestamp the event is scheduled for
		// `$action` is the md5 hash of the action used when the event is registered
		// `$instance` is the md5 hash of the event's arguments array, which Core uses to index the `cron` option
		$event     = $request->get_json_params();
		$timestamp = isset( $event['timestamp'] ) ? absint( $event['timestamp'] ) : null;
		$action    = isset( $event['action'] ) ? trim( sanitize_text_field( $event['action'] ) ) : null;
		$instance  = isset( $event['instance'] ) ? trim( sanitize_text_field( $event['instance'] ) ) : null;

Erick Hitter's avatar
Erick Hitter committed
96
		return rest_ensure_response( run_event( $timestamp, $action, $instance ) );
97
98
99
100
101
102
103
104
105
	}

	/**
	 * Check if request is authorized
	 */
	public function check_secret( $request ) {
		$body = $request->get_json_params();

		// For now, mimic original plugin's "authentication" method. This needs to be better.
106
		if ( ! isset( $body['secret'] ) || ! hash_equals( \WP_CRON_CONTROL_SECRET, $body['secret'] ) ) {
107
			return new \WP_Error( 'no-secret', __( 'Secret must be specified with all requests', 'automattic-cron-control' ), array( 'status' => 400, ) );
108
109
110
111
112
113
114
		}

		return true;
	}
}

REST_API::instance();