Completed
Push — add/blog-token-self-heal ( 8b31a7...74b013 )
by
unknown
44:31 queued 37:04
created

Invalid_Blog_Token   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 2

Importance

Changes 0
Metric Value
wmc 17
lcom 3
cbo 2
dl 0
loc 150
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 37 8
A admin_notice() 0 12 2
A jetpack_react_dashboard_error() 0 9 1
A should_self_heal() 0 3 2
A lock_attempts() 0 3 1
A unlock_attempts() 0 3 1
A refresh_blog_token() 0 18 2
1
<?php
2
/**
3
 * The Jetpack Connection error handler class for invalid blog tokens
4
 *
5
 * @package automattic/jetpack-connection
6
 */
7
8
namespace Automattic\Jetpack\Connection\Error_Handlers;
9
10
use Automattic\Jetpack\Connection\Manager;
11
use Automattic\Jetpack\Connection\Error_Handler;
12
13
/**
14
 * This class handles all the error codes that indicates a broken blog token and
15
 * suggests the user to reconnect.
16
 *
17
 * @since 8.7.0
18
 */
19
class Invalid_Blog_Token {
20
21
	/**
22
	 * Number of times we will try to regenerate the blog token
23
	 *
24
	 * @var integer
25
	 */
26
	private $max_heal_attempts = 1000;
27
28
	/**
29
	 * Name of the option where we store the number of attempts to self heal
30
	 *
31
	 * @var string
32
	 */
33
	private $attempts_option_name = '_jetpack_connection_blog_token_heal_attempts';
34
35
	/**
36
	 * Set up hooks
37
	 *
38
	 * @since 8.7.0
39
	 *
40
	 * @param array $errors The array containing verified errors stored in the database.
41
	 */
42
	public function __construct( $errors ) {
43
44
		/**
45
		 * Filters the message to be displayed in the admin notices area when there's a invalid blog token xmlrpc error
46
		 *
47
		 * Return an empty value to disable the message.
48
		 *
49
		 * @since 8.7.0
50
		 *
51
		 * @param string $message The error message.
52
		 */
53
		$this->message = apply_filters( 'jetpack_connection_invalid_blog_token_admin_notice', __( 'Your connection with WordPress.com seems to be broken. If you\'re experiencing issues, please try reconnecting.', 'jetpack' ) );
0 ignored issues
show
Bug introduced by
The property message does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
54
55
		if ( empty( $this->message ) ) {
56
			return;
57
		}
58
59
		// In this class, we will only handle errors with the blog token, so ignoring if there are only errors with user tokens.
60
		if ( ! isset( $errors[0] ) && ! isset( $errors['invalid'] ) ) {
61
			return;
62
		}
63
64
		$this->attempts = (int) get_option( $this->attempts_option_name );
0 ignored issues
show
Bug introduced by
The property attempts does not seem to exist. Did you mean max_heal_attempts?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
65
66
		if ( $this->should_self_heal() ) {
67
			$this->refresh_blog_token();
68
		}
69
70
		add_action( 'react_connection_errors_initial_state', array( $this, 'jetpack_react_dashboard_error' ) );
71
		// do not add admin notice to the jetpack dashboard.
72
		global $pagenow;
73
		if ( 'admin.php' === $pagenow || isset( $_GET['page'] ) && 'jetpack' === $_GET['page'] ) { // phpcs:ignore
74
			return;
75
		}
76
		add_action( 'admin_notices', array( $this, 'admin_notice' ) );
77
78
	}
79
80
	/**
81
	 * Prints an admin notice for the blog token error
82
	 *
83
	 * @since 8.7.0
84
	 *
85
	 * @return void
86
	 */
87
	public function admin_notice() {
88
89
		if ( ! current_user_can( 'jetpack_connect' ) ) {
90
			return;
91
		}
92
93
		?>
94
		<div class="notice notice-error is-dismissible jetpack-message jp-connect" style="display:block !important;">
95
			<p><?php echo esc_html( $this->message ); ?></p>
96
		</div>
97
		<?php
98
	}
99
100
	/**
101
	 * Adds the error message to the Jetpack React Dashboard
102
	 *
103
	 * @param array $errors The array of errors.
104
	 * @return array
105
	 */
106
	public function jetpack_react_dashboard_error( $errors ) {
107
108
		$errors[] = array(
109
			'code'    => 'invalid_blog_token',
110
			'message' => $this->message,
111
			'action'  => 'reconnect',
112
		);
113
		return $errors;
114
	}
115
116
	/**
117
	 * Checks the number of healing attempts and returns a boolean indicating if we should
118
	 * try again or not
119
	 *
120
	 * @return boolean
121
	 */
122
	public function should_self_heal() {
123
		return $this->attempts > 0 && $this->attempts < $this->max_heal_attempts;
0 ignored issues
show
Bug introduced by
The property attempts does not seem to exist. Did you mean max_heal_attempts?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
124
	}
125
126
	/**
127
	 * Lock attempts
128
	 *
129
	 * @return void
130
	 */
131
	private function lock_attempts() {
132
		update_option( $this->attempts_option_name, -1 );
133
	}
134
135
	/**
136
	 * Unlock attempts
137
	 *
138
	 * @return void
139
	 */
140
	private function unlock_attempts() {
141
		update_option( $this->attempts_option_name, $this->attempts );
0 ignored issues
show
Bug introduced by
The property attempts does not seem to exist. Did you mean max_heal_attempts?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
142
	}
143
144
	/**
145
	 * Tries to register the site again and refresh the blog token
146
	 *
147
	 * @return void
148
	 */
149
	public function refresh_blog_token() {
150
151
		$this->lock_attempts();
152
153
		$manager = new Manager();
154
155
		$heal = $manager->register();
156
		l( $heal );
157
158
		$this->attempts ++;
0 ignored issues
show
Bug introduced by
The property attempts does not seem to exist. Did you mean max_heal_attempts?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
159
160
		if ( true === $heal ) {
161
			Error_Handler::get_instance()->delete_all_errors();
162
			delete_option( $this->attempts_option_name );
163
		} else {
164
			$this->unlock_attempts();
165
		}
166
	}
167
168
}
169