HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //home/globfdxw/www/wp-content/plugins/wpforms-google-calendar/src/Api/Client.php
<?php

namespace WPFormsGoogleCalendar\Api;

use InvalidArgumentException;
use WPFormsGoogleCalendar\Plugin;
use WPFormsGoogleCalendar\Api\Http\Request;

/**
 * Client class.
 *
 * @since 1.0.0
 */
class Client {

	/**
	 * Google Calendar API URL.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private const API_URL = 'https://www.googleapis.com/calendar/v3/';

	/**
	 * WPForms website URL.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private const MIDDLEWARE_URL = 'https://wpforms.com/oauth/google-calendar-connect/';

	/**
	 * Account settings.
	 *
	 * @since 1.0.0
	 *
	 * @var array
	 */
	private $account;

	/**
	 * Class for making HTTP requests.
	 *
	 * @since 1.0.0
	 *
	 * @var Request
	 */
	private $request;

	/**
	 * Client constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param array $account Account settings.
	 *
	 * @throws InvalidArgumentException If the access token, refresh token, or account ID is empty.
	 */
	public function __construct( array $account ) {

		if ( empty( $account['access_token'] ) ) {
			throw new InvalidArgumentException( 'Access token cannot be empty.' );
		}

		if ( empty( $account['refresh_token'] ) ) {
			throw new InvalidArgumentException( 'Refresh token cannot be empty.' );
		}

		if ( empty( $account['id'] ) ) {
			throw new InvalidArgumentException( 'Account ID cannot be empty.' );
		}

		$this->account = $account;

		$this->maybe_refresh_token();

		$this->request = new Request( $this->account['access_token'] );
	}

	/**
	 * Check if the access token is expired.
	 *
	 * @since 1.0.0
	 *
	 * @return bool
	 */
	private function is_expired_token(): bool {

		$expires_in = $this->account['expires_in'] ?? 0;

		/**
		 * Adding one minute to cover a very rare case when a few seconds are left,
		 * and the site runs multiple API requests.
		 * The last one could be outdated.
		 */
		return ( time() + MINUTE_IN_SECONDS ) > $expires_in;
	}

	/**
	 * Refresh the access token if it is expired.
	 *
	 * @since 1.0.0
	 *
	 * @throws InvalidArgumentException If the response body does not contain the access token or expires in.
	 */
	private function maybe_refresh_token(): void {

		if ( ! $this->is_expired_token() ) {
			return;
		}

		$response = wp_remote_post(
			self::get_middleware_url(),
			[
				'body' => [
					'refresh_token' => $this->account['refresh_token'],
				],
			]
		);

		$response_body = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( ! isset( $response_body['data']['access_token'], $response_body['data']['expires_in'] ) ) {
			throw new InvalidArgumentException( esc_html__( 'Cannot refresh the token.', 'wpforms-google-calendar' ) );
		}

		$this->account = array_merge(
			$this->account,
			[
				'access_token' => $response_body['data']['access_token'],
				'expires_in'   => time() + (int) ( $response_body['data']['expires_in'] ),
			]
		);

		wpforms_update_providers_options( Plugin::SLUG, $this->account, $this->account['id'] );
	}

	/**
	 * Get authorization url to begin OAuth flow.
	 *
	 * @since 1.0.0
	 *
	 * @param string $redirect_uri Redirect URI.
	 *
	 * @return string
	 */
	public static function get_auth_url( string $redirect_uri ): string {

		$redirect_uri = add_query_arg(
			[
				'nonce' => wp_create_nonce( 'wpforms-google-calendar-connect' ),
			],
			$redirect_uri
		);

		$state = rawurlencode(
			base64_encode( // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
				wp_json_encode(
					[
						'redirect_uri' => $redirect_uri,
					]
				)
			)
		);

		return add_query_arg(
			[
				'action' => 'init',
				'state'  => $state,
			],
			self::get_middleware_url()
		);
	}

	/**
	 * Get a calendar list.
	 *
	 * @since 1.0.0
	 *
	 * @noinspection PhpUnusedLocalVariableInspection
	 */
	public function get_calendar_list(): array {

		$response = $this->request->get(
			self::API_URL . 'users/me/calendarList/',
			[
				'minAccessRole' => 'writer',
				'maxResults'    => 250,
			]
		);

		$body = $response->get_body();

		if ( empty( $body['items'] ) ) {
			return [];
		}

		$calendars = [];

		foreach ( $body['items'] as $key => $calendar ) {
			if ( ! isset( $calendar['id'], $calendar['summary'], $calendar['timeZone'] ) ) {
				continue;
			}

			$calendars[ $calendar['id'] ] = [
				'name'     => $calendar['summary'],
				'timezone' => $calendar['timeZone'],
			];
		}

		return $calendars;
	}

	/**
	 * Create an event.
	 *
	 * @since 1.0.0
	 *
	 * @param array $event_data Event data.
	 *
	 * @return bool
	 */
	public function create_event( array $event_data ): bool {

		if ( empty( $event_data['calendar_id'] ) ) {
			return false;
		}

		$response = $this->request->post( self::API_URL . "calendars/{$event_data['calendar_id']}/events/?sendUpdates=all", $event_data );

		return ! $response->has_errors();
	}

	/**
	 * Get middleware URL.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 * @noinspection PhpUndefinedConstantInspection
	 */
	private static function get_middleware_url(): string {

		if ( defined( 'WPFORMS_GOOGLE_CALENDAR_MIDDLEWARE_URL' ) && WPFORMS_GOOGLE_CALENDAR_MIDDLEWARE_URL ) {
			return (string) WPFORMS_GOOGLE_CALENDAR_MIDDLEWARE_URL;
		}

		return self::MIDDLEWARE_URL;
	}
}