608 lines
18 KiB
PHP
608 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* Simply Schedule Appointments Support Status Api.
|
|
*
|
|
* @since 2.1.6
|
|
* @package Simply_Schedule_Appointments
|
|
*/
|
|
|
|
/**
|
|
* Simply Schedule Appointments Support Status Api.
|
|
*
|
|
* @since 2.1.6
|
|
*/
|
|
class SSA_Support_Status_Api extends WP_REST_Controller {
|
|
/**
|
|
* Parent plugin class
|
|
*
|
|
* @var class
|
|
* @since 1.0.0
|
|
*/
|
|
protected $plugin = null;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @since 1.0.0
|
|
* @param object $plugin Main plugin object.
|
|
* @return void
|
|
*/
|
|
public function __construct( $plugin ) {
|
|
$this->plugin = $plugin;
|
|
$this->hooks();
|
|
}
|
|
|
|
/**
|
|
* Initiate our hooks
|
|
*
|
|
* @since 1.0.0
|
|
* @return void
|
|
*/
|
|
public function hooks() {
|
|
$this->register_routes();
|
|
}
|
|
|
|
|
|
/**
|
|
* Register the routes for the objects of the controller.
|
|
*/
|
|
public function register_routes() {
|
|
$version = '1';
|
|
$namespace = 'ssa/v' . $version;
|
|
$base = 'support_status';
|
|
register_rest_route( $namespace, '/' . $base, array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_items' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support_ticket', array(
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'create_support_ticket' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support_debug/wp', array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_wp_debug_log_content' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support_debug/wp/delete', array(
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'empty_wp_debug_log_content' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
|
|
register_rest_route( $namespace, '/' . 'support_debug/ssa', array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_ssa_debug_log_content' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support_debug/ssa/delete', array(
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'empty_ssa_debug_log_content' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support_debug/logs', array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_debug_log_urls' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support/export', array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_export_code' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route( $namespace, '/' . 'support/import', array(
|
|
array(
|
|
'methods' => WP_REST_Server::CREATABLE,
|
|
'callback' => array( $this, 'import_data_api' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
'args' => array(
|
|
|
|
),
|
|
),
|
|
) );
|
|
|
|
register_rest_route(
|
|
$namespace,
|
|
'/fetch-guides',
|
|
array(
|
|
array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'get_guides' ),
|
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
|
),
|
|
)
|
|
);
|
|
|
|
register_rest_route( $namespace, '/user/check', array(
|
|
'methods' => WP_REST_Server::READABLE,
|
|
'callback' => array( $this, 'check_user_login_status' ),
|
|
'permission_callback' => '__return_true',
|
|
) );
|
|
}
|
|
|
|
public function check_user_login_status( $request ) {
|
|
|
|
$data = array(
|
|
'is_user_logged_in' => is_user_logged_in(),
|
|
);
|
|
|
|
$response = array(
|
|
'response_code' => 200,
|
|
'error' => '',
|
|
'data' => $data
|
|
);
|
|
|
|
return new WP_REST_Response( $response, 200 );
|
|
}
|
|
|
|
|
|
public function create_support_ticket( $request ) {
|
|
// queue the minimal ticket sending here
|
|
$params = $request->get_params();
|
|
$debug_logs_hash = SSA_Debug::get_site_unique_hash_for_debug_logs();
|
|
ssa_schedule_single_action( time() + 30, 'ssa/support/send_minimal_support_ticket', array( 'params' => [...$params, 'export_code' => '{}', 'debug_logs_hash' => $debug_logs_hash] ) );
|
|
|
|
if ( ! empty( $params['include_active_plugins'] ) ) {
|
|
$params['active_plugins'] = array();
|
|
$active_plugins = get_option( 'active_plugins' );
|
|
sort( $active_plugins );
|
|
foreach ($active_plugins as $active_plugin) {
|
|
if ( strpos( $active_plugin, '/' ) ) {
|
|
$active_plugin = substr( $active_plugin, 0, strpos( $active_plugin, '/' ) );
|
|
}
|
|
$params['active_plugins'][] = $active_plugin;
|
|
}
|
|
unset( $params['include_active_plugins'] );
|
|
}
|
|
|
|
if ( ! empty( $params['include_settings'] ) ) {
|
|
$params['site_hash_for_debug_logs'] = $debug_logs_hash;
|
|
unset( $params['include_settings'] );
|
|
}
|
|
|
|
$result = self::ssa_send_support_ticket( $params, $debug_logs_hash );
|
|
if ( !is_wp_error( $result ) ) {
|
|
// remove the queued ticket from the queue
|
|
ssa_unschedule_all_actions( 'ssa/support/send_minimal_support_ticket' );
|
|
}
|
|
return $result;
|
|
}
|
|
public static function ssa_send_support_ticket($params = array(), $debug_logs_hash = '') {
|
|
$response = wp_remote_post( 'https://api.simplyscheduleappointments.com/support_ticket/', array(
|
|
'sslverify' => false,
|
|
'headers' => array(
|
|
'content-type' => 'application/json',
|
|
),
|
|
'body' => json_encode( $params ),
|
|
) );
|
|
|
|
$response_code = wp_remote_retrieve_response_code($response);
|
|
if( $response_code > 299 || $response_code < 200 ) {
|
|
ssa_debug_log( "Failed to submit support ticket - invalid response code - response: " .print_r ( $response, true), 100 ); //phpcs:ignore
|
|
return new WP_Error( 'failed_submission', __( 'Your support ticket failed to be sent, please send details to support@ssaplugin.com', 'simply-schedule-appointments' ), $debug_logs_hash );
|
|
}
|
|
|
|
$response = wp_remote_retrieve_body( $response );
|
|
if ( empty( $response ) ) {
|
|
ssa_debug_log( "Failed to submit support ticket - response empty - response: " .print_r ( $response, true), 100 ); //phpcs:ignore
|
|
return new WP_Error( 'empty_response', __( 'No response', 'simply-schedule-appointments' ), $debug_logs_hash );
|
|
}
|
|
$response = json_decode( $response, true );
|
|
if ( ! is_array( $response ) ) {
|
|
$response = json_decode( $response, true );
|
|
}
|
|
|
|
if ($response['status'] != 'success' ) {
|
|
ssa_debug_log( "Failed to submit support ticket - status != success - response: " .print_r ( $response, true), 100 ); //phpcs:ignore
|
|
return new WP_Error( 'failed_submission', __( 'Your support ticket failed to be sent, please send details to support@ssaplugin.com', 'simply-schedule-appointments' ), $debug_logs_hash );
|
|
}
|
|
return $response;
|
|
}
|
|
|
|
public function get_items_permissions_check( $request ) {
|
|
return current_user_can( 'ssa_manage_site_settings' );
|
|
}
|
|
|
|
public function get_items( $request ) {
|
|
$params = $request->get_params();
|
|
|
|
return array(
|
|
'response_code' => 200,
|
|
'error' => '',
|
|
'data' => array(
|
|
'site_status' => $this->plugin->support_status->get_site_status(),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Gets the default debug.log contents.
|
|
*
|
|
* @param WP_REST_Request $request
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_wp_debug_log_content( WP_REST_Request $request ) {
|
|
$developer_settings = $this->plugin->developer_settings->get();
|
|
if( $developer_settings && isset( $developer_settings['debug_mode'] ) && $developer_settings['debug_mode'] ) {
|
|
$path = ini_get('error_log');
|
|
// return $path;
|
|
if ( file_exists( $path ) && is_writeable( $path ) ) {
|
|
$content = file_get_contents( $path );
|
|
|
|
return new WP_REST_Response( $content, 200 );
|
|
}
|
|
}
|
|
|
|
return new WP_REST_Response( "", 200 );
|
|
}
|
|
|
|
|
|
/**
|
|
* Deletes the default debug.log file.
|
|
*
|
|
* @param WP_REST_Request $request
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function empty_wp_debug_log_content( WP_REST_Request $request ) {
|
|
$path = ini_get('error_log');
|
|
if ( file_exists( $path ) && is_writeable( $path ) ) {
|
|
unlink( $path );
|
|
|
|
return new WP_REST_Response( __( 'Debug Log file successfully cleared.' ), 200 );
|
|
} else {
|
|
return new WP_REST_Response( __( 'Debug Log file not found.' ), 200 );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the ssa_debug.log contents.
|
|
*
|
|
* @param WP_REST_Request $request
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_ssa_debug_log_content( WP_REST_Request $request ) {
|
|
$developer_settings = $this->plugin->developer_settings->get();
|
|
if( $developer_settings && isset( $developer_settings['ssa_debug_mode'] ) && $developer_settings['ssa_debug_mode'] ) {
|
|
$path = $this->plugin->support_status->get_log_file_path( 'debug' );
|
|
if ( file_exists( $path ) && is_readable( $path ) ) {
|
|
$content = file_get_contents( $path );
|
|
|
|
return new WP_REST_Response( $content, 200 );
|
|
}
|
|
}
|
|
|
|
return new WP_REST_Response( "", 200 );
|
|
}
|
|
|
|
/**
|
|
* Deletes the ssa_debug.log file.
|
|
*
|
|
* @param WP_REST_Request $request
|
|
* @return void
|
|
*/
|
|
public function empty_ssa_debug_log_content( WP_REST_Request $request ) {
|
|
$path = $this->plugin->support_status->get_log_file_path( 'debug' );
|
|
if ( file_exists( $path ) && is_writeable( $path ) ) {
|
|
unlink( $path );
|
|
|
|
return new WP_REST_Response( __( 'Debug Log file successfully cleared.' ), 200 );
|
|
} else {
|
|
return new WP_REST_Response( __( 'Debug Log file not found or could not be removed.' ), 200 );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the urls for all debug log files.
|
|
*
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_debug_log_urls() {
|
|
$logs = array(
|
|
'wp' => null,
|
|
'ssa' => null,
|
|
);
|
|
|
|
$path = ini_get('error_log');
|
|
if ( file_exists( $path ) && is_readable( $path ) ) {
|
|
$logs['wp'] = str_replace(
|
|
wp_normalize_path( untrailingslashit( ABSPATH ) ),
|
|
site_url(),
|
|
wp_normalize_path( $path )
|
|
);
|
|
}
|
|
|
|
$ssa_path = $this->plugin->support_status->get_log_file_path( 'debug' );
|
|
if ( file_exists( $ssa_path ) && is_readable( $ssa_path ) ) {
|
|
$logs['ssa'] = str_replace(
|
|
wp_normalize_path( untrailingslashit( ABSPATH ) ),
|
|
site_url(),
|
|
wp_normalize_path( $ssa_path )
|
|
);
|
|
}
|
|
|
|
return new WP_REST_Response( $logs, 200 );
|
|
}
|
|
|
|
/**
|
|
* Pulls plugin settings, Appointment Types and Appointments and returns a JSON payload to be imported into another SSA plugin.
|
|
*
|
|
* @param WP_REST_Request $request the Request payload.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_export_code( WP_REST_Request $request ) {
|
|
$params = $request->get_params();
|
|
|
|
$payload = array();
|
|
|
|
if ( isset( $params['settings'] ) && 'true' === $params['settings'] ) {
|
|
$payload['settings'] = $this->plugin->settings->get();
|
|
foreach ( $payload['settings']['notifications']['notifications'] as &$notification ) {
|
|
$subject = empty( $notification['subject'] ) ? null : $notification['subject'];
|
|
$notification['subject'] = wp_strip_all_tags( $subject );
|
|
$notification['message'] = str_ireplace(
|
|
array(
|
|
'"',
|
|
),
|
|
array(
|
|
'"',
|
|
),
|
|
$notification['message']
|
|
);
|
|
// TODO if this happens again: use html entities functions instead.
|
|
}
|
|
}
|
|
|
|
if ( isset( $params['appointment_types'] ) && 'true' === $params['appointment_types'] ) {
|
|
$payload['resource_groups'] = $this->plugin->resource_group_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['resources'] = $this->plugin->resource_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['resource_group_resources'] = $this->plugin->resource_group_resource_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['staff'] = $this->plugin->staff_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['appointment_types'] = $this->plugin->appointment_type_model->query(
|
|
array(
|
|
'order' => 'ASC', // necessary for keeping integrity with the order of rows inserted on the database.
|
|
'number' => -1,
|
|
)
|
|
);
|
|
|
|
$payload['staff_appointment_types'] = $this->plugin->staff_appointment_type_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['resource_group_appointment_types'] = $this->plugin->resource_group_appointment_type_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['appointment_type_labels'] = $this->plugin->appointment_type_label_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
}
|
|
|
|
if ( isset( $params['appointments'] ) && 'true' === $params['appointments'] ) {
|
|
$appointments = $this->plugin->appointment_model->query(
|
|
array(
|
|
'order' => 'ASC', // necessary for keeping integrity with the order of rows inserted on the database.
|
|
'number' => isset( $params['appointments_limit'] ) ? (int) $params['appointments_limit'] : -1,
|
|
'start_date_min' => isset( $params['future_appointments_only'] ) && 'true' === $params['future_appointments_only'] ? gmdate( 'Y-m-d H:i:s' ) : null,
|
|
)
|
|
);
|
|
|
|
if ( ! empty( $params['anonymize_customer_information'] ) && 'true' === $params['anonymize_customer_information'] ) {
|
|
foreach ( $appointments as &$appointment ) {
|
|
foreach ( $appointment['customer_information'] as $key => &$value ) {
|
|
switch ( $key ) {
|
|
case 'Phone':
|
|
$value = '123-456-7890';
|
|
break;
|
|
case 'Email':
|
|
$value = substr( sha1( $value ), 0, 10 ) . '@mailinator.com';
|
|
break;
|
|
default:
|
|
if ( is_array( $value ) ) {
|
|
$value = json_encode( $value );
|
|
}
|
|
$value = substr( sha1( $value ), 0, 10 );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$payload['appointments'] = $appointments;
|
|
// import meta data as well.
|
|
$payload['appointment_meta'] = $this->plugin->appointment_meta_model->query(
|
|
array(
|
|
'order' => 'ASC', // necessary for keeping integrity with the order of rows inserted on the database.
|
|
'number' => -1,
|
|
)
|
|
);
|
|
|
|
$payload['staff_appointments'] = $this->plugin->staff_appointment_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
$payload['resource_appointments'] = $this->plugin->resource_appointment_model->query(
|
|
array(
|
|
'number' => -1,
|
|
'order' => 'ASC',
|
|
)
|
|
);
|
|
|
|
} elseif ( isset( $params['appointment_types'] ) && 'true' === $params['appointment_types'] ) {
|
|
$payload['appointments'] = array();
|
|
$payload['appointment_meta'] = array();
|
|
$payload['staff_appointments'] = array();
|
|
}
|
|
|
|
// Backup export code. Conditional to avoid replacing a proper backup when generating export code to send to support.
|
|
if ( ! isset( $params['backup'] ) || 'false' !== $params['backup'] ) {
|
|
$this->plugin->support_status->save_export_backup( $payload );
|
|
}
|
|
|
|
return new WP_REST_Response( $payload, 200 );
|
|
}
|
|
|
|
/**
|
|
* Receives a JSON formatted string via POST on our REST API endpoint, and runs the import process.
|
|
*
|
|
* @param WP_REST_Request $request the request object.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function import_data_api( WP_REST_Request $request ) {
|
|
$json = $request->get_param( 'content' );
|
|
|
|
// verify if JSON data is valid.
|
|
$decoded = json_decode( $json, true );
|
|
|
|
if ( ! is_object( $decoded ) && ! is_array( $decoded ) ) {
|
|
return new WP_REST_Response( __( 'Invalid data format.'), 500 );
|
|
}
|
|
|
|
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
|
return new WP_REST_Response( __( 'Invalid data format.'), 500 );
|
|
}
|
|
|
|
$import = $this->plugin->support_status->import_data( $decoded );
|
|
|
|
// if any error happens while trying to import appointment type data, return.
|
|
if ( is_wp_error( $import ) ) {
|
|
return new WP_REST_Response( $import->get_error_messages(), 500 );
|
|
}
|
|
|
|
// everything was successfully imported.
|
|
return new WP_REST_Response( __( 'Data successfully imported!' ), 200 );
|
|
}
|
|
|
|
/**
|
|
* Checks transients to see if a request to ssa.com/guides is cached. If not, calls the API and caches the response.
|
|
*
|
|
* @since 5.4.0
|
|
*
|
|
* @param WP_REST_Request $request the request object.
|
|
* @return WP_REST_Response
|
|
*/
|
|
public function get_guides( WP_REST_Request $request ) {
|
|
$params = $request->get_params();
|
|
|
|
// $build a string to use as a transient key.
|
|
$transient_key = array();
|
|
foreach ( $params as $key => $value ) {
|
|
$transient_key[] .= $key . ':' . $value;
|
|
}
|
|
$transient_key = implode( '|', $transient_key );
|
|
$transient_name = 'ssa_guides_' . $transient_key;
|
|
|
|
$cached_response = get_transient( $transient_name );
|
|
|
|
if ( false === $cached_response ) {
|
|
$response = wp_safe_remote_get(
|
|
'https://simplyscheduleappointments.com/wp-json/ssa/v1/guides',
|
|
array(
|
|
'body' => $params,
|
|
)
|
|
);
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
return new WP_REST_Response( $response->get_error_messages(), 500 );
|
|
}
|
|
|
|
// check if the response is valid.
|
|
if ( strpos( $response['body'], 'rest_forbidden' ) !== false ) {
|
|
return new WP_REST_Response( __( 'Invalid data format.' ), 500 );
|
|
}
|
|
|
|
$cached_response = json_decode( $response['body'], true );
|
|
|
|
set_transient( $transient_name, $cached_response, WEEK_IN_SECONDS );
|
|
}
|
|
|
|
return new WP_REST_Response( $cached_response, 200 );
|
|
}
|
|
}
|