Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
51.11% covered (warning)
51.11%
23 / 45
40.00% covered (danger)
40.00%
4 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_Monitor
48.78% covered (danger)
48.78%
20 / 41
40.00% covered (danger)
40.00%
4 / 10
55.83
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 delete_all_notifications_copies
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 delete_notifications_copy
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 notifications_copy_option_name
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 save_notifications_copy
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 activate_module
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 jetpack_modules_loaded
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update_option_receive_jetpack_monitor_notification
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 user_receives_notifications
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
3.01
 monitor_get_last_downtime
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2/**
3 * Module Name: Downtime Monitor
4 * Module Description: Get instant alerts if your site goes down and know when it’s back online.
5 * Sort Order: 28
6 * Recommendation Order: 10
7 * First Introduced: 2.6
8 * Requires Connection: Yes
9 * Requires User Connection: Yes
10 * Auto Activate: No
11 * Module Tags: Recommended
12 * Feature: Security
13 * Additional Search Queries: monitor, uptime, downtime, monitoring, maintenance, maintenance mode, offline, site is down, site down, down, repair, error
14 *
15 * @package automattic/jetpack
16 */
17
18use Automattic\Jetpack\Connection\Manager as Connection_Manager;
19
20if ( ! defined( 'ABSPATH' ) ) {
21    exit( 0 );
22}
23
24/**
25 * Class Jetpack_Monitor
26 *
27 * @phan-constructor-used-for-side-effects
28 */
29class Jetpack_Monitor {
30
31    /**
32     * Name of the module.
33     *
34     * @var string Name of module.
35     */
36    public $module = 'monitor';
37
38    /**
39     * Constructor.
40     */
41    public function __construct() {
42        add_action( 'jetpack_modules_loaded', array( $this, 'jetpack_modules_loaded' ) );
43        add_action( 'jetpack_activate_module_monitor', array( $this, 'activate_module' ) );
44        add_action( 'jetpack_unlinked_user', array( $this, 'delete_notifications_copy' ) );
45        add_action( 'deleted_user', array( $this, 'delete_notifications_copy' ) );
46        add_action( 'jetpack_site_before_disconnected', array( $this, 'delete_all_notifications_copies' ) );
47    }
48
49    /**
50     * Forgets every linked user's saved notification choice, while a site disconnect can still say who was linked.
51     *
52     * @since $$next-version$$
53     *
54     * @return void
55     */
56    public function delete_all_notifications_copies() {
57        $user_tokens = Jetpack_Options::get_option( 'user_tokens' );
58        foreach ( array_keys( is_array( $user_tokens ) ? $user_tokens : array() ) as $user_id ) {
59            $this->delete_notifications_copy( $user_id );
60        }
61    }
62
63    /**
64     * Forgets a user's saved notification choice, which belongs to the WordPress.com account they had linked.
65     *
66     * @since $$next-version$$
67     *
68     * @param int $user_id User ID.
69     *
70     * @return void
71     */
72    public function delete_notifications_copy( $user_id ) {
73        delete_option( self::notifications_copy_option_name( $user_id ) );
74    }
75
76    /**
77     * Name of the option holding a user's local copy of their notification choice.
78     *
79     * @since $$next-version$$
80     *
81     * @param int $user_id User ID.
82     *
83     * @return string
84     */
85    public static function notifications_copy_option_name( $user_id ) {
86        return 'monitor_receive_notifications' . (int) $user_id;
87    }
88
89    /**
90     * Saves the current user's notification choice where Jetpack_Core_Json_Api_Endpoints::get_remote_value reads it.
91     *
92     * @since $$next-version$$
93     *
94     * @param bool $enabled Whether the current user receives notifications.
95     *
96     * @return void
97     */
98    public static function save_notifications_copy( $enabled ) {
99        // An integer: see Jetpack_Core_Json_Api_Endpoints::get_remote_value.
100        update_option( self::notifications_copy_option_name( get_current_user_id() ), (int) (bool) $enabled );
101    }
102
103    /**
104     * Runs upon module activation.
105     *
106     * @return void
107     */
108    public function activate_module() {
109        if ( ( new Connection_Manager( 'jetpack' ) )->is_user_connected() ) {
110            self::update_option_receive_jetpack_monitor_notification( true );
111        }
112    }
113
114    /**
115     * Runs on the jetpack_modules_loaded hook to enable configuation.
116     *
117     * @return void
118     */
119    public function jetpack_modules_loaded() {
120        Jetpack::enable_module_configurable( $this->module );
121    }
122
123    /**
124     * Whether to receive the notifications.
125     *
126     * @param bool $value `true` to enable notifications, `false` to disable them.
127     *
128     * @return bool
129     */
130    public function update_option_receive_jetpack_monitor_notification( $value ) {
131        $xml = new Jetpack_IXR_Client(
132            array(
133                'user_id' => get_current_user_id(),
134            )
135        );
136        $xml->query( 'jetpack.monitor.setNotifications', (bool) $value );
137
138        if ( $xml->isError() ) {
139            wp_die( sprintf( '%s: %s', esc_html( $xml->getErrorCode() ), esc_html( $xml->getErrorMessage() ) ) );
140        }
141
142        self::save_notifications_copy( $value );
143
144        return true;
145    }
146
147    /**
148     * Checks the status of notifications for current Jetpack site user.
149     *
150     * @since 2.8
151     * @since 4.1.0 New parameter $die_on_error.
152     *
153     * @param bool $die_on_error Whether to issue a wp_die when an error occurs or return a WP_Error object.
154     *
155     * @return boolean|WP_Error
156     */
157    public static function user_receives_notifications( $die_on_error = true ) {
158        $xml = new Jetpack_IXR_Client(
159            array(
160                'user_id' => get_current_user_id(),
161            )
162        );
163        $xml->query( 'jetpack.monitor.isUserInNotifications' );
164
165        if ( $xml->isError() ) {
166            if ( $die_on_error ) {
167                wp_die( sprintf( '%s: %s', esc_html( $xml->getErrorCode() ), esc_html( $xml->getErrorMessage() ) ), 400 );
168            } else {
169                return new WP_Error( $xml->getErrorCode(), $xml->getErrorMessage(), array( 'status' => 400 ) );
170            }
171        }
172        return $xml->getResponse();
173    }
174
175    /**
176     * Returns date of the last downtime.
177     *
178     * @since 4.0.0
179     * @return string date in YYYY-MM-DD HH:mm:ss format
180     */
181    public function monitor_get_last_downtime() {
182        $xml = new Jetpack_IXR_Client();
183
184        $xml->query( 'jetpack.monitor.getLastDowntime' );
185
186        if ( $xml->isError() ) {
187            return new WP_Error( 'monitor-downtime', $xml->getErrorMessage() );
188        }
189
190        set_transient( 'monitor_last_downtime', $xml->getResponse(), 10 * MINUTE_IN_SECONDS );
191
192        return $xml->getResponse();
193    }
194}
195
196new Jetpack_Monitor();
197
198// Register Jetpack Monitor abilities (WordPress Abilities API, WP 6.9+).
199\Automattic\Jetpack\Plugin\Abilities\Monitor_Abilities::init();