_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 */ protected function save_ticketing_settings( $message, $enabled, $token, $calendar_id, $account ) { $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' ); } /** * Check if the current WP instance has payments settings configured */ public function has_payment_settings() { $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; } } public function get_timely_token() { return $this->get_ticketing_settings( 'token' ); } 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( 'Content-Type' => 'application/x-www-form-urlencoded' ); $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.
Detail: %s.', AI1EC_PLUGIN_NAME ), $base_message, $api_error ); } else { if ( is_wp_error( $response ) ) { $error_message = sprintf( __( 'API URL: %s.
Detail: %s', AI1EC_PLUGIN_NAME ), $url, $response->get_error_message() ); } else { $error_message = sprintf( __( 'API URL: %s.
Detail: %s - %s', AI1EC_PLUGIN_NAME ), $url, wp_remote_retrieve_response_code( $response ), wp_remote_retrieve_response_message( $response ) ); $mailto = 'labs@time.ly'; 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.
%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.
%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() ); $response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars', $body ); 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' ) ); $response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars', $body ); if ( $this->is_response_success( $response ) ) { return $response->body->id; } else { $this->log_error( $response, 'Created calendar' ); return 0; } } /** * Check if the current WP instance is signed into the API */ public function is_signed() { 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.' . '

'; foreach ( $failList as $failed ) { $pieces = explode( '/', $failed ); $message .= '- ' . $pieces[0] . '
'; } $this->show_error( $message ); } set_transient( 'ai1ec_api_checked', true, 5 * 60 ); } } /** * Get the current email account */ public function get_current_account() { return $this->get_ticketing_settings( 'account', '' ); } /** * Get the current calendar id */ public function get_current_calendar() { return $this->get_ticketing_settings( 'calendar_id', 0 ); } /** * Get the last message return by Signup or Signup process */ public function get_sign_message() { 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, 'accept' => 'application/json', 'headers' => $this->_get_headers( $custom_headers ), 'timeout' => self::DEFAULT_TIMEOUT ); if ( ! is_null( $body ) ) { $request['body'] = $body; } $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 ) ); } }