Completed
Pull Request — master (#1224)
by
unknown
02:13
created

get_webhook_status_message()   B

Complexity

Conditions 9
Paths 4

Size

Total Lines 71

Duplication

Lines 28
Ratio 39.44 %

Importance

Changes 0
Metric Value
cc 9
nc 4
nop 0
dl 28
loc 71
rs 7.0771
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Class WC_Stripe_Webhook_State.
8
 *
9
 * Tracks the most recent successful and unsuccessful webhooks in test and live modes.
10
 * @since 4.4.2
11
 */
12
class WC_Stripe_Webhook_State {
13
	const OPTION_LIVE_MONITORING_BEGAN_AT = 'wc_stripe_wh_monitor_began_at';
14
	const OPTION_LIVE_LAST_SUCCESS_AT     = 'wc_stripe_wh_last_success_at';
15
	const OPTION_LIVE_LAST_FAILURE_AT     = 'wc_stripe_wh_last_failure_at';
16
	const OPTION_LIVE_LAST_ERROR          = 'wc_stripe_wh_last_error';
17
18
	const OPTION_TEST_MONITORING_BEGAN_AT = 'wc_stripe_wh_test_monitor_began_at';
19
	const OPTION_TEST_LAST_SUCCESS_AT     = 'wc_stripe_wh_test_last_success_at';
20
	const OPTION_TEST_LAST_FAILURE_AT     = 'wc_stripe_wh_test_last_failure_at';
21
	const OPTION_TEST_LAST_ERROR          = 'wc_stripe_wh_test_last_error';
22
23
	const VALIDATION_SUCCEEDED                 = 'validation_succeeded';
24
	const VALIDATION_FAILED_HEADERS_NULL       = 'headers_null';
25
	const VALIDATION_FAILED_BODY_NULL          = 'body_null';
26
	const VALIDATION_FAILED_USER_AGENT_INVALID = 'user_agent_invalid';
27
	const VALIDATION_FAILED_SIGNATURE_INVALID  = 'signature_invalid';
28
	const VALIDATION_FAILED_TIMESTAMP_MISMATCH = 'timestamp_out_of_range';
29
	const VALIDATION_FAILED_SIGNATURE_MISMATCH = 'signature_mismatch';
30
31
	/**
32
	 * Gets whether Stripe is in test mode or not
33
	 * 
34
	 * @since 4.4.2
35
	 * @return bool
36
	 */
37
	public static function get_testmode() {
38
		$stripe_settings = get_option( 'woocommerce_stripe_settings', array() );
39
		return ( ! empty( $stripe_settings['testmode'] ) && 'yes' === $stripe_settings['testmode'] ) ? true : false;
40
	}
41
42
	/**
43
	 * Gets (and sets, if unset) the timestamp the plugin first
44
	 * started tracking webhook failure and successes.
45
	 *
46
	 * @since 4.4.2
47
	 * @return integer UTC seconds since 1970.
48
	 */
49
	public static function get_monitoring_began_at() {
50
		$option = self::get_testmode() ? self::OPTION_TEST_MONITORING_BEGAN_AT : self::OPTION_LIVE_MONITORING_BEGAN_AT;
51
		$monitoring_began_at = get_option( $option, 0 );
52
		if ( 0 == $monitoring_began_at ) {
53
			$monitoring_began_at = current_time( 'timestamp', true );
54
			update_option( $option, $monitoring_began_at );
55
56
			// Enforce database consistency. This should only be needed if the user
57
			// has modified the database directly. We should not allow timestamps
58
			// before monitoring began.
59
			self::set_last_webhook_success_at( 0 );
60
			self::set_last_webhook_failure_at( 0 );
61
			self::set_last_error_reason( self::VALIDATION_SUCCEEDED );
62
		}
63
		return $monitoring_began_at;
64
	}
65
66
	/**
67
	 * Sets the timestamp of the last successfully processed webhook.
68
	 * 
69
	 * @since 4.4.2
70
	 * @param integer UTC seconds since 1970.
71
	 */
72
	public static function set_last_webhook_success_at( $timestamp ) {
73
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_SUCCESS_AT : self::OPTION_LIVE_LAST_SUCCESS_AT;
74
		update_option( $option, $timestamp );
75
	}
76
77
	/**
78
	 * Gets the timestamp of the last successfully processed webhook,
79
	 * or returns 0 if no webhook has ever been successfully processed.
80
	 *
81
	 * @since 4.4.2
82
	 * @return integer UTC seconds since 1970 | 0.
83
	 */
84
	public static function get_last_webhook_success_at() {
85
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_SUCCESS_AT : self::OPTION_LIVE_LAST_FAILURE_AT;
86
		return get_option( $option, 0 );
87
	}
88
89
	/**
90
	 * Sets the timestamp of the last failed webhook.
91
	 * 
92
	 * @since 4.4.2
93
	 * @param integer UTC seconds since 1970.
94
	 */
95
	public static function set_last_webhook_failure_at( $timestamp ) {
96
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_FAILURE_AT : self::OPTION_LIVE_LAST_FAILURE_AT;
97
		update_option( $option, $timestamp );
98
	}
99
100
	/**
101
	 * Gets the timestamp of the last failed webhook,
102
	 * or returns 0 if no webhook has ever failed to process.
103
	 *
104
	 * @since 4.4.2
105
	 * @return integer UTC seconds since 1970 | 0.
106
	 */
107
	public static function get_last_webhook_failure_at() {
108
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_FAILURE_AT : self::OPTION_LIVE_LAST_FAILURE_AT;
109
		return get_option( $option, 0 );
110
	}
111
112
	/**
113
	 * Sets the reason for the last failed webhook.
114
	 * 
115
	 * @since 4.4.2
116
	 * @param string Reason code.
117
	 * 
118
	 */
119
	public static function set_last_error_reason( $reason ) {
120
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_ERROR : self::OPTION_LIVE_LAST_ERROR;
121
		update_option( $option, $reason );
122
	}
123
124
	/**
125
	 * Returns the localized reason the last webhook failed.
126
	 *
127
	 * @since 4.4.2
128
	 * @return string Reason the last webhook failed.
129
	 */
130
	public static function get_last_error_reason() {
131
		$option = self::get_testmode() ? self::OPTION_TEST_LAST_ERROR : self::OPTION_LIVE_LAST_ERROR;
132
		$last_error = get_option( $option, false );
133
134
		if ( ! $last_error ) {
135
			return( __( 'No error', 'woocommerce-gateway-stripe' ) );
136
		}
137
138
		if ( self::VALIDATION_FAILED_BODY_NULL == $last_error ) {
139
			return( __( 'The webhook was missing expected body', 'woocommerce-gateway-stripe' ) );
140
		}
141
142
		if ( self::VALIDATION_FAILED_HEADERS_NULL == $last_error ) {
143
			return( __( 'The webhook was missing expected headers', 'woocommerce-gateway-stripe' ) );
144
		}
145
146
		if ( self::VALIDATION_FAILED_SIGNATURE_INVALID == $last_error ) {
147
			return( __( 'The webhook signature was missing or was incorrectly formatted', 'woocommerce-gateway-stripe' ) );
148
		}
149
150
		if ( self::VALIDATION_FAILED_SIGNATURE_MISMATCH == $last_error ) {
151
			return( __( 'The webhook was not signed with the expected signing secret', 'woocommerce-gateway-stripe' ) );
152
		}
153
154
		if ( self::VALIDATION_FAILED_TIMESTAMP_MISMATCH == $last_error ) {
155
			return( __( 'The timestamp in the webhook differed more than five minutes from the site time', 'woocommerce-gateway-stripe' ) );
156
		}
157
158
		if ( self::VALIDATION_FAILED_USER_AGENT_INVALID == $last_error ) {
159
			return( __( 'The webhook received did not come from Stripe', 'woocommerce-gateway-stripe' ) );
160
		}
161
162
		return( __( 'Unknown error.', 'woocommerce-gateway-stripe' ) );
163
	}
164
165
	/**
166
	 * Gets the state of webhook processing in a human readable format.
167
	 *
168
	 * @since 4.4.2
169
	 * @return string Details on recent webhook successes and failures.
170
	 */
171
	public static function get_webhook_status_message() {
172
		$monitoring_began_at = self::get_monitoring_began_at();
173
		$last_success_at     = self::get_last_webhook_success_at();
174
		$last_failure_at     = self::get_last_webhook_failure_at();
175
		$last_error          = self::get_last_error_reason();
176
		$test_mode           = self::get_testmode();
177
178
		$date_format = 'Y-m-d H:i:s e';
179
180
		// Case 1 (Nominal case): Most recent = success
181 View Code Duplication
		if ( $last_success_at > $last_failure_at ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
182
			$message = sprintf(
183
				$test_mode ?
184
					/* translators: 1) date and time of last webhook received, e.g. 2020-06-28 10:30:50 UTC */
185
					__( 'The most recent test webhook, timestamped %s, was processed successfully.', 'woocommerce-gateway-stripe' ) :
186
					/* translators: 1) date and time of last webhook received, e.g. 2020-06-28 10:30:50 UTC */
187
					__( 'The most recent live webhook, timestamped %s, was processed successfully.', 'woocommerce-gateway-stripe' ),
188
				date( $date_format, $last_success_at )
189
			);
190
			return $message;
191
		}
192
193
		// Case 2: No webhooks received yet
194
		if ( ( 0 == $last_success_at ) && ( 0 == $last_failure_at ) ) {
195
			$message = sprintf(
196
				$test_mode ?
197
					/* translators: 1) date and time webhook monitoring began, e.g. 2020-06-28 10:30:50 UTC */
198
					__( 'No test webhooks have been received since monitoring began at %s.', 'woocommerce-gateway-stripe' ) :
199
					/* translators: 1) date and time webhook monitoring began, e.g. 2020-06-28 10:30:50 UTC */
200
					__( 'No live webhooks have been received since monitoring began at %s.', 'woocommerce-gateway-stripe' ),
201
				date( $date_format, $monitoring_began_at )
202
			);
203
			return $message;
204
		}
205
206
		// Case 3: Failure after success
207 View Code Duplication
		if ( $last_success_at > 0 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
			$message = sprintf(
209
				$test_mode ?
210
					/* translators: 1) date and time of last failed webhook e.g. 2020-06-28 10:30:50 UTC */
211
					/* translators: 2) reason webhook failed */
212
					/* translators: 3) date and time of last successful webhook e.g. 2020-05-28 10:30:50 UTC */
213
					__( 'Warning: The most recent test webhook, received at %s, could not be processed. Reason: %s. (The last test webhook to process successfully was timestamped %s.)', 'woocommerce-gateway-stripe' ) :
214
					/* translators: 1) date and time of last failed webhook e.g. 2020-06-28 10:30:50 UTC */
215
					/* translators: 2) reason webhook failed */
216
					/* translators: 3) date and time of last successful webhook e.g. 2020-05-28 10:30:50 UTC */
217
					__( 'Warning: The most recent live webhook, received at %s, could not be processed. Reason: %s. (The last live webhook to process successfully was timestamped %s.)', 'woocommerce-gateway-stripe' ),
218
				date( $date_format, $last_failure_at ),
219
				$last_error,
220
				date( $date_format, $last_success_at )
221
			);
222
			return $message;
223
		}
224
225
		// Case 4: Failure with no prior success
226
		$message = sprintf(
227
			$test_mode ?
228
				/* translators: 1) date and time of last failed webhook e.g. 2020-06-28 10:30:50 UTC */
229
				/* translators: 2) reason webhook failed */
230
				/* translators: 3) date and time webhook monitoring began e.g. 2020-05-28 10:30:50 UTC */
231
				__( 'Warning: The most recent test webhook, received at %s, could not be processed. Reason: %s. (No test webhooks have been processed successfully since monitoring began at %s.)', 'woocommerce-gateway-stripe' ) :
232
				/* translators: 1) date and time of last failed webhook e.g. 2020-06-28 10:30:50 UTC */
233
				/* translators: 2) reason webhook failed */
234
				/* translators: 3) date and time webhook monitoring began e.g. 2020-05-28 10:30:50 UTC */
235
				__( 'Warning: The most recent live webhook, received at %s, could not be processed. Reason: %s. (No live webhooks have been processed successfully since monitoring began at %s.)', 'woocommerce-gateway-stripe' ),
236
			date( $date_format, $last_failure_at ),
237
			$last_error,
238
			date( $date_format, $monitoring_began_at )
239
		);
240
		return $message;
241
	}
242
};