2017-03-16 16:59:53 +01:00
< ? php
/**
* Common class for Timely API communication .
*
* @ author Time . ly Network , Inc .
* @ since 2.4
* @ package Ai1EC
* @ subpackage Ai1EC . Model
*/
abstract class Ai1ec_Api_Abstract extends Ai1ec_App {
2017-11-09 17:36:04 +01:00
const WP_OPTION_KEY = 'ai1ec_api_settings' ;
const DEFAULT_TIMEOUT = 30 ;
protected $_settings ;
/**
* Post construction routine .
*
* Override this method to perform post - construction tasks .
*
* @ return void Return from this method is ignored .
*/
protected function _initialize () {
$this -> _settings = $this -> _registry -> get ( 'model.settings' );
}
protected function get_ticketing_settings ( $find_attribute = null , $default_value_attribute = null ) {
$api_settings = get_option ( self :: WP_OPTION_KEY , null );
if ( ! is_array ( $api_settings ) ) {
$api_settings = array (
'enabled' => $this -> _settings -> get ( 'ticketing_enabled' ),
'message' => $this -> _settings -> get ( 'ticketing_message' ),
'token' => $this -> _settings -> get ( 'ticketing_token' ),
'calendar_id' => $this -> _settings -> get ( 'ticketing_calendar_id' )
);
update_option ( self :: WP_OPTION_KEY , $api_settings );
$this -> _settings -> set ( 'ticketing_message' , '' );
$this -> _settings -> set ( 'ticketing_enabled' , false );
$this -> _settings -> set ( 'ticketing_token' , '' );
$this -> _settings -> set ( 'ticketing_calendar_id' , null );
}
if ( is_null ( $find_attribute ) ) {
return $api_settings ;
} else {
if ( isset ( $api_settings [ $find_attribute ] ) ) {
return $api_settings [ $find_attribute ];
} else {
return $default_value_attribute ;
}
}
}
/**
* @ param String $message last message received from the Sign up or Sign in process
* @ param bool $enabled true or false is ticket is enabled
* @ param string $token autenthication token
* @ param int @ calendar_id remote id of the calendar
* @ param string $account Email used to create the account
*/
2017-03-16 16:59:53 +01:00
protected function save_ticketing_settings ( $message , $enabled , $token , $calendar_id , $account ) {
2017-11-09 17:36:04 +01:00
$api_settings = $this -> get_ticketing_settings ();
$api_settings [ 'message' ] = $message ;
$api_settings [ 'enabled' ] = $enabled ;
$api_settings [ 'token' ] = $token ;
$api_settings [ 'calendar_id' ] = $calendar_id ;
$api_settings [ 'account' ] = $account ;
return update_option ( self :: WP_OPTION_KEY , $api_settings );
}
protected function clear_ticketing_settings () {
delete_option ( self :: WP_OPTION_KEY );
// Clear transient API data
delete_transient ( 'ai1ec_api_feeds_subscriptions' );
delete_transient ( 'ai1ec_api_subscriptions' );
delete_transient ( 'ai1ec_api_features' );
delete_transient ( 'ai1ec_api_checked' );
$this -> check_settings ();
}
/**
* Save the Payment settings localy ( same saved on the API )
* @ param array Preferences to save
*/
public function save_payment_settings ( array $values ) {
$api_settings = $this -> get_ticketing_settings ();
if ( null !== $values ) {
$api_settings [ 'payment_settings' ] = $values ;
} else {
unset ( $api_settings [ 'payment_settings' ] );
}
return update_option ( self :: WP_OPTION_KEY , $api_settings );
}
/**
* Get the saved payments settings ( the same saved on the API )
*/
public function get_payment_settings () {
return $this -> get_ticketing_settings ( 'payment_settings' );
}
/**
2017-03-16 16:59:53 +01:00
* Check if the current WP instance has payments settings configured
*/
public function has_payment_settings () {
2017-11-09 17:36:04 +01:00
$payment_settings = $this -> get_payment_settings ();
if ( null === $payment_settings ) {
//code to migrate the settings save on ticketing api and
//bring them to the core side
$payment_settings = $this -> get_payment_preferences ();
if ( is_object ( $payment_settings ) ) {
$payment_settings = ( array ) $payment_settings ;
}
$this -> save_payment_settings ( ( array ) $payment_settings );
}
return ( null !== $payment_settings &&
'paypal' === $payment_settings [ 'payment_method' ] &&
false === ai1ec_is_blank ( $payment_settings [ 'paypal_email' ] ) ) ;
}
/**
* @ return object Response from API , or empty defaults
*/
public function get_payment_preferences () {
$calendar_id = $this -> _get_ticket_calendar ();
$settings = null ;
if ( 0 < $calendar_id ) {
$response = $this -> request_api ( 'GET' , AI1EC_API_URL . " calendars/ $calendar_id /payment " ,
null , //no body
true //decode response body
);
if ( $this -> is_response_success ( $response ) ) {
$settings = $response -> body ;
}
}
if ( is_null ( $settings ) ) {
return ( object ) array ( 'payment_method' => 'paypal' , 'paypal_email' => '' , 'first_name' => '' , 'last_name' => '' , 'currency' => 'USD' );
} else {
if ( ! isset ( $settings -> currency ) ) {
$settings -> currency = 'USD' ;
}
return $settings ;
}
}
2017-03-16 16:59:53 +01:00
public function get_timely_token () {
return $this -> get_ticketing_settings ( 'token' );
2017-11-09 17:36:04 +01:00
}
protected function save_calendar_id ( $calendar_id ) {
$api_settings = $this -> get_ticketing_settings ();
$api_settings [ 'calendar_id' ] = $calendar_id ;
return update_option ( self :: WP_OPTION_KEY , $api_settings );
}
/**
* Get the header array with authorization token
*/
protected function _get_headers ( $custom_headers = null ) {
$headers = array (
2019-07-25 14:11:00 +02:00
'Content-Type' => 'application/x-www-form-urlencoded'
2017-11-09 17:36:04 +01:00
);
$headers [ 'Authorization' ] = 'Basic ' . $this -> get_ticketing_settings ( 'token' , '' );
if ( null !== $custom_headers ) {
foreach ( $custom_headers as $key => $value ) {
if ( null === $value ) {
unset ( $headers [ $key ] );
} else {
$headers [ $key ] = $value ;
}
}
}
return $headers ;
}
/**
* Create a standarized message to return
* 1 ) If the API respond with http code 400 and with a JSON body , so , we will consider the API message to append in the base message .
* 2 ) If the API does not responde with http code 400 or does not have a valid a JSON body , we will show the API URL and the http message error .
*/
protected function _transform_error_message ( $base_message , $response , $url , $ask_for_reload = false ) {
$api_error = $this -> get_api_error_msg ( $response );
$result = null ;
if ( false === ai1ec_is_blank ( $api_error ) ) {
$result = sprintf (
__ ( '%s.<br/>Detail: %s.' , AI1EC_PLUGIN_NAME ),
$base_message , $api_error
);
} else {
if ( is_wp_error ( $response ) ) {
$error_message = sprintf (
__ ( 'API URL: %s.<br/>Detail: %s' , AI1EC_PLUGIN_NAME ),
$url ,
$response -> get_error_message ()
);
} else {
$error_message = sprintf (
__ ( 'API URL: %s.<br/>Detail: %s - %s' , AI1EC_PLUGIN_NAME ),
$url ,
wp_remote_retrieve_response_code ( $response ),
wp_remote_retrieve_response_message ( $response )
);
$mailto = '<a href="mailto:labs@time.ly" target="_top">labs@time.ly</a>' ;
if ( true === $ask_for_reload ) {
$result = sprintf (
__ ( '%s. Please reload this page to try again. If this error persists, please contact us at %s. In your report please include the information below.<br/>%s.' , AI1EC_PLUGIN_NAME ),
$base_message ,
$mailto ,
$error_message
);
} else {
$result = sprintf (
__ ( '%s. Please try again. If this error persists, please contact us at %s. In your report please include the information below.<br/>%s.' , AI1EC_PLUGIN_NAME ),
$base_message ,
$mailto ,
$error_message
);
}
}
}
$result = trim ( $result );
$result = str_replace ( '..' , '.' , $result );
$result = str_replace ( '.,' , '.' , $result );
return $result ;
}
/**
* Search for the API message error
*/
public function get_api_error_msg ( $response ) {
if ( isset ( $response ) && false === is_wp_error ( $response ) ) {
$response_body = json_decode ( $response [ 'body' ], true );
if ( is_array ( $response_body ) &&
isset ( $response_body [ 'errors' ] ) ) {
$errors = $response_body [ 'errors' ];
if ( false === is_array ( $errors )) {
$errors = array ( $errors );
}
$messages = null ;
foreach ( $errors as $key => $value ) {
if ( false === ai1ec_is_blank ( $value ) ) {
if ( is_array ( $value ) ) {
$value = implode ( ', ' , $value );
}
$messages [] = $value ;
}
}
if ( null !== $messages && false === empty ( $messages ) ) {
return implode ( ', ' , $messages );
}
}
}
return null ;
}
/**
* Get the ticket calendar from settings , if the calendar does not exists in
* settings , then we will try to find on the API
* @ return string JSON .
*/
protected function _get_ticket_calendar ( $createIfNotExists = true ) {
$ticketing_calendar_id = $this -> get_ticketing_settings ( 'calendar_id' , 0 );
if ( 0 < $ticketing_calendar_id ) {
return $ticketing_calendar_id ;
} else {
if ( ! $createIfNotExists ) {
return 0 ;
}
// Try to find the calendar in the API
$ticketing_calendar_id = $this -> _find_user_calendar ();
if ( 0 < $ticketing_calendar_id ) {
$this -> save_calendar_id ( $ticketing_calendar_id );
return $ticketing_calendar_id ;
} else {
// If the calendar doesn't exist in the API, create a new one
$ticketing_calendar_id = $this -> _create_calendar ();
if ( 0 < $ticketing_calendar_id ) {
$this -> save_calendar_id ( $ticketing_calendar_id );
return $ticketing_calendar_id ;
} else {
return 0 ;
}
}
}
}
/**
* Find the existent calendar when the user is signing in
*/
protected function _find_user_calendar () {
$body = array (
'title' => get_bloginfo ( 'name' ),
'url' => ai1ec_site_url ()
);
2019-07-25 14:11:00 +02:00
$response = $this -> request_api ( 'GET' , AI1EC_API_URL . 'calendars' , $body );
2017-11-09 17:36:04 +01:00
if ( $this -> is_response_success ( $response ) ) {
if ( is_array ( $response -> body ) ) {
return $response -> body [ 0 ] -> id ;
} else {
return $response -> body -> id ;
}
} else {
return 0 ;
}
}
/**
* Create a calendar when the user is signup
*/
protected function _create_calendar () {
$body = array (
'title' => get_bloginfo ( 'name' ),
'url' => ai1ec_site_url (),
'timezone' => $this -> _settings -> get ( 'timezone_string' )
);
2019-07-25 14:11:00 +02:00
$response = $this -> request_api ( 'POST' , AI1EC_API_URL . 'calendars' , $body );
2017-11-09 17:36:04 +01:00
if ( $this -> is_response_success ( $response ) ) {
return $response -> body -> id ;
} else {
$this -> log_error ( $response , 'Created calendar' );
return 0 ;
}
}
2017-03-16 16:59:53 +01:00
/**
* Check if the current WP instance is signed into the API
*/
public function is_signed () {
2017-11-09 17:36:04 +01:00
return ( true === $this -> get_ticketing_settings ( 'enabled' , false ) );
}
public function check_settings ( $force = false ) {
$checked = get_transient ( 'ai1ec_api_checked' );
if ( false === $checked || $force ) {
require_once ( ABSPATH . 'wp-admin/includes/plugin.php' );
$failList = array ();
foreach ( Ai1ec_Api_Features :: $features as $key => $value ) {
if ( empty ( $value ) ) {
continue ;
}
if ( ( ! $this -> is_signed () || ! $this -> has_subscription_active ( $key ) ) && call_user_func ( 'is' . '_' . 'pl' . 'ug' . 'in' . '_' . 'ac' . 'ti' . 've' , $value ) ) {
$failList [] = $value ;
}
}
if ( count ( $failList ) > 0 ) {
call_user_func ( 'de' . 'act' . 'iv' . 'ate' . '_' . 'pl' . 'ug' . 'ins' , $failList );
$message = 'Your ' .
'All-in-One Event Calendar ' .
'has the ' .
'following ' .
'plugins ' .
'installed ' .
'but they are ' .
'disabled. ' .
'To keep ' .
'them ' .
'enabled' .
', simply ' .
'keep ' .
'your calendar ' .
'logged in ' .
'to your ' .
'Timely account.' .
'<br /><br />' ;
foreach ( $failList as $failed ) {
$pieces = explode ( '/' , $failed );
$message .= '- ' . $pieces [ 0 ] . '<br />' ;
}
$this -> show_error ( $message );
}
set_transient ( 'ai1ec_api_checked' , true , 5 * 60 );
}
2017-03-16 16:59:53 +01:00
}
/**
* Get the current email account
*/
2017-11-09 17:36:04 +01:00
public function get_current_account () {
return $this -> get_ticketing_settings ( 'account' , '' );
}
2017-03-16 16:59:53 +01:00
2017-11-09 17:36:04 +01:00
/**
* Get the current calendar id
*/
2017-03-16 16:59:53 +01:00
public function get_current_calendar () {
2017-11-09 17:36:04 +01:00
return $this -> get_ticketing_settings ( 'calendar_id' , 0 );
2017-03-16 16:59:53 +01:00
}
/**
* Get the last message return by Signup or Signup process
*/
public function get_sign_message () {
2017-11-09 17:36:04 +01:00
return $this -> get_ticketing_settings ( 'message' , '' );
}
/**
* Clear the last message return by Signup or Signup process
*/
public function clear_sign_message () {
$api_settings = $this -> get_ticketing_settings ();
$api_settings [ 'message' ] = '' ;
return update_option ( self :: WP_OPTION_KEY , $api_settings );
}
/**
* @ return array List of subscriptions and limits
*/
protected function get_subscriptions ( $force_refresh = false ) {
$subscriptions = get_transient ( 'ai1ec_api_subscriptions' );
if ( false === $subscriptions || $force_refresh || ( defined ( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
$response = $this -> request_api ( 'GET' , AI1EC_API_URL . 'calendars/' . $this -> _get_ticket_calendar () . '/subscriptions' ,
null ,
true
);
if ( $this -> is_response_success ( $response ) ) {
$subscriptions = ( array ) $response -> body ;
} else {
$subscriptions = array ();
}
// Save for 5 minutes
$minutes = 5 ;
set_transient ( 'ai1ec_api_subscriptions' , $subscriptions , $minutes * 60 );
}
return $subscriptions ;
}
/**
* Check if calendar should have a specific feature enabled
*/
public function has_subscription_active ( $feature ) {
$subscriptions = $this -> get_subscriptions ();
return array_key_exists ( $feature , $subscriptions );
}
/**
* Check if feature has reached its limit
*/
public function subscription_has_reached_limit ( $feature ) {
$has_reached_limit = true ;
$provided = $this -> subscription_get_quantity_limit ( $feature );
$used = $this -> subscription_get_used_quantity ( $feature );
if ( $provided - $used > 0 ) {
$has_reached_limit = false ;
}
return $has_reached_limit ;
}
/**
* Get feature quantity limit
*/
public function subscription_get_quantity_limit ( $feature ) {
$provided = 0 ;
$subscriptions = $this -> get_subscriptions ();
if ( array_key_exists ( $feature , $subscriptions ) ) {
$quantity = ( array ) $subscriptions [ $feature ];
$provided = $quantity [ 'provided' ];
}
return $provided ;
}
/**
* Get feature used quantity
*/
public function subscription_get_used_quantity ( $feature ) {
$used = 0 ;
$subscriptions = $this -> get_subscriptions ();
if ( array_key_exists ( $feature , $subscriptions ) ) {
$quantity = ( array ) $subscriptions [ $feature ];
$used = $quantity [ 'used' ];
}
return $used ;
}
/**
* Make the request to the API endpons
* @ param $url The end part of the url to make the request .
* $body The body to send the message
* $method POST | GET | PUT , etc
* or send a customized message to be showed in case of error
* $decode_response_body TRUE ( default ) to decode the body response
* @ return stdClass with the the fields :
* is_error TRUE or FALSE
* error in case of is_error be true
* body in case of is_error be false
*/
protected function request_api ( $method , $url , $body = null , $decode_response_body = true , $custom_headers = null ) {
$request = array (
'method' => $method ,
2019-07-25 14:11:00 +02:00
'accept' => 'application/json' ,
2017-11-09 17:36:04 +01:00
'headers' => $this -> _get_headers ( $custom_headers ),
'timeout' => self :: DEFAULT_TIMEOUT
);
if ( ! is_null ( $body ) ) {
2019-07-25 14:11:00 +02:00
$request [ 'body' ] = $body ;
2017-11-09 17:36:04 +01:00
}
$response = wp_remote_request ( $url , $request );
$result = new stdClass ();
$result -> url = $url ;
$result -> raw = $response ;
if ( is_wp_error ( $response ) ) {
$result -> is_error = true ;
$result -> error = $response -> get_error_message ();
} else {
$result -> response_code = wp_remote_retrieve_response_code ( $response );
if ( 200 === $result -> response_code ) {
if ( true === $decode_response_body ) {
$result -> body = json_decode ( $response [ 'body' ] );
if ( false === is_null ( $result -> body ) ) {
$result -> is_error = false ;
} else {
$result -> is_error = true ;
$result -> error = __ ( 'Error decoding the response' , AI1EC_PLUGIN_NAME );
unset ( $result -> body );
}
} else {
$result -> is_error = false ;
$result -> body = $response [ 'body' ];
}
} else {
$result -> is_error = true ;
$result -> error = wp_remote_retrieve_response_message ( $response );
}
}
return $result ;
}
/**
* Make a post request to the api
* @ param rest_endpoint Partial URL that can include { calendar_id } that will be replaced by the current calendar signed
*/
public function call_api ( $method , $endpoint , $body = null , $decode_response_body = true , $custom_headers = null ) {
$calendar_id = $this -> _get_ticket_calendar ();
if ( 0 >= $calendar_id ) {
return false ;
}
$url = AI1EC_API_URL . str_replace ( '{calendar_id}' , $calendar_id , $endpoint );
return $this -> request_api ( $method , $url , $body , $decode_response_body , $custom_headers );
}
/**
* Save an error notification to be showed to the user on WP header of the page
* @ param $response The response got from request_api method .
* $custom_error_message The custom message to show before the detailed message
* @ return full error message
*/
protected function save_error_notification ( $response , $custom_error_response ) {
$error_message = $this -> _transform_error_message (
$custom_error_response ,
$response -> raw ,
$response -> url ,
true
);
$response -> error_message = $error_message ;
$notification = $this -> _registry -> get ( 'notification.admin' );
$notification -> store ( $error_message , 'error' , 0 , array ( Ai1ec_Notification_Admin :: RCPT_ADMIN ), false );
error_log ( $custom_error_response . ': ' . $error_message . ' - raw error: ' . print_r ( $response -> raw , true ) );
return $error_message ;
}
/**
* Save an error notification to be showed to the user on WP header of the page
* @ param $response The response got from request_api method .
* $custom_error_message The custom message to show before the detailed message
* @ return full error message
*/
protected function log_error ( $response , $custom_error_response ) {
$error_message = $this -> _transform_error_message (
$custom_error_response ,
$response -> raw ,
$response -> url ,
true
);
error_log ( $custom_error_response . ': ' . $error_message . ' - raw error: ' . print_r ( $response -> raw , true ) );
return $error_message ;
}
protected function show_error ( $error_message ) {
$notification = $this -> _registry -> get ( 'notification.admin' );
$notification -> store ( $error_message , 'error' , 0 , array ( Ai1ec_Notification_Admin :: RCPT_ADMIN ), false );
error_log ( $error_message );
return $error_message ;
}
/**
* Useful method to check if the response of request_api is a successful message
*/
public function is_response_success ( $response ) {
return $response != null &&
( ! isset ( $response -> is_error ) || ( isset ( $response -> is_error ) && false === $response -> is_error ) );
}
2017-03-16 16:59:53 +01:00
}