Skip to content

Commit

Permalink
Closes #6715 (#6739)
Browse files Browse the repository at this point in the history
Co-authored-by: WordPressFan <[email protected]>
Co-authored-by: Mathieu Lamiot <[email protected]>
  • Loading branch information
3 people authored Jul 1, 2024
1 parent 3db0518 commit c827f94
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 73 deletions.
14 changes: 11 additions & 3 deletions inc/Engine/Admin/Settings/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,17 @@ public function customer_data() {

$data['license_type'] = rocket_get_license_type( $user );

$data['license_class'] = time() < $user->licence_expiration ? 'wpr-isValid' : 'wpr-isInvalid';
$data['license_expiration'] = date_i18n( get_option( 'date_format' ), (int) $user->licence_expiration );
$data['is_from_one_dot_com'] = (bool) $user->{'has_one-com_account'};
if ( ! empty( $user->licence_expiration ) ) {
$data['license_class'] = time() < $user->licence_expiration ? 'wpr-isValid' : 'wpr-isInvalid';
}

if ( ! empty( $user->licence_expiration ) ) {
$data['license_expiration'] = date_i18n( get_option( 'date_format' ), (int) $user->licence_expiration );
}

if ( isset( $user->{'has_one-com_account'} ) ) {
$data['is_from_one_dot_com'] = (bool) $user->{'has_one-com_account'};
}

return $data;
}
Expand Down
2 changes: 2 additions & 0 deletions inc/Engine/Admin/Settings/Subscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ public function refresh_customer_data() {
}

delete_transient( 'wp_rocket_customer_data' );
delete_transient( 'wpr_user_information_timeout_active' );
delete_transient( 'wpr_user_information_timeout' );

return wp_send_json_success( $this->page->customer_data() );
}
Expand Down
153 changes: 153 additions & 0 deletions inc/Engine/Common/JobManager/APIHandler/AbstractSafeAPIClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?php

namespace WP_Rocket\Engine\Common\JobManager\APIHandler;

use WP_Error;

/**
* Class AbstractSafeAPIClient
*
* This abstract class provides a base for making API requests.
* It includes methods for sending GET and POST requests, and handles transient caching to mitigate the impact of API failures.
*
* @package WP_Rocket\Engine\Common\JobManager\APIHandler
*/
abstract class AbstractSafeAPIClient {

/**
* Get the transient key.
*
* @return string The transient key.
*/
abstract protected function get_transient_key();

/**
* Get the API URL.
*
* @return string The API URL.
*/
abstract protected function get_api_url();

/**
* Send a GET request.
*
* @param array $params The request parameters.
* @param bool $safe Send safe request WP functions or not, default to not.
*
* @return mixed The response from the API.
*/
public function send_get_request( $params = [], $safe = false ) {
return $this->send_request( 'GET', $params, $safe );
}

/**
* Send a POST request.
*
* @param array $params The request parameters.
* @param bool $safe Send safe request WP functions or not, default to not.
*
* @return mixed The response from the API.
*/
public function send_post_request( $params = [], $safe = false ) {
return $this->send_request( 'POST', $params, $safe );
}

/**
* Send a request to the API.
*
* @param string $method The HTTP method (GET or POST).
* @param array $params The request parameters.
* @param bool $safe Send safe request WP functions or not, default to not.
* @return mixed The response from the API, or WP_Error if a timeout is active.
*/
private function send_request( $method, $params = [], $safe = false ) {
$api_url = $this->get_api_url();

$transient_key = $this->get_transient_key();
if ( get_transient( $transient_key . '_timeout_active' ) ) {
return new WP_Error( 429, __( 'Too many requests.', 'rocket' ) );
}
// Get previous_expiration early to avoid multiple parallel requests increasing the expiration multiple times.
$previous_expiration = (int) get_transient( $transient_key . '_timeout' );

$params['method'] = strtoupper( $method );

$response = $this->send_remote_request( $api_url, $method, $params, $safe );

if ( is_wp_error( $response ) ) {
$this->set_timeout_transients( $previous_expiration );
return $response;
}

$body = wp_remote_retrieve_body( $response );
if ( empty( $body ) || ( is_array( $response ) && ! empty( $response['response']['code'] ) && 200 !== $response['response']['code'] ) ) {
$this->set_timeout_transients( $previous_expiration );
return new WP_Error( 500, __( 'Not valid response.', 'rocket' ) );
}

$this->delete_timeout_transients();

return $response;
}

/**
* Set the timeout transients.
*
* @param string $previous_expiration The previous value of _timeout_active transient.
*/
private function set_timeout_transients( $previous_expiration ) {
$transient_key = $this->get_transient_key();

$expiration = ( 0 === $previous_expiration )
? 300
: ( 2 * $previous_expiration <= DAY_IN_SECONDS
? 2 * $previous_expiration
: DAY_IN_SECONDS
);

set_transient( $transient_key . '_timeout', $expiration, WEEK_IN_SECONDS );
set_transient( $transient_key . '_timeout_active', true, $expiration );
}

/**
* Delete the timeout transients.
*
* This method deletes the timeout transients for the API requests. It uses the transient key obtained from the `get_transient_key` method.
* The transients deleted are:
* - `{transient_key}_timeout_active`: This transient indicates if a timeout is currently active.
* - `{transient_key}_timeout`: This transient stores the timeout duration.
*
* @return void
*/
private function delete_timeout_transients() {
$transient_key = $this->get_transient_key();
delete_transient( $transient_key . '_timeout_active' );
delete_transient( $transient_key . '_timeout' );
}

/**
* Decide which WP core function will be used to send the request based on the params.
*
* @param string $api_url API Url.
* @param string $method Request method (GET or POST).
* @param array $params Parameters being sent with the request.
* @param bool $safe Send safe request WP functions or not, default to not.
* @return array|WP_Error
*/
private function send_remote_request( $api_url, $method, $params, $safe ) {
if ( ! $safe ) {
return wp_remote_request( $api_url, $params );
}

unset( $params['method'] );

switch ( $method ) {
case 'GET':
return wp_safe_remote_get( $api_url, $params );
case 'POST':
return wp_safe_remote_post( $api_url, $params );
}

return new WP_Error( 400, __( 'Not valid request type.', 'rocket' ) );
}
}
10 changes: 3 additions & 7 deletions inc/Engine/Common/JobManager/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
namespace WP_Rocket\Engine\Common\JobManager;

use WP_Rocket\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
use WP_Rocket\Engine\Common\JobManager\Strategy\Context\RetryContext;
use WP_Rocket\Engine\Common\JobManager\Strategy\Factory\StrategyFactory;
use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\DefaultProcess;
use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\JobSetFail;
use WP_Rocket\Engine\Common\JobManager\Strategy\Strategies\ResetRetryProcess;
use WP_Rocket\Engine\Common\Clock\WPRClock;
use WP_Rocket\Engine\Common\JobManager\Queue\Queue;
use WP_Rocket\Engine\Common\JobManager\APIHandler\APIClient;
use WP_Rocket\Engine\Common\JobManager\Cron\Subscriber as CronSubscriber;

use WP_Rocket\Engine\Common\JobManager\Queue\Queue;
use WP_Rocket\Engine\Common\JobManager\Strategy\Context\RetryContext;
use WP_Rocket\Engine\Common\JobManager\Strategy\Factory\StrategyFactory;

class ServiceProvider extends AbstractServiceProvider {
/**
Expand Down
71 changes: 28 additions & 43 deletions inc/Engine/License/API/PricingClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,33 @@

namespace WP_Rocket\Engine\License\API;

class PricingClient {
use WP_Rocket\Engine\Common\JobManager\APIHandler\AbstractSafeAPIClient;

class PricingClient extends AbstractSafeAPIClient {
const PRICING_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/pricing-2023.php';

/**
* Get the transient key for plugin updates.
*
* This method returns the transient key used for caching plugin updates.
*
* @return string The transient key for plugin updates.
*/
protected function get_transient_key() {
return 'wp_rocket_pricing';
}

/**
* Get the API URL for plugin updates.
*
* This method returns the API URL used for fetching plugin updates.
*
* @return string The API URL for plugin updates.
*/
protected function get_api_url() {
return self::PRICING_ENDPOINT;
}

/**
* Gets pricing data from cache if it exists, else gets it from the pricing endpoint
*
Expand Down Expand Up @@ -40,51 +64,12 @@ public function get_pricing_data() {
* @return bool|object
*/
private function get_raw_pricing_data() {
if ( (bool) get_transient( 'wp_rocket_pricing_timeout_active' ) ) {
return false;
}

$response = wp_safe_remote_get(
self::PRICING_ENDPOINT
);

if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
$this->set_timeout_transients();

return false;
}

$body = wp_remote_retrieve_body( $response );

if ( empty( $body ) ) {
$this->set_timeout_transients();
$response = $this->send_get_request( [], true );

if ( is_wp_error( $response ) || ( is_array( $response ) && 200 !== $response['response']['code'] ) ) {
return false;
}

delete_transient( 'wp_rocket_pricing_timeout' );
delete_transient( 'wp_rocket_pricing_timeout_active' );

return json_decode( $body );
}

/**
* Set pricing timeout transients.
*
* @since 3.8.4
*
* @return void
*/
private function set_timeout_transients() {
$timeout = (int) get_transient( 'wp_rocket_pricing_timeout' );
$timeout = ( 0 === $timeout )
? 300
: ( 2 * $timeout <= DAY_IN_SECONDS
? 2 * $timeout :
DAY_IN_SECONDS
);

set_transient( 'wp_rocket_pricing_timeout', $timeout, WEEK_IN_SECONDS );
set_transient( 'wp_rocket_pricing_timeout_active', true, $timeout );
return json_decode( wp_remote_retrieve_body( $response ) );
}
}
33 changes: 28 additions & 5 deletions inc/Engine/License/API/UserClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
namespace WP_Rocket\Engine\License\API;

use WP_Rocket\Admin\Options_Data;
use WP_Rocket\Engine\Common\JobManager\APIHandler\AbstractSafeAPIClient;

class UserClient {
class UserClient extends AbstractSafeAPIClient {
const USER_ENDPOINT = 'https://wp-rocket.me/stat/1.0/wp-rocket/user.php';

/**
Expand All @@ -14,6 +15,28 @@ class UserClient {
*/
private $options;

/**
* Get the transient key for plugin updates.
*
* This method returns the transient key used for caching plugin updates.
*
* @return string The transient key for plugin updates.
*/
protected function get_transient_key() {
return 'wpr_user_information';
}

/**
* Get the API URL for plugin updates.
*
* This method returns the API URL used for fetching plugin updates.
*
* @return string The API URL for plugin updates.
*/
protected function get_api_url() {
return self::USER_ENDPOINT;
}

/**
* Instantiate the class
*
Expand Down Expand Up @@ -65,14 +88,14 @@ private function get_raw_user_data() {
? $this->options->get( 'consumer_email', '' )
: rocket_get_constant( 'WP_ROCKET_EMAIL', '' );

$response = wp_safe_remote_post(
self::USER_ENDPOINT,
$response = $this->send_post_request(
[
'body' => 'user_id=' . rawurlencode( $customer_email ) . '&consumer_key=' . sanitize_key( $customer_key ),
]
],
true
);

if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
if ( is_wp_error( $response ) ) {
return false;
}

Expand Down
Loading

0 comments on commit c827f94

Please sign in to comment.