Google_Calendar_Helpers
Class Google_Calendar_Helpers
Source Source
File: src/integrations/google-calendar/helpers/google-calendar-helpers.php
class Google_Calendar_Helpers { /** * The Pro helpers options object. * * @var string|object */ public $pro = ''; /** * The helpers options object. * * @var string|object */ public $options = ''; /** * The wp_options table key for selecting the integration options. * * @var string */ const OPTION_KEY = 'automator_google_calendar_credentials'; /** * The public API edge. * * @var string */ const API_ENDPOINT = 'v2/google-calendar'; /** * Set the options. * * @param Google_Calendar_Helpers $options */ public function setOptions( Google_Calendar_Helpers $options ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid $this->options = $options; } /** * Set pro method. * * @param Google_Calendar_Helpers $pro */ public function setPro( \Uncanny_Automator_Pro\Google_Calendar_Helpers $pro ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid $this->pro = $pro; } public function __construct() { // Process authentication. add_action( 'wp_ajax_automator_google_calendar_process_code_callback', array( $this, 'automator_google_calendar_process_code_callback' ) ); // Disconnect. add_action( 'wp_ajax_automator_google_calendar_disconnect_user', array( $this, 'disconnect_user' ) ); // List calendars. add_action( 'wp_ajax_automator_google_calendar_list_calendars', array( $this, 'list_calendars' ) ); // List calendards dropdown. add_action( 'wp_ajax_automator_google_calendar_list_calendars_dropdown', array( $this, 'list_calendars_dropdown' ) ); // List events. add_action( 'wp_ajax_automator_google_calendar_list_events', array( $this, 'list_events' ) ); require_once __DIR__ . '/../settings/settings-google-calendar.php'; new Google_Calendar_Settings( $this ); } /** * Method parse_response. * * @param mixed $response The response from API Call. * * @return array The parsed response. */ public function parse_response( $response ) { return array_map( function( $response ) { return array( 'text' => $response['summary'], 'value' => $response['id'], ); }, $response ); } /** * Method list_calendars_dropdown. * * A wp_ajax callback method. * * @return void. */ public function list_calendars_dropdown() { Automator()->utilities->ajax_auth_check(); $response = get_transient( 'automator_google_calendar_calendar_list' ); $items = array(); // Serve from cache. if ( false !== $response ) { echo wp_json_encode( $this->parse_response( $response['data'] ) ); wp_die(); } // Otherwise, request live data. try { $response = $this->api_call( array( 'action' => 'list_calendars', ) ); set_transient( 'automator_google_calendar_calendar_list', $response, 5 * MINUTE_IN_SECONDS ); $items = $this->parse_response( $response['data'] ); } catch ( \Exception $e ) { $items = array( array( /* translators: Error message */ 'text' => sprintf( esc_html__( '%1$s: %2$s Please try again later.', 'uncanny-automator' ), $e->getCode(), $e->getMessage() ), 'value' => '-1', ), ); } echo wp_json_encode( $items ); wp_die(); } /** * Method list_calendars. * * A wp_ajax callback method. * * @return void. */ public function list_calendars() { if ( ! wp_verify_nonce( automator_filter_input( 'nonce', INPUT_POST ), 'uncanny_automator' ) ) { wp_send_json( array( 'error' => 'Authentication failed. Invalid nonce.', ) ); } $response = get_transient( 'automator_google_calendar_calendar_list' ); if ( false !== $response ) { wp_send_json( $response ); } $body = array( 'action' => 'list_calendars', ); try { $response = $this->api_call( $body, null ); set_transient( 'automator_google_calendar_calendar_list', $response, 5 * MINUTE_IN_SECONDS ); wp_send_json( $response ); } catch ( \Exception $e ) { $error_message = $e->getMessage(); wp_send_json( array( 'error' => $error_message, 'error_code' => $e->getCode(), ) ); } } /** * Method list_events. * * A wp_ajax callback method. * * @return void. */ public function list_events() { Automator()->utilities->ajax_auth_check(); $items = array(); try { $response = $this->api_call( array( 'action' => 'list_events', 'calendar_id' => automator_filter_input( 'value', INPUT_POST ), 'timezone' => wp_timezone_string(), ) ); if ( is_array( $response['data'] ) && ! empty( $response['data'] ) ) { foreach ( $response['data'] as $event ) { if ( ! empty( $event['summary'] ) ) { // Date start can either be from [date_start] or from [datetime_start]. // Google API returns date_start if its wholeday event. Otherwise, datetime_start. $date_start = isset( $event['datetime_start'] ) ? $event['datetime_start'] : ''; $type = 'datetime'; if ( empty( $date_start ) ) { // Try the [date_start]. The [date_start] AND the [datetime_start] cannot be both nulled at the same time. $date_start = isset( $event['date_start'] ) ? $event['date_start'] : ''; $type = 'date'; } $date = new \DateTime( $date_start, new \DateTimeZone( wp_timezone_string() ) ); $date_string = $date->format( 'F j, Y' ); if ( 'datetime' === $type ) { $date_string = $date->format( 'F j, Y g:i A' ); } $items[] = array( 'text' => sprintf( '%1$s (%2$s)', $event['summary'], $date_string ), 'value' => $event['id'], ); } } } } catch ( \Exception $e ) { $items = array( array( /* translators: Error message */ 'text' => sprintf( esc_html__( '%1$s: %2$s Please try again later.', 'uncanny-automator' ), $e->getCode(), $e->getMessage() ), 'value' => '', ), ); } if ( ! empty( $events ) ) { foreach ( $events as $event ) { $items[] = array( 'text' => $event['summary'], 'value' => $event['id'], ); } } wp_send_json( $items ); } /** * Method automator_google_calendar_process_code_callback. * * A wp_ajax callback. * * @return void. */ public function automator_google_calendar_process_code_callback() { // Redirect if there are any errors. $this->auth_redirect_when_error( automator_filter_input( 'nonce' ), automator_filter_input( 'auth_error' ) ); // Persist connection if okay. $is_connected = $this->auth_persist_connection( automator_filter_input( 'automator_api_message' ), get_transient( 'automator_api_google_authorize_nonce' ) ); if ( $is_connected ) { $this->redirect_with_success( 200 ); } $this->redirect_with_error( 'generic_error' ); wp_die(); } /** * Method auth_redirect_when_error * * Redirects if nonce is invalid, or if auth is successful. * * @param string $nonce The nonce. * @param string $invoked_errors The displayed error message. * * @return void. */ protected function auth_redirect_when_error( $nonce = '', $invoked_errors = '' ) { // Check nonce. if ( ! wp_verify_nonce( $nonce, 'automator_api_google_calendar_authorize' ) ) { $this->redirect_with_error( 'invalid_nonce' ); } // Redirect if there are any errors. if ( ! empty( $invoked_errors ) ) { $this->redirect_with_error( str_replace( ' ', '_', strtolower( rawurlencode( $invoked_errors ) ) ) ); } } /** * Method redirect_with_success. * * Redirects with a success message. * * @param string $success_message The success message. * * return void. */ public function redirect_with_success( $success_message = '' ) { wp_safe_redirect( $this->get_settings_page_url( array( 'auth_success' => $success_message, ) ) ); exit; } /** * Method redirect_with_error. * * Redirects with an error message. * * @param string $error_message The error message. * * return void. */ public function redirect_with_error( $error_message = '' ) { wp_safe_redirect( $this->get_settings_page_url( array( 'auth_error' => $error_message, ) ) ); exit; } /** * Method auth_persist_connection. * * Save the connection data to wp_options. * * @param string $api_message The secret message from the API. * @param string $secret The secret token. * * @return boolean True if persists successfully. Otherwise, false. */ protected function auth_persist_connection( $api_message = '', $secret = '' ) { $tokens = Automator_Helpers_Recipe::automator_api_decode_message( $api_message, $secret ); if ( false !== $tokens ) { if ( $this->has_missing_scopes( $tokens ) ) { $this->redirect_with_error( esc_html__( 'missing_scope', 'uncanny-automator' ) ); } update_option( self::OPTION_KEY, $tokens ); return true; } return false; } /** * Method has_missing_scopes. * * Checks if the user has missing scopes. Scopes are checked during OAuth consent screen. * * @param mixed $token The access token combination. * * @return boolean True if there are scopes missing. Otherwise, false. */ public function has_missing_scopes( $token ) { if ( ! isset( $token['scope'] ) || empty( $token['scope'] ) ) { return true; } $scopes = array( 'https://www.googleapis.com/auth/calendar', 'https://www.googleapis.com/auth/calendar.events', ); $has_missing_scope = false; foreach ( $scopes as $scope ) { if ( ! str_contains( $token['scope'], $scope ) ) { $has_missing_scope = true; } } return $has_missing_scope; } /** * Method get_settings_page_url. * * Create and retrieve the settings page uri. * * @param array $params The url query parameters. * * @return string The Google Calendar settings page. */ public function get_settings_page_url( $params = array() ) { return add_query_arg( array_merge( array( 'post_type' => 'uo-recipe', 'page' => 'uncanny-automator-config', 'tab' => 'premium-integrations', 'integration' => 'google-calendar', ), $params ), admin_url( 'edit.php' ) ); } /** * Method get_disconnect_url. * * @return string Returns the wp_ajax disconnect url callback. */ public function get_disconnect_url() { return add_query_arg( array( 'action' => 'automator_google_calendar_disconnect_user', 'nonce' => wp_create_nonce( 'automator-google-calendar-user-disconnect' ), ), admin_url( 'admin-ajax.php' ) ); } /** * Method get_authentication_url. * * @return string The OAuth consent screen url. */ public function get_authentication_url() { // Create nonce. $nonce = wp_create_nonce( 'automator_api_google_calendar_authorize' ); // Construct the redirect uri. $redirect_uri = add_query_arg( array( 'action' => 'automator_google_calendar_process_code_callback', 'nonce' => $nonce, ), admin_url( 'admin-ajax.php' ) ); set_transient( 'automator_api_google_authorize_nonce', $nonce, 3600 ); // Construct the OAuth uri. $auth_uri = add_query_arg( array( 'action' => 'authorization_request', 'redirect_url' => rawurlencode( $redirect_uri ), 'nonce' => $nonce, 'plugin_ver' => InitializePlugin::PLUGIN_VERSION, ), AUTOMATOR_API_URL . 'v2/google-calendar' ); return $auth_uri; } /** * Method get_client. * * @return mixed The Google Client that was saved in wp_options (self::OPTION_KEY) */ public function get_client() { return get_option( self::OPTION_KEY, false ); } /** * Method get_user_info. * * @return array The user info. */ public function get_user_info() { $user_info = array( 'avatar_uri' => '', 'name' => '', 'email' => '', ); $transient_key = 'automator_google_calendar_user_info'; $saved_user_info = get_transient( $transient_key ); if ( false !== $saved_user_info ) { return $saved_user_info; } try { $user = $this->api_user_info(); if ( empty( $user['data'] ) ) { return $user_info; } $user_info['name'] = $user['data']['name']; $user_info['avatar_uri'] = $user['data']['picture']; $user_info['email'] = $user['data']['email']; set_transient( $transient_key, $user_info, DAY_IN_SECONDS ); } catch ( \Exception $e ) { return $user_info; } return $user_info; } /** * Method get_calendar_options. * * Retrieves the calendar options fields. * * @return array The option items. */ public function get_calendar_options() { $response = get_transient( 'automator_google_calendar_calendar_list' ); $items = array(); // Serve from cache. if ( false !== $response ) { if ( is_array( $response ) && ! empty( $response ) ) { $response = $this->parse_response( $response['data'] ); foreach ( $response as $calendar ) { $items[ $calendar['value'] ] = $calendar['text']; } } return $items; } // Otherwise, request live data. try { $response = $this->api_call( array( 'action' => 'list_calendars', ), null ); set_transient( 'automator_google_calendar_calendar_list', $response, 5 * MINUTE_IN_SECONDS ); if ( is_array( $response ) && ! empty( $response ) ) { $response = $this->parse_response( $response['data'] ); foreach ( $response as $calendar ) { $items[ $calendar['value'] ] = $calendar['text']; } } return $items; } catch ( \Exception $e ) { $items = array( /* translators: Error message */ '' => sprintf( esc_html__( '%1$s: %2$s Please try again later.', 'uncanny-automator' ), $e->getCode(), $e->getMessage() ), ); } return $items; } /** * Method is_user_connected * * @return boolean True if has Google Client. Otherwise, false. */ public function is_user_connected() { return ! empty( $this->get_client() ); } /** * Method api_get_user_info. * * @return string The api response. */ public function api_user_info() { $client = $this->get_client(); if ( empty( $client['scope'] ) ) { return; } $body = array( 'action' => 'user_info', ); $response = false; try { $response = $this->api_call( $body, null ); } catch ( \Exception $e ) { automator_log( $e->getMessage() ); } return $response; } /** * Method disconnect_user. * * Removes the Google Calendar settings from wp_options table. * * @return void|null|array. */ public function disconnect_user() { if ( wp_verify_nonce( automator_filter_input( 'nonce' ), 'automator-google-calendar-user-disconnect' ) ) { // De-authorize app. $this->api_revoke_access(); // Delete the connection settings. $this->disconnect_client(); } wp_safe_redirect( $this->get_settings_page_url() ); exit; } /** * Method api_revoke_access. * * @return void */ public function api_revoke_access() { try { $body = array( 'action' => 'revoke_access', ); $response = $this->api_call( $body ); } catch ( \Exception $e ) { automator_log( $e->getMessage(), true ); } } /** * Method disconnect_client. * * Deletes all Google Calendar transients and option. * * @return boolean True. */ public function disconnect_client() { delete_transient( 'automator_google_calendar_calendar_list' ); delete_transient( 'automator_google_calendar_user_info' ); delete_option( self::OPTION_KEY ); return true; } /** * Method api_call * * @param array $body The request body form-data. * @param array $action The Automator Action parameters. * * @return string Json encoded response from API. */ public function api_call( $body, $action = null ) { $body['access_token'] = wp_json_encode( $this->get_client() ); $params = array( 'endpoint' => self::API_ENDPOINT, 'body' => $body, 'action' => $action, 'timeout' => 15, ); $response = Api_Server::api_call( $params ); if ( 200 !== $response['statusCode'] ) { throw new \Exception( $params['endpoint'] . ' failed' ); } return $response; } }
Expand full source code Collapse full source code View on Github
Methods Methods
- __construct
- api_call — Method api_call
- api_revoke_access — Method api_revoke_access.
- api_user_info — Method api_get_user_info.
- auth_persist_connection — Method auth_persist_connection.
- auth_redirect_when_error — Method auth_redirect_when_error
- automator_google_calendar_process_code_callback — Method automator_google_calendar_process_code_callback.
- disconnect_client — Method disconnect_client.
- disconnect_user — Method disconnect_user.
- get_authentication_url — Method get_authentication_url.
- get_calendar_options — Method get_calendar_options.
- get_client — Method get_client.
- get_disconnect_url — Method get_disconnect_url.
- get_settings_page_url — Method get_settings_page_url.
- get_user_info — Method get_user_info.
- has_missing_scopes — Method has_missing_scopes.
- is_user_connected — Method is_user_connected
- list_calendars — Method list_calendars.
- list_calendars_dropdown — Method list_calendars_dropdown.
- list_events — Method list_events.
- parse_response — Method parse_response.
- redirect_with_error — Method redirect_with_error.
- redirect_with_success — Method redirect_with_success.
- setOptions — Set the options.
- setPro — Set pro method.