Opal-Estate-Pro/inc/api/class-opalestate-api.php

1368 lines
34 KiB
PHP
Raw Normal View History

2019-09-10 06:27:33 +02:00
<?php
/**
* Opalestate API
*
* A front-facing JSON/XML API that makes it possible to query donation data.
*
* @package Opalestate
* @subpackage Classes/API
* @copyright Copyright (c) 2019, WordImpress
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @since 1.1
*/
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Opalestate_API Class
*
* Renders API returns as a JSON/XML array
*
* @since 1.1
*/
class Opalestate_API {
/**
* Latest API Version
*/
const VERSION = 1;
/**
* Pretty Print?
*
* @var bool
* @access private
* @since 1.1
*/
private $pretty_print = false;
/**
* Log API requests?
*
* @var bool
* @access public
* @since 1.1
*/
public $log_requests = true;
/**
* Is this a valid request?
*
* @var bool
* @access private
* @since 1.1
*/
private $is_valid_request = false;
/**
* User ID Perpropertying the API Request
*
* @var int
* @access public
* @since 1.1
*/
public $user_id = 0;
/**
* Instance of Opalestate Stats class
*
* @var object
* @access private
* @since 1.1
*/
private $stats;
/**
* Response data to return
*
* @var array
* @access private
* @since 1.1
*/
private $data = array();
/**
*
* @var bool
* @access public
* @since 1.1
*/
public $override = true;
/**
* Version of the API queried
*
* @var string
* @access public
* @since 1.1
*/
private $queried_version;
/**
* All versions of the API
*
* @var string
* @access protected
* @since 1.1
*/
protected $versions = array();
/**
* Queried endpoint
*
* @var string
* @access private
* @since 1.1
*/
private $endpoint;
/**
* Endpoints routes
*
* @var object
* @access private
* @since 1.1
*/
private $routes;
/**
* Setup the Opalestate API
*
* @since 1.1
* @access public
*/
public function __construct() {
$this->versions = array(
'v1' => 'Opalestate_API',
);
add_action( 'init', array( $this, 'add_endpoint' ) );
add_action( 'wp', array( $this, 'process_query' ), - 1 );
add_filter( 'query_vars', array( $this, 'query_vars' ) );
add_action( 'show_user_profile', array( $this, 'user_key_field' ) );
add_action( 'edit_user_profile', array( $this, 'user_key_field' ) );
add_action( 'personal_options_update', array( $this, 'update_key' ) );
add_action( 'edit_user_profile_update', array( $this, 'update_key' ) );
add_action( 'opalestate_process_api_key', array( $this, 'process_api_key' ) );
// Setup a backwards compatibility check for user API Keys
add_filter( 'get_user_metadata', array( $this, 'api_key_backwards_compat' ), 10, 4 );
// Determine if JSON_PRETTY_PRINT is available
$this->pretty_print = defined( 'JSON_PRETTY_PRINT' ) ? JSON_PRETTY_PRINT : null;
// Allow API request logging to be turned off
$this->log_requests = apply_filters( 'opalestate_api_log_requests', $this->log_requests );
}
/**
* Registers a new rewrite endpoint for accessing the API
*
* @access public
*
* @param array $rewrite_rules WordPress Rewrite Rules
*
* @since 1.1
*/
public function add_endpoint( $rewrite_rules ) {
add_rewrite_endpoint( 'opalestate-api', EP_ALL );
}
/**
* Registers query vars for API access
*
* @access public
* @since 1.1
*
* @param array $vars Query vars
*
* @return string[] $vars New query vars
*/
public function query_vars( $vars ) {
$vars[] = 'token';
$vars[] = 'key';
$vars[] = 'query';
$vars[] = 'type';
$vars[] = 'property';
$vars[] = 'number';
$vars[] = 'date';
$vars[] = 'startdate';
$vars[] = 'enddate';
$vars[] = 'donor';
$vars[] = 'propertyat';
$vars[] = 'id';
$vars[] = 'purchasekey';
$vars[] = 'email';
return $vars;
}
/**
* Retrieve the API versions
*
* @access public
* @since 1.1
* @return array
*/
public function get_versions() {
return $this->versions;
}
/**
* Retrieve the API version that was queried
*
* @access public
* @since 1.1
* @return string
*/
public function get_queried_version() {
return $this->queried_version;
}
/**
* Retrieves the default version of the API to use
*
* @access public
* @since 1.1
* @return string
*/
public function get_default_version() {
$version = get_option( 'opalestate_default_api_version' );
if ( defined( 'OPALESTATE_API_VERSION' ) ) {
$version = OPALESTATE_API_VERSION;
} elseif ( ! $version ) {
$version = 'v1';
}
return $version;
}
/**
* Sets the version of the API that was queried.
*
* Falls back to the default version if no version is specified
*
* @access private
* @since 1.1
*/
private function set_queried_version() {
global $wp_query;
$version = $wp_query->query_vars['opalestate-api'];
if ( strpos( $version, '/' ) ) {
$version = explode( '/', $version );
$version = strtolower( $version[0] );
$wp_query->query_vars['opalestate-api'] = str_replace( $version . '/', '', $wp_query->query_vars['opalestate-api'] );
if ( array_key_exists( $version, $this->versions ) ) {
$this->queried_version = $version;
} else {
$this->is_valid_request = false;
$this->invalid_version();
}
} else {
$this->queried_version = $this->get_default_version();
}
}
/**
* Validate the API request
*
* Checks for the user's public key and token against the secret key
*
* @access private
* @global object $wp_query WordPress Query
* @uses Opalestate_API::get_user()
* @uses Opalestate_API::invalid_key()
* @uses Opalestate_API::invalid_auth()
* @since 1.1
* @return void
*/
private function validate_request() {
global $wp_query;
$this->override = false;
// Make sure we have both user and api key
if ( ! empty( $wp_query->query_vars['opalestate-api'] ) && ( $wp_query->query_vars['opalestate-api'] != 'properties' || ! empty( $wp_query->query_vars['token'] ) ) ) {
if ( empty( $wp_query->query_vars['token'] ) || empty( $wp_query->query_vars['key'] ) ) {
$this->missing_auth();
}
// Retrieve the user by public API key and ensure they exist
if ( ! ( $user = $this->get_user( $wp_query->query_vars['key'] ) ) ) {
$this->invalid_key();
} else {
$token = urldecode( $wp_query->query_vars['token'] );
$secret = $this->get_user_secret_key( $user );
$public = urldecode( $wp_query->query_vars['key'] );
if ( hash_equals( md5( $secret . $public ), $token ) ) {
$this->is_valid_request = true;
} else {
$this->invalid_auth();
}
}
} elseif ( ! empty( $wp_query->query_vars['opalestate-api'] ) && $wp_query->query_vars['opalestate-api'] == 'properties' ) {
$this->is_valid_request = true;
$wp_query->set( 'key', 'public' );
}
}
/**
* Retrieve the user ID based on the public key provided
*
* @access public
* @since 1.1
* @global WPDB $wpdb Used to query the database using the WordPress
* Database API
*
* @param string $key Public Key
*
* @return bool if user ID is found, false otherwise
*/
public function get_user( $key = '' ) {
global $wpdb, $wp_query;
if ( empty( $key ) ) {
$key = urldecode( $wp_query->query_vars['key'] );
}
if ( empty( $key ) ) {
return false;
}
$user = get_transient( md5( 'opalestate_api_user_' . $key ) );
if ( false === $user ) {
$user = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s LIMIT 1", $key ) );
set_transient( md5( 'opalestate_api_user_' . $key ), $user, DAY_IN_SECONDS );
}
if ( $user != null ) {
$this->user_id = $user;
return $user;
}
return false;
}
public function get_user_public_key( $user_id = 0 ) {
global $wpdb;
if ( empty( $user_id ) ) {
return '';
}
$cache_key = md5( 'opalestate_api_user_public_key' . $user_id );
$user_public_key = get_transient( $cache_key );
if ( empty( $user_public_key ) ) {
$user_public_key = $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_value = 'opalestate_user_public_key' AND user_id = %d", $user_id ) );
set_transient( $cache_key, $user_public_key, HOUR_IN_SECONDS );
}
return $user_public_key;
}
public function get_user_secret_key( $user_id = 0 ) {
global $wpdb;
if ( empty( $user_id ) ) {
return '';
}
$cache_key = md5( 'opalestate_api_user_secret_key' . $user_id );
$user_secret_key = get_transient( $cache_key );
if ( empty( $user_secret_key ) ) {
$user_secret_key = $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_value = 'opalestate_user_secret_key' AND user_id = %d", $user_id ) );
set_transient( $cache_key, $user_secret_key, HOUR_IN_SECONDS );
}
return $user_secret_key;
}
/**
* Displays a missing authentication error if all the parameters aren't
* provided
*
* @access private
* @uses Opalestate_API::output()
* @since 1.1
*/
private function missing_auth() {
$error = array();
$error['error'] = esc_html__( 'You must specify both a token and API key!', 'opalestate-pro' );
$this->data = $error;
$this->output( 401 );
}
/**
* Displays an authentication failed error if the user failed to provide valid
* credentials
*
* @access private
* @since 1.1
* @uses Opalestate_API::output()
* @return void
*/
private function invalid_auth() {
$error = array();
$error['error'] = esc_html__( 'Your request could not be authenticated!', 'opalestate-pro' );
$this->data = $error;
$this->output( 403 );
}
/**
* Displays an invalid API key error if the API key provided couldn't be
* validated
*
* @access private
* @since 1.1
* @uses Opalestate_API::output()
* @return void
*/
private function invalid_key() {
$error = array();
$error['error'] = esc_html__( 'Invalid API key!', 'opalestate-pro' );
$this->data = $error;
$this->output( 403 );
}
/**
* Displays an invalid version error if the version number passed isn't valid
*
* @access private
* @since 1.1
* @uses Opalestate_API::output()
* @return void
*/
private function invalid_version() {
$error = array();
$error['error'] = esc_html__( 'Invalid API version!', 'opalestate-pro' );
$this->data = $error;
$this->output( 404 );
}
/**
* Listens for the API and then processes the API requests
*
* @access public
* @global $wp_query
* @since 1.1
* @return void
*/
public function process_query() {
global $wp_query;
// Start logging how long the request takes for logging
$before = microtime( true );
// Check for opalestate-api var. Get out if not present
if ( empty( $wp_query->query_vars['opalestate-api'] ) ) {
return;
}
// Determine which version was queried
$this->set_queried_version();
// Determine the kind of query
$this->set_query_mode();
// Check for a valid user and set errors if necessary
$this->validate_request();
// Only proceed if no errors have been noted
if ( ! $this->is_valid_request ) {
return;
}
if ( ! defined( 'OPALESTATE_DOING_API' ) ) {
define( 'OPALESTATE_DOING_API', true );
}
$data = array();
$this->routes = new $this->versions[$this->get_queried_version()];
$this->routes->validate_request();
switch ( $this->endpoint ) :
case 'properties' :
$property = isset( $wp_query->query_vars['property'] ) ? $wp_query->query_vars['property'] : null;
$data = $this->routes->get_properties( $property );
break;
case 'featured' :
$property = isset( $wp_query->query_vars['property'] ) ? $wp_query->query_vars['property'] : null;
$data = $this->routes->get_featured_properties( $property );
break;
case 'agents' :
$agent = isset( $wp_query->query_vars['agent'] ) ? $wp_query->query_vars['agent'] : null;
$data = $this->routes->get_agents( $agent );
break;
endswitch;
// Allow extensions to setup their own return data
$this->data = apply_filters( 'opalestate_api_output_data', $data, $this->endpoint, $this );
$after = microtime( true );
$request_time = ( $after - $before );
$this->data['request_speed'] = $request_time;
// Log this API request, if enabled. We log it here because we have access to errors.
$this->log_request( $this->data );
// Send out data to the output function
$this->output();
}
/**
* Returns the API endpoint requested
*
* @access public
* @since 1.1
* @return string $query Query mode
*/
public function get_query_mode() {
return $this->endpoint;
}
/**
* Determines the kind of query requested and also ensure it is a valid query
*
* @access public
* @since 1.1
* @global $wp_query
*/
public function set_query_mode() {
global $wp_query;
// Whitelist our query options
$accepted = apply_filters( 'opalestate_api_valid_query_modes', array(
'agents',
'properties',
'featured'
) );
$query = isset( $wp_query->query_vars['opalestate-api'] ) ? $wp_query->query_vars['opalestate-api'] : null;
$query = str_replace( $this->queried_version . '/', '', $query );
$error = array();
// Make sure our query is valid
if ( ! in_array( $query, $accepted ) ) {
$error['error'] = esc_html__( 'Invalid query!', 'opalestate-pro' );
$this->data = $error;
// 400 is Bad Request
$this->output( 400 );
}
$this->endpoint = $query;
}
/**
* Get page number
*
* @access public
* @since 1.1
* @global $wp_query
* @return int $wp_query->query_vars['page'] if page number returned (default: 1)
*/
public function get_paged() {
global $wp_query;
return isset( $wp_query->query_vars['page'] ) ? $wp_query->query_vars['page'] : 1;
}
/**
* Number of results to display per page
*
* @access public
* @since 1.1
* @global $wp_query
* @return int $per_page Results to display per page (default: 10)
*/
public function per_page() {
global $wp_query;
$per_page = isset( $wp_query->query_vars['number'] ) ? $wp_query->query_vars['number'] : 10;
return apply_filters( 'opalestate_api_results_per_page', $per_page );
}
/**
*
*
*/
public function get_agents( $agent = null ) {
$agents = array();
$error = array();
if ( $agent == null ) {
$agents['agents'] = array();
$property_list = get_posts( array(
'post_type' => 'opalestate_agent',
'posts_per_page' => $this->per_page(),
'suppress_filters' => true,
'paged' => $this->get_paged()
) );
if ( $property_list ) {
$i = 0;
foreach ( $property_list as $agent_info ) {
$agents['agents'][ $i ] = $this->get_agent_data( $agent_info );
$i ++;
}
}
} else {
if ( get_post_type( $agent ) == 'opalestate_property' ) {
$agent_info = get_post( $agent );
$agents['agents'][0] = $this->get_agent_data( $agent_info );
} else {
$error['error'] = sprintf(
/* translators: %s: property */
esc_html__( 'Form %s not found!', 'opalestate-pro' ),
$agent
);
return $error;
}
}
return $agents;
}
/**
*
*
*/
public function get_agent_data( $agent_info ){
$ouput = array();
$ouput['info']['id'] = $agent_info->ID;
$ouput['info']['slug'] = $agent_info->post_name;
$ouput['info']['title'] = $agent_info->post_title;
$ouput['info']['create_date'] = $agent_info->post_date;
$ouput['info']['modified_date'] = $agent_info->post_modified;
$ouput['info']['status'] = $agent_info->post_status;
$ouput['info']['link'] = html_entity_decode( $agent_info->guid );
$ouput['info']['content'] = $agent_info->post_content;
$ouput['info']['thumbnail'] = wp_get_attachment_url( get_post_thumbnail_id( $agent_info->ID ) );
$agent = new OpalEstate_Agent( $agent_info->ID );
$ouput['info']['featured'] = (int)$agent->is_featured();
$ouput['info']['email'] = get_post_meta( $agent_info->ID, OPALESTATE_AGENT_PREFIX . 'email', true );
$ouput['info']['address'] = get_post_meta( $agent_info->ID, OPALESTATE_AGENT_PREFIX . 'address', true );
$terms = wp_get_post_terms( $agent_info->ID, 'opalestate_agent_location' );
$ouput['info']['location'] = $terms && !is_wp_error($terms) ? $terms : array();
$ouput['socials'] = $agent->get_socials();
$ouput['levels'] = wp_get_post_terms( $agent_info->ID, 'opalestate_agent_level' );
return apply_filters( 'opalestate_api_agents', $ouput );
}
/**
* Process Get Products API Request
*
* @access public
* @since 1.1
*
* @param int $property Opalestate Form ID
*
* @return array $customers Multidimensional array of the properties
*/
public function get_featured_properties( $property = null ) {
$properties = array();
$error = array();
if ( $property == null ) {
$properties['properties'] = array();
$property_list = get_posts( array(
'post_type' => 'opalestate_property',
'posts_per_page' => $this->per_page(),
'suppress_filters' => true,
'paged' => $this->get_paged(),
'meta_key' => OPALESTATE_PROPERTY_PREFIX . 'featured',
'meta_value' => 1,
'meta_compare' => '='
) );
if ( $property_list ) {
$i = 0;
foreach ( $property_list as $property_info ) {
$properties['properties'][ $i ] = $this->get_property_data( $property_info );
$i ++;
}
}
} else {
if ( get_post_type( $property ) == 'opalestate_property' ) {
$property_info = get_post( $property );
$properties['properties'][0] = $this->get_property_data( $property_info );
} else {
$error['error'] = sprintf(
/* translators: %s: property */
esc_html__( 'Form %s not found!', 'opalestate-pro' ),
$property
);
return $error;
}
}
return $properties;
}
/**
* Process Get Products API Request
*
* @access public
* @since 1.1
*
* @param int $property Opalestate Form ID
*
* @return array $customers Multidimensional array of the properties
*/
public function get_properties( $property = null ) {
$properties = array();
$error = array();
if ( $property == null ) {
$properties['properties'] = array();
$property_list = get_posts( array(
'post_type' => 'opalestate_property',
'posts_per_page' => $this->per_page(),
'suppress_filters' => true,
'paged' => $this->get_paged()
) );
if ( $property_list ) {
$i = 0;
foreach ( $property_list as $property_info ) {
$properties['properties'][ $i ] = $this->get_property_data( $property_info );
$i ++;
}
}
} else {
if ( get_post_type( $property ) == 'opalestate_property' ) {
$property_info = get_post( $property );
$properties['properties'][0] = $this->get_property_data( $property_info );
} else {
$error['error'] = sprintf(
/* translators: %s: property */
esc_html__( 'Form %s not found!', 'opalestate-pro' ),
$property
);
return $error;
}
}
return $properties;
}
/**
* Opalestaten a opalestate_property post object, generate the data for the API output
*
* @since 1.1
*
* @param object $property_info The Download Post Object
*
* @return array Array of post data to return back in the API
*/
private function get_property_data( $property_info ) {
$property = array();
$property['info']['id'] = $property_info->ID;
$property['info']['slug'] = $property_info->post_name;
$property['info']['title'] = $property_info->post_title;
$property['info']['create_date'] = $property_info->post_date;
$property['info']['modified_date'] = $property_info->post_modified;
$property['info']['status'] = $property_info->post_status;
$property['info']['link'] = html_entity_decode( $property_info->guid );
$property['info']['content'] = $property_info->post_content;
$property['info']['thumbnail'] = wp_get_attachment_url( get_post_thumbnail_id( $property_info->ID ) );
$data = opalesetate_property( $property_info->ID );
$gallery = $data->get_gallery();
$property['info']['gallery'] = isset($gallery[0]) && !empty($gallery[0]) ? $gallery[0]: array();
$property['info']['price'] = opalestate_price_format( $data->get_price() );
$property['info']['map'] = $data->get_map();
$property['info']['address'] = $data->get_address();
$property['meta'] = $data->get_meta_shortinfo();
$property['status'] = $data->get_status();
$property['locations'] = $data->get_locations();
$property['amenities'] = $data->get_amenities();
$property['types'] = $data->get_types_tax();
if ( user_can( $this->user_id, 'view_opalestate_sensitive_data' ) || $this->override ) {
//Sensitive data here
do_action( 'opalestate_api_sensitive_data' );
}
return apply_filters( 'opalestate_api_properties_property', $property );
}
/**
* Retrieve the output propertyat
*
* Determines whether results should be displayed in XML or JSON
*
* @since 1.1
* @access public
*
* @return mixed|void
*/
public function get_output_propertyat() {
global $wp_query;
$propertyat = isset( $wp_query->query_vars['propertyat'] ) ? $wp_query->query_vars['propertyat'] : 'json';
return apply_filters( 'opalestate_api_output_propertyat', $propertyat );
}
/**
* Log each API request, if enabled
*
* @access private
* @since 1.1
*
* @global Opalestate_Logging $opalestate_logs
* @global WP_Query $wp_query
*
* @param array $data
*
* @return void
*/
private function log_request( $data = array() ) {
if ( ! $this->log_requests ) {
return;
}
/**
* @var Opalestate_Logging $opalestate_logs
*/
global $opalestate_logs;
/**
* @var WP_Query $wp_query
*/
global $wp_query;
$query = array(
'opalestate-api' => $wp_query->query_vars['opalestate-api'],
'key' => isset( $wp_query->query_vars['key'] ) ? $wp_query->query_vars['key'] : null,
'token' => isset( $wp_query->query_vars['token'] ) ? $wp_query->query_vars['token'] : null,
'query' => isset( $wp_query->query_vars['query'] ) ? $wp_query->query_vars['query'] : null,
'type' => isset( $wp_query->query_vars['type'] ) ? $wp_query->query_vars['type'] : null,
'property' => isset( $wp_query->query_vars['property'] ) ? $wp_query->query_vars['property'] : null,
'customer' => isset( $wp_query->query_vars['customer'] ) ? $wp_query->query_vars['customer'] : null,
'date' => isset( $wp_query->query_vars['date'] ) ? $wp_query->query_vars['date'] : null,
'startdate' => isset( $wp_query->query_vars['startdate'] ) ? $wp_query->query_vars['startdate'] : null,
'enddate' => isset( $wp_query->query_vars['enddate'] ) ? $wp_query->query_vars['enddate'] : null,
'id' => isset( $wp_query->query_vars['id'] ) ? $wp_query->query_vars['id'] : null,
'purchasekey' => isset( $wp_query->query_vars['purchasekey'] ) ? $wp_query->query_vars['purchasekey'] : null,
'email' => isset( $wp_query->query_vars['email'] ) ? $wp_query->query_vars['email'] : null,
);
$log_data = array(
'log_type' => 'api_request',
'post_excerpt' => http_build_query( $query ),
'post_content' => ! empty( $data['error'] ) ? $data['error'] : '',
);
$log_meta = array(
'request_ip' => opalestate_get_ip(),
'user' => $this->user_id,
'key' => isset( $wp_query->query_vars['key'] ) ? $wp_query->query_vars['key'] : null,
'token' => isset( $wp_query->query_vars['token'] ) ? $wp_query->query_vars['token'] : null,
'time' => $data['request_speed'],
'version' => $this->get_queried_version()
);
}
/**
* Retrieve the output data
*
* @access public
* @since 1.1
* @return array
*/
public function get_output() {
return $this->data;
}
/**
* Output Query in either JSON/XML. The query data is outputted as JSON
* by default
*
* @since 1.1
* @global WP_Query $wp_query
*
* @param int $status_code
*/
public function output( $status_code = 200 ) {
/**
* @var WP_Query $wp_query
*/
global $wp_query;
$propertyat = $this->get_output_propertyat();
status_header( $status_code );
do_action( 'opalestate_api_output_before', $this->data, $this, $propertyat );
switch ( $propertyat ) :
case 'xml' :
require_once OPALESTATE_PLUGIN_DIR . 'inc/libraries/array2xml.php';
$xml = Array2XML::createXML( 'opalestate-pro', $this->data );
echo $xml->saveXML();
break;
case 'json' :
header( 'Content-Type: application/json' );
if ( ! empty( $this->pretty_print ) ) {
echo json_encode( $this->data, $this->pretty_print );
} else {
echo json_encode( $this->data );
}
break;
default :
// Allow other propertyats to be added via extensions
do_action( 'opalestate_api_output_' . $propertyat, $this->data, $this );
break;
endswitch;
do_action( 'opalestate_api_output_after', $this->data, $this, $propertyat );
die();
}
/**
* Modify User Profile
*
* Modifies the output of profile.php to add key generation/revocation
*
* @access public
* @since 1.1
*
* @param object $user Current user info
*
* @return void
*/
function user_key_field( $user ) {
if ( ( opalestate_get_option( 'api_allow_user_keys', false ) || current_user_can( 'manage_opalestate_settings' ) ) && current_user_can( 'edit_user', $user->ID ) ) {
$user = get_userdata( $user->ID );
?>
<hr class="clearfix clear">
<table class="property-table">
<tbody>
<tr>
<th>
<?php esc_html_e( 'Opalestate API Keys', 'opalestate-pro' ); ?>
</th>
<td>
<?php
$public_key = $this->get_user_public_key( $user->ID );
$secret_key = $this->get_user_secret_key( $user->ID );
?>
<?php if ( empty( $user->opalestate_user_public_key ) ) { ?>
<input name="opalestate_set_api_key" type="checkbox" id="opalestate_set_api_key" value="0"/>
<span class="description"><?php esc_html_e( 'Generate API Key', 'opalestate-pro' ); ?></span>
<?php } else { ?>
<strong style="display:inline-block; width: 125px;"><?php esc_html_e( 'Public key:', 'opalestate-pro' ); ?>&nbsp;</strong>
<input type="text" disabled="disabled" class="regular-text" id="publickey" value="<?php echo esc_attr( $public_key ); ?>"/>
<br/>
<strong style="display:inline-block; width: 125px;"><?php esc_html_e( 'Secret key:', 'opalestate-pro' ); ?>&nbsp;</strong>
<input type="text" disabled="disabled" class="regular-text" id="privatekey" value="<?php echo esc_attr( $secret_key ); ?>"/>
<br/>
<strong style="display:inline-block; width: 125px;"><?php esc_html_e( 'Token:', 'opalestate-pro' ); ?>&nbsp;</strong>
<input type="text" disabled="disabled" class="regular-text" id="token" value="<?php echo esc_attr( $this->get_token( $user->ID ) ); ?>"/>
<br/>
<input name="opalestate_set_api_key" type="checkbox" id="opalestate_set_api_key" value="0"/>
<span class="description"><label for="opalestate_set_api_key"><?php esc_html_e( 'Revoke API Keys', 'opalestate-pro' ); ?></label></span>
<?php } ?>
</td>
</tr>
</tbody>
</table>
<?php }
}
/**
* Process an API key generation/revocation
*
* @access public
* @since 1.1
*
* @param array $args
*
* @return void
*/
public function process_api_key( $args ) {
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'opalestate-api-nonce' ) ) {
wp_die( esc_html__( 'Nonce verification failed.', 'opalestate-pro' ), esc_html__( 'Error', 'opalestate-pro' ), array( 'response' => 403 ) );
}
if ( empty( $args['user_id'] ) ) {
wp_die( esc_html__( 'User ID Required.', 'opalestate-pro' ), esc_html__( 'Error', 'opalestate-pro' ), array( 'response' => 401 ) );
}
if ( is_numeric( $args['user_id'] ) ) {
$user_id = isset( $args['user_id'] ) ? absint( $args['user_id'] ) : get_current_user_id();
} else {
$userdata = get_user_by( 'login', $args['user_id'] );
$user_id = $userdata->ID;
}
$process = isset( $args['opalestate_api_process'] ) ? strtolower( $args['opalestate_api_process'] ) : false;
if ( $user_id == get_current_user_id() && ! opalestate_get_option( 'allow_user_api_keys' ) && ! current_user_can( 'manage_opalestate_settings' ) ) {
wp_die(
sprintf(
/* translators: %s: process */
esc_html__( 'You do not have permission to %s API keys for this user.', 'opalestate-pro' ),
$process
),
esc_html__( 'Error', 'opalestate-pro' ),
array( 'response' => 403 )
);
} elseif ( ! current_user_can( 'manage_opalestate_settings' ) ) {
wp_die(
sprintf(
/* translators: %s: process */
esc_html__( 'You do not have permission to %s API keys for this user.', 'opalestate-pro' ),
$process
),
esc_html__( 'Error', 'opalestate-pro' ),
array( 'response' => 403 )
);
}
switch ( $process ) {
case 'generate':
if ( $this->generate_api_key( $user_id ) ) {
delete_transient( 'opalestate_total_api_keys' );
wp_redirect( add_query_arg( 'opalestate-message', 'api-key-generated', 'edit.php?post_type=opalestate_property&page=opalestate-settings&tab=api' ) );
exit();
} else {
wp_redirect( add_query_arg( 'opalestate-message', 'api-key-failed', 'edit.php?post_type=opalestate_property&page=opalestate-settings&tab=api' ) );
exit();
}
break;
case 'regenerate':
$this->generate_api_key( $user_id, true );
delete_transient( 'opalestate_total_api_keys' );
wp_redirect( add_query_arg( 'opalestate-message', 'api-key-regenerated', 'edit.php?post_type=opalestate_property&page=opalestate-settings&tab=api' ) );
exit();
break;
case 'revoke':
$this->revoke_api_key( $user_id );
delete_transient( 'opalestate_total_api_keys' );
wp_redirect( add_query_arg( 'opalestate-message', 'api-key-revoked', 'edit.php?post_type=opalestate_property&page=opalestate-settings&tab=api' ) );
exit();
break;
default;
break;
}
}
/**
* Generate new API keys for a user
*
* @access public
* @since 1.1
*
* @param int $user_id User ID the key is being generated for
* @param boolean $regenerate Regenerate the key for the user
*
* @return boolean True if (re)generated succesfully, false otherwise.
*/
public function generate_api_key( $user_id = 0, $regenerate = false ) {
if ( empty( $user_id ) ) {
return false;
}
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
$public_key = $this->get_user_public_key( $user_id );
$secret_key = $this->get_user_secret_key( $user_id );
if ( empty( $public_key ) || $regenerate == true ) {
$new_public_key = $this->generate_public_key( $user->user_email );
$new_secret_key = $this->generate_private_key( $user->ID );
} else {
return false;
}
if ( $regenerate == true ) {
$this->revoke_api_key( $user->ID );
}
update_user_meta( $user_id, $new_public_key, 'opalestate_user_public_key' );
update_user_meta( $user_id, $new_secret_key, 'opalestate_user_secret_key' );
return true;
}
/**
* Revoke a users API keys
*
* @access public
* @since 1.1
*
* @param int $user_id User ID of user to revoke key for
*
* @return string
*/
public function revoke_api_key( $user_id = 0 ) {
if ( empty( $user_id ) ) {
return false;
}
$user = get_userdata( $user_id );
if ( ! $user ) {
return false;
}
$public_key = $this->get_user_public_key( $user_id );
$secret_key = $this->get_user_secret_key( $user_id );
if ( ! empty( $public_key ) ) {
delete_transient( md5( 'opalestate_api_user_' . $public_key ) );
delete_transient( md5( 'opalestate_api_user_public_key' . $user_id ) );
delete_transient( md5( 'opalestate_api_user_secret_key' . $user_id ) );
delete_user_meta( $user_id, $public_key );
delete_user_meta( $user_id, $secret_key );
} else {
return false;
}
return true;
}
public function get_version() {
return self::VERSION;
}
/**
* Generate and Save API key
*
* Generates the key requested by user_key_field and stores it in the database
*
* @access public
* @since 1.1
*
* @param int $user_id
*
* @return void
*/
public function update_key( $user_id ) {
if ( current_user_can( 'edit_user', $user_id ) && isset( $_POST['opalestate_set_api_key'] ) ) {
$user = get_userdata( $user_id );
$public_key = $this->get_user_public_key( $user_id );
$secret_key = $this->get_user_secret_key( $user_id );
if ( empty( $public_key ) ) {
$new_public_key = $this->generate_public_key( $user->user_email );
$new_secret_key = $this->generate_private_key( $user->ID );
update_user_meta( $user_id, $new_public_key, 'opalestate_user_public_key' );
update_user_meta( $user_id, $new_secret_key, 'opalestate_user_secret_key' );
} else {
$this->revoke_api_key( $user_id );
}
}
}
/**
* Generate the public key for a user
*
* @access private
* @since 1.1
*
* @param string $user_email
*
* @return string
*/
private function generate_public_key( $user_email = '' ) {
$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
$public = hash( 'md5', $user_email . $auth_key . date( 'U' ) );
return $public;
}
/**
* Generate the secret key for a user
*
* @access private
* @since 1.1
*
* @param int $user_id
*
* @return string
*/
private function generate_private_key( $user_id = 0 ) {
$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
$secret = hash( 'md5', $user_id . $auth_key . date( 'U' ) );
return $secret;
}
/**
* Retrieve the user's token
*
* @access private
* @since 1.1
*
* @param int $user_id
*
* @return string
*/
public function get_token( $user_id = 0 ) {
return hash( 'md5', $this->get_user_secret_key( $user_id ) . $this->get_user_public_key( $user_id ) );
}
/**
* API Key Backwards Compatibility
*
* A Backwards Compatibility call for the change of meta_key/value for users API Keys
*
* @since 1.3.6
*
* @param string $check Whether to check the cache or not
* @param int $object_id The User ID being passed
* @param string $meta_key The user meta key
* @param bool $single If it should return a single value or array
*
* @return string The API key/secret for the user supplied
*/
public function api_key_backwards_compat( $check, $object_id, $meta_key, $single ) {
if ( $meta_key !== 'opalestate_user_public_key' && $meta_key !== 'opalestate_user_secret_key' ) {
return $check;
}
$return = $check;
switch ( $meta_key ) {
case 'opalestate_user_public_key':
$return = Opalestate()->api->get_user_public_key( $object_id );
break;
case 'opalestate_user_secret_key':
$return = Opalestate()->api->get_user_secret_key( $object_id );
break;
}
if ( ! $single ) {
$return = array( $return );
}
return $return;
}
}