@@ -0,0 +1,622 @@
|
||||
<?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 {
|
||||
|
||||
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
|
||||
*/
|
||||
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.<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()
|
||||
);
|
||||
$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.' .
|
||||
'<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 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
class Ai1ec_Api_Features {
|
||||
|
||||
const CODE_API_ACCESS = 'api-access';
|
||||
const CODE_TICKETING = 'ticketing';
|
||||
const CODE_TWITTER = 'twitter';
|
||||
const CODE_FRONTEND_SUBMISSIONS = 'frontend-submissions';
|
||||
const CODE_CSV_IMPORT = 'csv-import';
|
||||
const CODE_SUPER_WIDGET = 'super-widget';
|
||||
const CODE_EXTENDED_VIEWS = 'extended-views';
|
||||
const CODE_BIG_FILTERING = 'big-filtering';
|
||||
const CODE_CUSTOM_FILTERS = 'custom-filter-groups';
|
||||
const CODE_DISCOVER_EVENTS = 'discover-events';
|
||||
const CODE_EVENT_PROMOTE = 'event-promote';
|
||||
const CODE_FACEBOOK_INTEGRATION = 'facebook-integration';
|
||||
const CODE_FEATURED_EVENTS = 'featured-events';
|
||||
const CODE_MAILCHIMP = 'mailchimp';
|
||||
const CODE_PHRASE_OVERRIDE = 'phrase-override';
|
||||
const CODE_POPOVERS = 'popovers';
|
||||
const CODE_SAVE_AND_SHARE = 'save-and-share';
|
||||
const CODE_VENUES = 'venues';
|
||||
const CODE_IMPORT_FEEDS = 'import-feeds';
|
||||
|
||||
public static $features = array(
|
||||
self::CODE_API_ACCESS => '',
|
||||
self::CODE_TICKETING => '',
|
||||
self::CODE_TWITTER => 'all-in-one-event-calendar-twitter-integration/all-in-one-event-calendar-twitter-integration.php',
|
||||
self::CODE_FRONTEND_SUBMISSIONS => 'all-in-one-event-calendar-frontend-submissions/all-in-one-event-calendar-frontend-submissions.php',
|
||||
self::CODE_CSV_IMPORT => 'all-in-one-event-calendar-csv-feed/all-in-one-event-calendar-csv-feed.php',
|
||||
self::CODE_SUPER_WIDGET => 'all-in-one-event-calendar-super-widget/all-in-one-event-calendar-super-widget.php',
|
||||
self::CODE_EXTENDED_VIEWS => 'all-in-one-event-calendar-extended-views/all-in-one-event-calendar-extended-views.php',
|
||||
self::CODE_BIG_FILTERING => 'all-in-one-event-calendar-big-filtering/all-in-one-event-calendar-big-filtering.php',
|
||||
self::CODE_CUSTOM_FILTERS => 'all-in-one-event-calendar-custom-filter-groups/all-in-one-event-calendar-custom-filter-groups.php',
|
||||
self::CODE_DISCOVER_EVENTS => '',
|
||||
self::CODE_EVENT_PROMOTE => 'all-in-one-event-calendar-event-promote/all-in-one-event-calendar-event-promote.php',
|
||||
self::CODE_FACEBOOK_INTEGRATION => 'all-in-one-event-calendar-facebook-integration/all-in-one-event-calendar-facebook-integration.php',
|
||||
self::CODE_FEATURED_EVENTS => 'all-in-one-event-calendar-featured-events/all-in-one-event-calendar-featured-events.php',
|
||||
self::CODE_MAILCHIMP => 'all-in-one-event-calendar-mailchimp/all-in-one-event-calendar-mailchimp.php',
|
||||
self::CODE_PHRASE_OVERRIDE => 'all-in-one-event-calendar-phrase-override/all-in-one-event-calendar-phrase-override.php',
|
||||
self::CODE_POPOVERS => 'all-in-one-event-calendar-popovers/all-in-one-event-calendar-popovers.php',
|
||||
self::CODE_SAVE_AND_SHARE => 'all-in-one-event-calendar-save-and-share/all-in-one-event-calendar-save-and-share.php',
|
||||
self::CODE_VENUES => 'all-in-one-event-calendar-venue/all-in-one-event-calendar-venue.php',
|
||||
self::CODE_IMPORT_FEEDS => '',
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication related to Discover Events and Feeds.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Feeds extends Ai1ec_Api_Abstract {
|
||||
|
||||
// Feed status
|
||||
// c = Feed not migrated yet to API
|
||||
// a = Feed migrated to API (all events)
|
||||
// b = Feed migrated to API (individual events were selected)
|
||||
public static $FEED_NOT_MIGRATED_CODE = 'c';
|
||||
public static $FEED_API_ALL_EVENTS_CODE = 'a';
|
||||
public static $FEED_API_SOME_EVENTS_CODE = 'b';
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get static var (for PHP 5.2 compatibility)
|
||||
*
|
||||
* @param String $var
|
||||
*/
|
||||
public function getStaticVar($var) {
|
||||
return self::$$var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getting a suggested events list.
|
||||
* @return stClass Response using the following format:
|
||||
* [total] => 10
|
||||
* [per_page] => 8
|
||||
* [current_page] => 1
|
||||
* [last_page] => 2
|
||||
* [next_page_url] =>
|
||||
* [prev_page_url] =>
|
||||
* [from] => 1
|
||||
* [to] => 8
|
||||
* [data] => Array list of suggested events
|
||||
*/
|
||||
public function get_suggested_events() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$body = null;
|
||||
if (
|
||||
isset( $_POST[ 'lat' ] ) &&
|
||||
isset( $_POST[ 'lng' ] ) &&
|
||||
isset( $_POST[ 'radius' ] )
|
||||
) {
|
||||
$body = array(
|
||||
'lat' => $_POST[ 'lat' ],
|
||||
'lng' => $_POST[ 'lng' ],
|
||||
'radius' => $_POST[ 'radius' ]
|
||||
);
|
||||
}
|
||||
|
||||
$page = isset( $_POST[ 'page' ] ) ? $_POST[ 'page' ] : 1;
|
||||
$max = isset( $_POST[ 'max' ] ) ? $_POST[ 'max' ] : 8;
|
||||
$term = isset( $_POST[ 'term' ] ) && $_POST[ 'term' ]
|
||||
? urlencode( $_POST[ 'term' ] )
|
||||
: '*';
|
||||
$location = isset( $_POST[ 'location' ] ) && $_POST[ 'location' ]
|
||||
? '&location=' . urlencode( $_POST[ 'location' ] )
|
||||
: '';
|
||||
|
||||
$url = AI1EC_API_URL .
|
||||
"calendars/$calendar_id/discover/events?page=$page&max=$max&term=$term" .
|
||||
$location;
|
||||
|
||||
$response = $this->request_api( 'GET', $url,
|
||||
$body,
|
||||
true //decode body response
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to get the Suggested Events from Time.ly Network', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( 'We were unable to get the Suggested Events from Time.ly Network' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to Process and Import the Feed
|
||||
*/
|
||||
public function import_feed( $entry ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/import',
|
||||
array(
|
||||
'url' => $entry['feed_url'],
|
||||
'categories' => $entry['feed_category'],
|
||||
'tags' => $entry['feed_tags'],
|
||||
'allow_comments' => $entry['comments_enabled'],
|
||||
'show_maps' => $entry['map_display_enabled'],
|
||||
'import_any_tag_and_categories' => $entry['keep_tags_categories'],
|
||||
'preserve_imported_events' => $entry['keep_old_events'],
|
||||
'assign_default_utc' => $entry['import_timezone']
|
||||
)
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to import feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to get the feed
|
||||
*/
|
||||
public function get_feed( $feed_id ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/get/' . $feed_id,
|
||||
array( 'max' => '9999' )
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to get feed data', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to get list of feed subscriptions
|
||||
*/
|
||||
public function get_feed_subscriptions( $force_refresh = false ) {
|
||||
$feeds_subscriptions = get_transient( 'ai1ec_api_feeds_subscriptions' );
|
||||
|
||||
if ( $force_refresh || false === $feeds_subscriptions ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/feeds/list',
|
||||
null,
|
||||
true
|
||||
);
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$feeds_subscriptions = (array) $response->body;
|
||||
} else {
|
||||
$feeds_subscriptions = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_api_feeds_subscriptions', $feeds_subscriptions, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $feeds_subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync feed subscriptions
|
||||
*/
|
||||
public function get_and_sync_feed_subscriptions() {
|
||||
$feeds_subscriptions = $this->get_feed_subscriptions();
|
||||
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
$table_name = $db->get_table_name( 'ai1ec_event_feeds' );
|
||||
|
||||
// Select all feeds
|
||||
$rows = $db->select(
|
||||
$table_name,
|
||||
array(
|
||||
'feed_id',
|
||||
'feed_url',
|
||||
'feed_name',
|
||||
'feed_category',
|
||||
'feed_tags',
|
||||
'comments_enabled',
|
||||
'map_display_enabled',
|
||||
'keep_tags_categories',
|
||||
'keep_old_events',
|
||||
'import_timezone'
|
||||
)
|
||||
);
|
||||
|
||||
// Iterate over API response
|
||||
foreach( $feeds_subscriptions as $api_feed ) {
|
||||
$found = false;
|
||||
|
||||
foreach ( $rows as $row ) {
|
||||
// Check if URL is the same
|
||||
if ( trim( $row->feed_url ) === trim( $api_feed->url ) ) {
|
||||
$found = true;
|
||||
|
||||
// Update feed
|
||||
$db->update(
|
||||
$table_name,
|
||||
array(
|
||||
'comments_enabled' => $api_feed->allow_comments,
|
||||
'map_display_enabled' => $api_feed->show_maps,
|
||||
'keep_tags_categories' => $api_feed->import_any_tag_and_categories,
|
||||
'keep_old_events' => $api_feed->preserve_imported_events,
|
||||
'import_timezone' => $api_feed->assign_default_utc,
|
||||
'feed_name' => $api_feed->feed_id
|
||||
),
|
||||
array(
|
||||
'feed_id' => $row->feed_id
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Not found in local database.. Insert
|
||||
if ( ! $found ) {
|
||||
$entry = array(
|
||||
'feed_url' => $api_feed->url,
|
||||
'feed_name' => $api_feed->feed_id,
|
||||
'feed_category' => $api_feed->categories,
|
||||
'feed_tags' => $api_feed->tags,
|
||||
'comments_enabled' => $api_feed->allow_comments,
|
||||
'map_display_enabled' => $api_feed->show_maps,
|
||||
'keep_tags_categories' => $api_feed->import_any_tag_and_categories,
|
||||
'keep_old_events' => $api_feed->preserve_imported_events,
|
||||
'import_timezone' => $api_feed->assign_default_utc
|
||||
);
|
||||
$format = array( '%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d' );
|
||||
$db->insert(
|
||||
$table_name,
|
||||
$entry,
|
||||
$format
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to subscribe feed
|
||||
*/
|
||||
public function subscribe_feed( $feed_id, $feed_event_uid = '' ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/subscribe',
|
||||
array(
|
||||
'feed_id' => $feed_id,
|
||||
'feed_event_uid' => $feed_event_uid
|
||||
)
|
||||
);
|
||||
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to subscribe feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the API to unsubscribe feed
|
||||
*/
|
||||
public function unsubscribe_feed( $feed_id, $feed_event_uid = '' ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
throw new Exception( 'Calendar ID not found' );
|
||||
}
|
||||
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'calendars/' . $calendar_id . '/feeds/unsubscribe',
|
||||
array(
|
||||
'feed_id' => $feed_id,
|
||||
'feed_event_uid' => $feed_event_uid
|
||||
)
|
||||
);
|
||||
|
||||
// Refresh list of subscriptions and limits
|
||||
$this->get_subscriptions( true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification(
|
||||
$response,
|
||||
__( 'We were unable to unsubscribe feed', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
throw new Exception( $this->get_api_error_msg( $response->raw ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication for Registration.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Registration extends Ai1ec_Api_Abstract {
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function signin() {
|
||||
$body['email'] = $_POST['ai1ec_email'];
|
||||
$body['password'] = $_POST['ai1ec_password'];
|
||||
$body['calendar_type'] = $_POST['ai1ec_calendar_type'];
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'auth/authenticate', $body, true, array( 'Authorization' => null ) );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$response_body = (array) $response->body;
|
||||
// Save calendar ID as 0 first, otherwise the auth data won't be saved in the database before creating/finding the calendar
|
||||
$this->save_ticketing_settings( $response_body['message'], true, $response_body['auth_token'], 0, $body['email'] );
|
||||
// Now save the calendar ID
|
||||
$this->save_calendar_id( $this->_get_ticket_calendar() );
|
||||
$this->has_payment_settings();
|
||||
$this->get_subscriptions( true );
|
||||
$this->sync_api_settings();
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you In for Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
$this->save_ticketing_settings( $error_message, false, '', 0, null );
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function signup() {
|
||||
$body['name'] = $_POST['ai1ec_name'];
|
||||
$body['email'] = $_POST['ai1ec_email'];
|
||||
$body['password'] = $_POST['ai1ec_password'];
|
||||
$body['password_confirmation'] = $_POST['ai1ec_password_confirmation'];
|
||||
$body['phone'] = $_POST['ai1ec_phone'];
|
||||
$body['calendar_type'] = $_POST['ai1ec_calendar_type'];
|
||||
$body['terms'] = $_POST['ai1ec_terms'];
|
||||
$response = $this->request_api( 'POST', AI1EC_API_URL . 'auth/register', $body, true );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$response_body = (array) $response->body;
|
||||
// Save calendar ID as 0 first, otherwise the auth data won't be saved in the database before creating the calendar
|
||||
$this->save_ticketing_settings( $response_body['Registration'], true, $response_body['auth_token'] , 0, $body['email'] );
|
||||
// Now save the calendar ID
|
||||
$this->save_calendar_id( $this->_create_calendar() );
|
||||
$this->has_payment_settings();
|
||||
$this->get_subscriptions( true );
|
||||
$this->sync_api_settings();
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you Up for Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
$this->save_ticketing_settings( $error_message, false, '', 0, null );
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
protected function availability() {
|
||||
$api_features = get_transient( 'ai1ec_api_features' );
|
||||
|
||||
if ( false === $api_features || ( defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'feature/availability', null, true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$api_features = (array) $response->body;
|
||||
} else {
|
||||
$api_features = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_api_features', $api_features, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $api_features;
|
||||
}
|
||||
|
||||
protected function is_feature_available( $feature_code ) {
|
||||
$availability = $this->availability();
|
||||
|
||||
if ( ! is_null( $availability ) ) {
|
||||
foreach ( $availability as $value ) {
|
||||
if ( isset( $value->code ) && $feature_code === $value->code
|
||||
&& isset( $value->available ) && true === $value->available ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
protected function settings() {
|
||||
$calendar_settings = get_transient( 'ai1ec_calendar_settings' );
|
||||
|
||||
if ( false === $calendar_settings || ( defined( 'AI1EC_DEBUG' ) && AI1EC_DEBUG ) ) {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/settings', null, true );
|
||||
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$calendar_settings = (array) $response->body;
|
||||
} else {
|
||||
$calendar_settings = array();
|
||||
}
|
||||
|
||||
// Save for 5 minutes
|
||||
$minutes = 5;
|
||||
set_transient( 'ai1ec_calendar_settings', $calendar_settings, $minutes * 60 );
|
||||
}
|
||||
|
||||
return $calendar_settings;
|
||||
}
|
||||
|
||||
public function is_api_sign_up_available() {
|
||||
return $this->is_feature_available( Ai1ec_Api_Features::CODE_API_ACCESS );
|
||||
}
|
||||
|
||||
public function is_ticket_available() {
|
||||
return $this->is_feature_available( Ai1ec_Api_Features::CODE_TICKETING );
|
||||
}
|
||||
|
||||
public function is_ticket_enabled() {
|
||||
return $this->has_subscription_active( Ai1ec_Api_Features::CODE_TICKETING );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the ticketing settings on WP database only
|
||||
*/
|
||||
public function signout() {
|
||||
$calendar_id = $this->_get_ticket_calendar( false );
|
||||
if ( 0 >= $calendar_id ) {
|
||||
$this->clear_ticketing_settings();
|
||||
return false;
|
||||
}
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $calendar_id . '/signout', null, true );
|
||||
// Consider "Unauthorized" status (401) a valid response
|
||||
if ( $this->is_response_success( $response ) || 401 === wp_remote_retrieve_response_code( $response->raw ) ) {
|
||||
$this->clear_ticketing_settings();
|
||||
return array( 'message' => '' );
|
||||
} else {
|
||||
$error_message = $this->save_error_notification( $response, __( 'We were unable to Sign you Out of Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return array( 'message' => $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body from API.
|
||||
*/
|
||||
public function save_payment_preferences() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( 0 >= $calendar_id ) {
|
||||
return false;
|
||||
}
|
||||
$settings = array(
|
||||
'payment_method' => $_POST['ai1ec_payment_method'],
|
||||
'paypal_email' => $_POST['ai1ec_paypal_email'],
|
||||
'first_name' => $_POST['ai1ec_first_name'],
|
||||
'last_name' => $_POST['ai1ec_last_name'],
|
||||
'currency' => $_POST['ai1ec_currency']
|
||||
);
|
||||
$custom_headers['content-type'] = 'application/x-www-form-urlencoded';
|
||||
$response = $this->request_api( 'PUT', AI1EC_API_URL . 'calendars/' . $calendar_id . '/payment',
|
||||
$settings,
|
||||
true, //decode response body
|
||||
$custom_headers
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$this->save_payment_settings( $settings );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
__( 'Payment preferences were saved.', AI1EC_PLUGIN_NAME ),
|
||||
'updated',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
return $response->body;
|
||||
} else {
|
||||
$this->save_error_notification( $response,
|
||||
__( 'Payment preferences were not saved.', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function _order_comparator( $order1, $order2 ) {
|
||||
return strcmp( $order1->created_at, $order2->created_at ) * -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function get_purchases() {
|
||||
$response = $this->request_api( 'GET', AI1EC_API_URL . 'calendars/' . $this->_get_ticket_calendar() . '/sales',
|
||||
null, //body
|
||||
true //decode response body
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$result = $response->body;
|
||||
if ( isset( $result->orders ) ) {
|
||||
usort( $result->orders, array( "Ai1ec_Api_Registration", "_order_comparator" ) );
|
||||
return $result->orders;
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
} else {
|
||||
$this->save_error_notification( $response,
|
||||
__( 'We were unable to get the Sales information from Time.ly Network', AI1EC_PLUGIN_NAME )
|
||||
);
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync settings from API after signing in
|
||||
*/
|
||||
public function sync_api_settings() {
|
||||
// Sync feeds subscriptions
|
||||
try {
|
||||
$api_feed = $this->_registry->get( 'model.api.api-feeds' );
|
||||
$api_feed->get_and_sync_feed_subscriptions();
|
||||
} catch ( Exception $e ) {
|
||||
$error_message = 'Some feeds were not imported to Time.ly Network. Error: ' . $e->getMessage();
|
||||
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $error_message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<?php
|
||||
class Ai1ec_Api_Settings {
|
||||
const FACEBOOK_API_KEY = 'facebook_api_key';
|
||||
}
|
||||
@@ -0,0 +1,901 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class for Timely API communication for Ticketing.
|
||||
*
|
||||
* @author Time.ly Network, Inc.
|
||||
* @since 2.4
|
||||
* @package Ai1EC
|
||||
* @subpackage Ai1EC.Model
|
||||
*/
|
||||
class Ai1ec_Api_Ticketing extends Ai1ec_Api_Abstract {
|
||||
|
||||
const API_EVENT_DATA = '_ai1ec_api_event_id';
|
||||
|
||||
const ATTR_EVENT_ID = 'api_event_id';
|
||||
const ATTR_THUMBNAIL_ID = 'thumbnail_id';
|
||||
const ATTR_ICS_CHECKOUT_URL = 'ics_checkout_url';
|
||||
const ATTR_ICS_API_URL = 'ics_api_url';
|
||||
const ATTR_ACCOUNT = 'account';
|
||||
const ATTR_CALENDAR_ID = 'calendar_id';
|
||||
const ATTR_CURRENCY = 'currency';
|
||||
|
||||
const MAX_TICKET_TO_BUY_DEFAULT = 25;
|
||||
|
||||
/**
|
||||
* Post construction routine.
|
||||
*
|
||||
* Override this method to perform post-construction tasks.
|
||||
*
|
||||
* @return void Return from this method is ignored.
|
||||
*/
|
||||
protected function _initialize() {
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the valid Tickets Types (not removed) included inside the Ticket Event
|
||||
*/
|
||||
private function _count_valid_tickets( $post_ticket_types ) {
|
||||
if (false === isset( $post_ticket_types ) || 0 === count( $post_ticket_types ) ) {
|
||||
return 0;
|
||||
} else {
|
||||
$count = 0;
|
||||
foreach ( $post_ticket_types as $ticket_type_ite ) {
|
||||
if ( !isset( $ticket_type_ite['remove'] ) ) {
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error if the Ticket Event is not owned by the Current account
|
||||
*/
|
||||
private function _prevent_update_ticket_event( Ai1ec_Event $event, $ajax_action = false ) {
|
||||
if ( $this->is_ticket_event_imported( $event->get( 'post_id' ) ) ) {
|
||||
//prevent changes on Ticket Events that were imported
|
||||
$error = __( 'This Event was replicated from another site. Changes are not allowed.', AI1EC_PLUGIN_NAME );
|
||||
if ( ! $ajax_action ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
$error,
|
||||
'error',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $event->get( 'post_id' ) ) ) {
|
||||
//prevent changes on Ticket Events that were imported
|
||||
$error = sprintf(
|
||||
__( 'This Event was created using a different account %s. Changes are not allowed.', AI1EC_PLUGIN_NAME ),
|
||||
$this->get_api_event_account( $event->get( 'post_id' ) )
|
||||
);
|
||||
if ( ! $ajax_action ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store(
|
||||
$error,
|
||||
'error',
|
||||
0,
|
||||
array( Ai1ec_Notification_Admin::RCPT_ADMIN ),
|
||||
false
|
||||
);
|
||||
}
|
||||
return $error;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run some validations inside the _POST request to check if the Event
|
||||
* submmited is a valid event for Tickets
|
||||
* @return NULL in case of success or a Message in case of error
|
||||
*/
|
||||
private function _is_valid_post( Ai1ec_Event $event, $updating ) {
|
||||
$message = null;
|
||||
if ( ( isset( $_POST['ai1ec_rdate'] ) && ! empty( $_POST['ai1ec_rdate'] ) ) ||
|
||||
( isset( $_POST['ai1ec_repeat'] ) && ! empty( $_POST['ai1ec_repeat'] ) )
|
||||
) {
|
||||
$message = __( 'The Repeat option was selected but recurrence is not supported by Event with Tickets.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( isset( $_POST['ai1ec_tickets_loading_error'] ) ) {
|
||||
//do not update tickets because is unsafe. There was a problem to load the tickets,
|
||||
//the customer received the same message when the event was loaded.
|
||||
$message = $_POST['ai1ec_tickets_loading_error'];
|
||||
} else if ( false === ai1ec_is_blank( $event->get( 'ical_feed_url' ) ) ) {
|
||||
//prevent ticket creating inside Regular Events Imported events
|
||||
$message = __( 'This Event was replicated from another site. Any changes on Tickets were discarded.', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$error = $this->_prevent_update_ticket_event( $event );
|
||||
if ( null !== $error ) {
|
||||
$message = $error;
|
||||
} else if ( ! isset( $_POST['ai1ec_tickets'] ) || 0 === $this->_count_valid_tickets( $_POST['ai1ec_tickets'] ) ) {
|
||||
$message = __( 'The Event has the cost option Ticket selected but no ticket was included.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( false === $this->has_payment_settings() ) {
|
||||
$message = __( 'You need to save the payments settings to create ticket events.', AI1EC_PLUGIN_NAME );
|
||||
} else if ( ! isset( $_POST['tax_options'] ) && ! $updating ) {
|
||||
$message = __( 'Tax and Invoice options are required.', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
}
|
||||
if ( null !== $message ) {
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create or update a Ticket Event on API server
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function store_event( Ai1ec_Event $event, WP_Post $post, $updating ) {
|
||||
|
||||
$error = $this->_is_valid_post( $event, $updating );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
$api_event_id = $this->get_api_event_id( $event->get( 'post_id' ) );
|
||||
$is_new = ! $api_event_id;
|
||||
$fields = array( 'visibility' => $_POST['visibility'] );
|
||||
if ( isset( $_POST['tax_options'] ) ) {
|
||||
$fields['tax_options'] = $_POST['tax_options'];
|
||||
}
|
||||
$body_data = $this->parse_event_fields_to_api_structure(
|
||||
$event,
|
||||
$post,
|
||||
$_POST['ai1ec_tickets'],
|
||||
$fields
|
||||
);
|
||||
$url = AI1EC_API_URL . 'events';
|
||||
if ( $api_event_id ) {
|
||||
$url = $url . '/' . $api_event_id;
|
||||
}
|
||||
|
||||
//get the thumbnail id saved previously
|
||||
$api_data = $this->get_api_event_data( $event->get( 'post_id' ) );
|
||||
if ( isset( $api_data[self::ATTR_THUMBNAIL_ID] ) ) {
|
||||
$event_thumbnail_id = $api_data[self::ATTR_THUMBNAIL_ID];
|
||||
} else {
|
||||
$event_thumbnail_id = 0;
|
||||
}
|
||||
//get the current thumbnail id
|
||||
$post_thumbnail_id = get_post_thumbnail_id( $event->get( 'post_id' ) );
|
||||
if ( false === isset( $post_thumbnail_id ) ) {
|
||||
$post_thumbnail_id = 0;
|
||||
}
|
||||
$update_image = ( $event_thumbnail_id !== $post_thumbnail_id );
|
||||
$payload = '';
|
||||
$custom_headers = null;
|
||||
|
||||
if ( true === $update_image && 0 < $post_thumbnail_id ) {
|
||||
$boundary = wp_generate_password( 24 );
|
||||
$custom_headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
|
||||
$body_data['update_image'] = '1';
|
||||
foreach ($body_data as $key => $value) {
|
||||
if ( is_array( $value ) ) {
|
||||
$index = 0;
|
||||
foreach ( $value as $arr_key => $arr_value ) {
|
||||
if ( is_array( $arr_value ) ) {
|
||||
foreach ( $arr_value as $child_key => $child_value ) {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . $key . '[' . $index . '][' . $child_key . ']"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $child_value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
} else {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="tax_options[' . $arr_key . ']"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $arr_value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
} else {
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= $value;
|
||||
$payload .= "\r\n";
|
||||
}
|
||||
}
|
||||
$file_path = get_attached_file ( $post_thumbnail_id );
|
||||
$file_type = wp_check_filetype ( $file_path );
|
||||
$payload .= '--' . $boundary;
|
||||
$payload .= "\r\n";
|
||||
$payload .= 'Content-Disposition: form-data; name="image_id"; filename="' . basename( $file_path ) . '"' . "\r\n";
|
||||
$payload .= 'Content-Type: ' . $file_type['type'] . "\r\n";
|
||||
$payload .= "\r\n";
|
||||
$payload .= file_get_contents( $file_path );
|
||||
$payload .= "\r\n";
|
||||
$payload .= '--' . $boundary . '--';
|
||||
} else {
|
||||
$body_data['update_image'] = (true === $update_image) ? '1' : '0';
|
||||
$payload = $body_data;
|
||||
}
|
||||
$response = $this->request_api( 'POST', $url, $payload,
|
||||
true, //true to decode response body
|
||||
$custom_headers
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$api_event_id = $response->body->id;
|
||||
if ( isset( $response->body->currency ) ) {
|
||||
$currency = $response->body->currency;
|
||||
} else {
|
||||
$currency = 'USD';
|
||||
}
|
||||
$currency = $response->body->currency;
|
||||
if ( $post_thumbnail_id <= 0 ) {
|
||||
$post_thumbnail_id = null;
|
||||
}
|
||||
$this->save_api_event_data( $event->get( 'post_id') , $api_event_id, null, null, $currency, $post_thumbnail_id );
|
||||
return true;
|
||||
} else {
|
||||
$error_message = '';
|
||||
if ( $is_new ) {
|
||||
$error_message = __( 'We were unable to create the Event on Time.ly Ticketing', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$error_message = __( 'We were unable to update the Event on Time.ly Ticketing', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
return $this->save_error_notification( $response, $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the fields of an Event to the structure used by API
|
||||
*/
|
||||
public function parse_event_fields_to_api_structure( Ai1ec_Event $event , WP_Post $post, $post_ticket_types, $api_fields_values ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
if ( $calendar_id <= 0 ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//fields of ai1ec events table used by API
|
||||
$body['latitude'] = $event->get( 'latitude' );
|
||||
$body['longitude'] = $event->get( 'longitude' );
|
||||
$body['post_id'] = $event->get( 'post_id' );
|
||||
$body['calendar_id'] = $calendar_id;
|
||||
$body['dtstart'] = $event->get( 'start' )->format_to_javascript();
|
||||
$body['dtend'] = $event->getenddate()->format_to_javascript();
|
||||
$body['timezone'] = $event->get( 'timezone_name' );
|
||||
$body['venue_name'] = $event->get( 'venue' );
|
||||
$body['address'] = $event->get( 'address' );
|
||||
$body['city'] = $event->get( 'city' );
|
||||
$body['province'] = $event->get( 'province' );
|
||||
$body['postal_code'] = $event->get( 'postal_code' );
|
||||
$body['country'] = $event->get( 'country' );
|
||||
$body['contact_name'] = $event->get( 'contact_name' );
|
||||
$body['contact_phone'] = $event->get( 'contact_phone' );
|
||||
$body['contact_email'] = $event->get( 'contact_email' );
|
||||
$body['contact_website'] = $event->get( 'contact_url' );
|
||||
$body['uid'] = $event->get_uid();
|
||||
$body['title'] = $post->post_title;
|
||||
$body['description'] = $post->post_content;
|
||||
$body['url'] = get_permalink( $post->ID );
|
||||
$body['status'] = $post->post_status;
|
||||
|
||||
$utc_current_time = $this->_registry->get( 'date.time')->format_to_javascript();
|
||||
$body['created_at'] = $utc_current_time;
|
||||
$body['updated_at'] = $utc_current_time;
|
||||
|
||||
//removing blank values
|
||||
foreach ($body as $key => $value) {
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
unset( $body[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_null( $api_fields_values ) || 0 == count( $api_fields_values ) ) {
|
||||
$api_fields_values = array( 'status' => 'closed', 'ai1ec_version' => AI1EC_VERSION );
|
||||
} else {
|
||||
if ( ! isset( $api_fields_values['ai1ec_version'] ) ) {
|
||||
$api_fields_values['ai1ec_version'] = AI1EC_VERSION;
|
||||
}
|
||||
foreach ( $api_fields_values as $key => $value ) {
|
||||
$body[$key] = $api_fields_values[$key];
|
||||
if ( 'visibility' === $key ) {
|
||||
if ( 0 === strcasecmp( 'private', $value ) ) {
|
||||
$body['status'] = 'private';
|
||||
} else if ( 0 === strcasecmp( 'password', $value ) ) {
|
||||
$body['status'] = 'password';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tickets_types = array();
|
||||
if ( ! is_null( $post_ticket_types ) ) {
|
||||
$index = 0;
|
||||
foreach ( $post_ticket_types as $ticket_type_ite ) {
|
||||
if ( false === isset( $ticket_type_ite['id'] ) &&
|
||||
isset( $ticket_type_ite['remove'] ) ) {
|
||||
//ignoring new tickets that didn't go to api yet
|
||||
continue;
|
||||
}
|
||||
$tickets_types[$index++] = $this->_parse_tickets_type_post_to_api_structure(
|
||||
$ticket_type_ite,
|
||||
$event
|
||||
);
|
||||
}
|
||||
}
|
||||
$body['ticket_types'] = $tickets_types;
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the fields of a Ticket Type to the structure used by API
|
||||
*/
|
||||
protected function _parse_tickets_type_post_to_api_structure( $ticket_type_ite, $event ) {
|
||||
$utc_current_time = $this->_registry->get( 'date.time' )->format_to_javascript();
|
||||
if ( isset( $ticket_type_ite['id'] ) ) {
|
||||
$ticket_type['id'] = $ticket_type_ite['id'];
|
||||
$ticket_type['created_at'] = $ticket_type_ite['created_at'];
|
||||
} else {
|
||||
$ticket_type['created_at'] = $utc_current_time;
|
||||
}
|
||||
if ( isset( $ticket_type_ite['remove'] ) ) {
|
||||
$ticket_type['deleted_at'] = $utc_current_time;
|
||||
}
|
||||
$ticket_type['name'] = $ticket_type_ite['ticket_name'];
|
||||
$ticket_type['description'] = $ticket_type_ite['description'];
|
||||
$ticket_type['price'] = $ticket_type_ite['ticket_price'];
|
||||
if ( 0 === strcasecmp( 'on', $ticket_type_ite['unlimited'] ) ) {
|
||||
$ticket_type['quantity'] = null;
|
||||
} else {
|
||||
$ticket_type['quantity'] = $ticket_type_ite['quantity'];
|
||||
}
|
||||
$ticket_type['buy_min_qty'] = $ticket_type_ite['buy_min_limit'];
|
||||
if ( ai1ec_is_blank( $ticket_type_ite['buy_max_limit'] ) ) {
|
||||
$ticket_type['buy_max_qty'] = null;
|
||||
} else {
|
||||
$ticket_type['buy_max_qty'] = $ticket_type_ite['buy_max_limit'];
|
||||
}
|
||||
if ( 0 === strcasecmp( 'on', $ticket_type_ite['availibility'] ) ) {
|
||||
//immediate availability
|
||||
$timezone_start_time = $this->_registry->get( 'date.time' );
|
||||
$timezone_start_time->set_timezone( $event->get('timezone_name') );
|
||||
$ticket_type['immediately'] = true;
|
||||
$ticket_type['sale_start_date'] = $timezone_start_time->format_to_javascript( $event->get('timezone_name') );
|
||||
$ticket_type['sale_end_date'] = $event->get( 'end' )->format_to_javascript();
|
||||
} else {
|
||||
$ticket_type['immediately'] = false;
|
||||
$ticket_type['sale_start_date'] = $ticket_type_ite['ticket_sale_start_date'];
|
||||
$ticket_type['sale_end_date'] = $ticket_type_ite['ticket_sale_end_date'];
|
||||
}
|
||||
$ticket_type['updated_at'] = $utc_current_time;
|
||||
$ticket_type['status'] = $ticket_type_ite['ticket_status'];
|
||||
return $ticket_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unparse the fields of API structure to the Ticket Type
|
||||
*/
|
||||
protected function _unparse_tickets_type_from_api_structure( $ticket_type_api ) {
|
||||
$ticket_type = $ticket_type_api;
|
||||
$ticket_type->ticket_name = $ticket_type_api->name;
|
||||
$ticket_type->ticket_price = $ticket_type_api->price;
|
||||
$ticket_type->buy_min_limit = $ticket_type_api->buy_min_qty;
|
||||
if ( null === $ticket_type_api->buy_max_qty ) {
|
||||
$ticket_type->buy_max_limit = self::MAX_TICKET_TO_BUY_DEFAULT;
|
||||
} else {
|
||||
$ticket_type->buy_max_limit = $ticket_type_api->buy_max_qty;
|
||||
}
|
||||
if ( true === ( ( bool ) $ticket_type_api->immediately ) ) {
|
||||
$ticket_type->availibility = 'on';
|
||||
} else {
|
||||
$ticket_type->availibility = 'off';
|
||||
}
|
||||
$ticket_type->ticket_sale_start_date = $ticket_type_api->sale_start_date; //YYYY-MM-YY HH:NN:SS
|
||||
$ticket_type->ticket_sale_end_date = $ticket_type_api->sale_end_date; //YYYY-MM-YY HH:NN:SS
|
||||
$ticket_type->ticket_status = $ticket_type_api->status;
|
||||
if ( 'open' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Open for sale', AI1EC_PLUGIN_NAME );
|
||||
} else if ( 'closed' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Sale ended', AI1EC_PLUGIN_NAME );
|
||||
} else if ( 'canceled' === $ticket_type_api->status ) {
|
||||
$ticket_type->ticket_status_label = __( 'Canceled', AI1EC_PLUGIN_NAME );
|
||||
} else {
|
||||
$ticket_type->ticket_status_label = $ticket_type_api->status;
|
||||
}
|
||||
if ( false === isset( $ticket_type_api->quantity ) ||
|
||||
null === $ticket_type_api->quantity ) {
|
||||
$ticket_type->unlimited = 'on';
|
||||
} else {
|
||||
$ticket_type->unlimited = 'off';
|
||||
}
|
||||
$ticket_type->ticket_type_id = $ticket_type_api->id;
|
||||
$ticket_type->available = $ticket_type_api->available;
|
||||
$ticket_type->availability = $this->_parse_availability_message( $ticket_type_api->availability );
|
||||
|
||||
//derived property to set the max quantity of dropdown
|
||||
if ( $ticket_type->available !== null ) {
|
||||
if ( $ticket_type->available > $ticket_type->buy_max_limit ) {
|
||||
$ticket_type->buy_max_available = $ticket_type->buy_max_limit;
|
||||
} else {
|
||||
$ticket_type->buy_max_available = $ticket_type->available;
|
||||
}
|
||||
} else {
|
||||
$ticket_type->buy_max_available = $ticket_type->buy_max_limit;
|
||||
}
|
||||
return $ticket_type;
|
||||
}
|
||||
|
||||
public function _parse_availability_message( $availability ){
|
||||
if ( ai1ec_is_blank ( $availability ) ) {
|
||||
return null;
|
||||
} else {
|
||||
switch ($availability) {
|
||||
case 'past_event':
|
||||
return __( 'Past Event' );
|
||||
case 'event_closed':
|
||||
return __( 'Event closed' );
|
||||
case 'not_available_yet':
|
||||
return __( 'Not available yet' );
|
||||
case 'sale_closed':
|
||||
return __( 'Sale closed' );
|
||||
case 'sold_out':
|
||||
return __( 'Sold out' );
|
||||
default:
|
||||
return __( 'Not available' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_event( $post_id ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return (object) array( 'data' => array() );
|
||||
}
|
||||
$response = $this->request_api( 'GET', $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/edit' );
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
if ( isset( $response->body->ticket_types ) ) {
|
||||
foreach ( $response->body->ticket_types as $ticket_api ) {
|
||||
$this->_unparse_tickets_type_from_api_structure( $ticket_api );
|
||||
}
|
||||
}
|
||||
return (object) array( 'data' => $response->body );
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Event Details from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response->raw, $response->url,
|
||||
true
|
||||
);
|
||||
return (object) array( 'data' => array(), 'error' => $error_message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string JSON.
|
||||
*/
|
||||
public function get_ticket_types( $post_id, $get_canceled = true ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
$response = $this->request_api( 'GET', $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/ticket_types',
|
||||
array( 'get_canceled' => ( true === $get_canceled ? 1 : 0 ) )
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
if ( isset( $response->body->ticket_types ) ) {
|
||||
foreach ( $response->body->ticket_types as $ticket_api ) {
|
||||
$this->_unparse_tickets_type_from_api_structure( $ticket_api );
|
||||
}
|
||||
return json_encode( array( 'data' => $response->body->ticket_types ) );
|
||||
} else {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Tickets Details from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response->raw, $response->url,
|
||||
true
|
||||
);
|
||||
return json_encode( array( 'data' => array(), 'error' => $error_message ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object Response body in JSON.
|
||||
*/
|
||||
public function get_tickets( $post_id ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return json_encode( array( 'data' => array() ) );
|
||||
}
|
||||
$request = array(
|
||||
'headers' => $this->_get_headers(),
|
||||
'timeout' => parent::DEFAULT_TIMEOUT
|
||||
);
|
||||
$url = $this->get_api_event_url( $post_id ) . 'events/' . $api_event_id . '/tickets';
|
||||
$response = wp_remote_get( $url, $request );
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 === $response_code ) {
|
||||
return $response['body'];
|
||||
} else {
|
||||
$error_message = $this->_transform_error_message(
|
||||
__( 'We were unable to get the Tickets Attendees from Time.ly Ticketing', AI1EC_PLUGIN_NAME ),
|
||||
$response, $url,
|
||||
true
|
||||
);
|
||||
return json_encode( array( 'data' => array(), 'error' => $error_message ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a Ticket Event was imported from an ICS Feed
|
||||
*/
|
||||
public function is_ticket_event_imported( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) && isset( $data[self::ATTR_ICS_API_URL] ) ) {
|
||||
return ( ! ai1ec_is_blank ( $data[self::ATTR_ICS_API_URL] ) );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Ticket Event was created using a different account
|
||||
* The user probably created the event from one account, signed out and
|
||||
* is currently signed in with a new account
|
||||
*/
|
||||
public function is_ticket_event_from_another_account( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ACCOUNT] ) ) {
|
||||
return ( $this->get_current_account() != $data[self::ATTR_ACCOUNT] );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API account where the event was created
|
||||
* @param int $post_id Post ID
|
||||
* @param bool $default_null True to return NULL if the value does not exist, false to return the configured API URL
|
||||
*/
|
||||
public function get_api_event_account( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ACCOUNT] ) ) {
|
||||
return $data[self::ATTR_ACCOUNT];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the response that came from the API is the event not found
|
||||
*/
|
||||
private function _is_event_notfound_error( $response ) {
|
||||
if ( isset( $response->response_code ) && 404 === $response->response_code ) {
|
||||
if ( isset( $response->body ) ) {
|
||||
if ( is_array( $response->body ) &&
|
||||
isset( $response->body['message'] ) ) {
|
||||
if ( false !== stripos( $response->body['message'], 'event not found') ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return NULL in case of success or an error string in case of error
|
||||
*/
|
||||
public function update_api_event_fields( WP_Post $post, $api_fields_values, $post_action = 'trash', $ajax_action = false ) {
|
||||
$post_id = $post->ID;
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
$message = __( 'Event not found inside the database.', AI1EC_PLUGIN_NAME );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
if ( 'update' === $post_action ) {
|
||||
$error = $this->_prevent_update_ticket_event( $event, $ajax_action );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
} else {
|
||||
if ( $this->is_ticket_event_imported( $post_id ) ) {
|
||||
return null;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $post_id ) ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$headers = $this->_get_headers();
|
||||
$body_data = $this->parse_event_fields_to_api_structure(
|
||||
$event,
|
||||
$post,
|
||||
null, //does not update ticket types, just chaging the api fields specified
|
||||
$api_fields_values
|
||||
);
|
||||
$response = $this->request_api( 'POST',
|
||||
AI1EC_API_URL . 'events/' . $api_event_id,
|
||||
$body_data,
|
||||
true //true to decode response body
|
||||
);
|
||||
if ( ! $this->is_response_success( $response ) ) {
|
||||
if ( $this->_is_event_notfound_error( $response ) ) {
|
||||
if ( isset( $api_fields_values['status'] ) &&
|
||||
'trash' === $api_fields_values['status'] ) {
|
||||
//this is an exception, the event was deleted on API server, but for some reason
|
||||
//the metada was not unset, in this case leave the event be
|
||||
//move to trash
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$message = $this->save_error_notification( $response, __( 'We were unable to Update the Event on Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return $message;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the API event
|
||||
* @return NULL in case of success or an error string in case of error
|
||||
*/
|
||||
public function delete_api_event( $post_id, $post_action = 'delete', $ajax_action = false ) {
|
||||
$api_event_id = $this->get_api_event_id( $post_id );
|
||||
if ( ! $api_event_id ) {
|
||||
return null;
|
||||
}
|
||||
if ( 'update' === $post_action ) {
|
||||
try {
|
||||
$event = $this->_registry->get( 'model.event', $post_id );
|
||||
} catch ( Ai1ec_Event_Not_Found_Exception $excpt ) {
|
||||
$message = __( 'Event not found inside the database.', AI1EC_PLUGIN_NAME );
|
||||
$notification = $this->_registry->get( 'notification.admin' );
|
||||
$notification->store( $message, 'error', 0, array( Ai1ec_Notification_Admin::RCPT_ADMIN ), false );
|
||||
return $message;
|
||||
}
|
||||
$error = $this->_prevent_update_ticket_event( $event, $ajax_action );
|
||||
if ( null !== $error ) {
|
||||
return $error;
|
||||
}
|
||||
} else {
|
||||
if ( $this->is_ticket_event_imported( $post_id ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
if ( $this->is_ticket_event_from_another_account( $post_id ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$response = $this->request_api( 'DELETE',
|
||||
AI1EC_API_URL . 'events/' . $api_event_id,
|
||||
true //true to decode response body
|
||||
);
|
||||
if ( $this->is_response_success( $response ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
} else {
|
||||
if ( $this->_is_event_notfound_error( $response ) ) {
|
||||
$this->clear_event_metadata( $post_id );
|
||||
return null;
|
||||
}
|
||||
$message = $this->save_error_notification( $response, __( 'We were unable to remove the Event on Time.ly Network', AI1EC_PLUGIN_NAME ) );
|
||||
return $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the event metadata used by Event from the post id
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function clear_event_metadata( $post_id ) {
|
||||
delete_post_meta( $post_id, self::API_EVENT_DATA );
|
||||
}
|
||||
|
||||
public function get_api_event_data( $post_id ) {
|
||||
$data = get_post_meta(
|
||||
$post_id,
|
||||
self::API_EVENT_DATA,
|
||||
true
|
||||
);
|
||||
if ( ai1ec_is_blank ( $data ) ) {
|
||||
return null;
|
||||
} else if ( is_numeric( $data ) ) {
|
||||
//migrate the old metadata into one
|
||||
$new_data[self::ATTR_EVENT_ID] = $data;
|
||||
$value = get_post_meta( $post_id, '_ai1ec_thumbnail_id', true );
|
||||
if ( false === ai1ec_is_blank( $value ) ) {
|
||||
$new_data[self::ATTR_THUMBNAIL_ID] = $value;
|
||||
}
|
||||
$value = get_post_meta( $post_id, '_ai1ec_ics_checkout_url', true );
|
||||
if ( false === ai1ec_is_blank( $value ) ) {
|
||||
$new_data[self::ATTR_ICS_CHECKOUT_URL] = $value;
|
||||
}
|
||||
$value = get_post_meta( $post_id, '_ai1ec_ics_api_url' , true );
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
//not imported ticket event
|
||||
$new_data[self::ATTR_ACCOUNT] = $this->get_current_account();
|
||||
$new_data[self::ATTR_CALENDAR_ID] = $this->get_current_calendar();
|
||||
} else {
|
||||
$new_data[self::ATTR_ICS_API_URL] = $value;
|
||||
}
|
||||
$new_data[self::ATTR_CURRENCY] = 'USD';
|
||||
update_post_meta( $post_id, self::API_EVENT_DATA, $new_data );
|
||||
return $new_data;
|
||||
} else if ( is_array( $data ) ) {
|
||||
return $data;
|
||||
} else {
|
||||
wp_die( 'Error geting the api data' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the id of the event on the API
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_id( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
return $data[self::ATTR_EVENT_ID];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API URL of the event
|
||||
* @param int $post_id Post ID
|
||||
* @param bool $default_null True to return NULL if the value does not exist, false to return the configured API URL
|
||||
*/
|
||||
public function get_api_event_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ICS_API_URL] ) ) {
|
||||
return $data[self::ATTR_ICS_API_URL];
|
||||
} else {
|
||||
return AI1EC_API_URL;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Currency of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_currency ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_CURRENCY] ) ) {
|
||||
return $data[self::ATTR_CURRENCY];
|
||||
} else {
|
||||
return 'USD';
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Checkout url of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_checkout_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
if ( isset( $data[self::ATTR_ICS_CHECKOUT_URL] ) ) {
|
||||
return $data[self::ATTR_ICS_CHECKOUT_URL];
|
||||
} else {
|
||||
return AI1EC_TICKETS_CHECKOUT_URL;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Buy Ticket URL of the event
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
public function get_api_event_buy_ticket_url ( $post_id ) {
|
||||
$data = $this->get_api_event_data( $post_id );
|
||||
if ( isset( $data[self::ATTR_EVENT_ID] ) ) {
|
||||
$api_event_id = $data[self::ATTR_EVENT_ID];
|
||||
if ( isset( $data[self::ATTR_ICS_CHECKOUT_URL] ) ) {
|
||||
$checkout_url = $data[self::ATTR_ICS_CHECKOUT_URL];
|
||||
} else {
|
||||
$checkout_url = AI1EC_TICKETS_CHECKOUT_URL;
|
||||
}
|
||||
return str_replace( '{event_id}', $api_event_id, $checkout_url );
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax options modal
|
||||
* @param int $event_id Event ID (optional)
|
||||
*/
|
||||
public function get_tax_options_modal( $post_id = null ) {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
$event_id = $this->get_api_event_id( $post_id );
|
||||
$response = $this->request_api( 'GET',
|
||||
AI1EC_API_URL . 'calendars/' . $calendar_id . '/tax_options' .
|
||||
( is_null( $event_id ) ? '' : '?event_id=' . $event_id )
|
||||
);
|
||||
return (object) array( 'data' => $response->raw, 'error' => false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tax options modal
|
||||
* @param int $event_id Event ID (optional)
|
||||
*/
|
||||
public function get_tax_options_modal_ep() {
|
||||
$calendar_id = $this->_get_ticket_calendar();
|
||||
$response = $this->request_api( 'GET',
|
||||
AI1EC_API_URL . 'eventpromote/' . $calendar_id . '/tax_options'
|
||||
);
|
||||
return (object) array( 'data' => $response->raw, 'error' => false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the API event data
|
||||
* @param int $post_id Post ID
|
||||
* @param int $api_event_id (optional) Id of the event on the API
|
||||
* @param string $ics_api_url (optional) API URL of the event on the API (used when importing an ICS feed)
|
||||
* @param string $ics_checkout_url (optional) API CHECKOUT URL of the event on the API (used when importing an ICS feed)
|
||||
* @param string $currency (optional) Currency code of the event
|
||||
* @param string $thumbnail_id (optional) Id of the Thumbnail (Featured Image id)
|
||||
*/
|
||||
public function save_api_event_data( $post_id, $api_event_id, $ics_api_url = null, $ics_checkout_url = null, $currency = null, $thumbnail_id = null ) {
|
||||
if ( ai1ec_is_blank( $api_event_id ) ) {
|
||||
throw new Error( 'Api event id should never be null' );
|
||||
}
|
||||
$api_data[self::ATTR_EVENT_ID] = $api_event_id;
|
||||
$api_data[self::ATTR_ICS_API_URL] = $ics_api_url;
|
||||
$api_data[self::ATTR_ICS_CHECKOUT_URL] = $ics_checkout_url;
|
||||
$api_data[self::ATTR_CURRENCY] = $currency;
|
||||
$api_data[self::ATTR_THUMBNAIL_ID] = $thumbnail_id;
|
||||
if ( ai1ec_is_blank( $ics_api_url ) ) {
|
||||
$api_data[self::ATTR_ACCOUNT] = $this->get_current_account();
|
||||
$api_data[self::ATTR_CALENDAR_ID] = $this->get_current_calendar();
|
||||
}
|
||||
$previous_data = $this->get_api_event_data( $post_id );
|
||||
$new_data = array();
|
||||
if ( is_array( $previous_data ) ) {
|
||||
foreach ( $previous_data as $key => $value) {
|
||||
$new_data[$key] = $value;
|
||||
}
|
||||
}
|
||||
foreach ( $api_data as $key => $value ) {
|
||||
if ( ai1ec_is_blank( $value ) ) {
|
||||
unset( $new_data[$key] );
|
||||
} else {
|
||||
$new_data[$key] = $api_data[$key];
|
||||
}
|
||||
}
|
||||
return update_post_meta( $post_id, self::API_EVENT_DATA, $new_data, $previous_data );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user