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-entry-automation/src/Helpers/DropboxReconnect.php
<?php

namespace WPFormsEntryAutomation\Helpers;

use WPFormsDropbox\Plugin as DropboxPlugin;
use WPFormsEntryAutomation\Plugin;

/**
 * Handles the reconnection process for Dropbox accounts in WPForms.
 *
 * This class is responsible for managing Dropbox account reconnections by storing
 * temporary data, handling AJAX requests, updating provider options, and replacing
 * account IDs as needed.
 *
 * @since 1.0.0
 */
class DropboxReconnect {

	/**
	 * Transient name used for storing temporary reconnection data.
	 *
	 * @since 1.0.0
	 */
	private const TRANSIENT_RECONNECT = 'wpforms_entry_automation_dropbox_reconnect';

	/**
	 * Account ID that needs to be replaced in provider options.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private $account_id_for_replacing = '';

	/**
	 * Account ID that will replace the old account ID in provider options.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private $account_id_replacement = '';

	/**
	 * Registers hooks for the Dropbox provider.
	 *
	 * @since 1.0.0
	 */
	public function hooks(): void {

		$slug = Plugin::SLUG;

		add_filter( "wpforms_builder_ajax_{$slug}_dropbox_reconnect", [ $this, 'ajax_dropbox_reconnect' ] );
		add_filter( "wpforms_builder_ajax_{$slug}_dropbox_load_accounts_scopes", [ $this, 'ajax_get_accounts_with_scopes' ] );

		// phpcs:disable WordPress.Security.NonceVerification.Recommended
		if ( ! isset(
			$_GET['dropbox_connect'],
			$_GET['state'],
			$_GET['account_id'],
			$_GET['access_token'],
			$_GET['refresh_token'],
			$_GET['expires_in']
		) ) {
			return;
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		// Reconnect a Dropbox account during the auth process.
		// See \WPFormsDropbox\Api\Auth::process_auth.
		add_action( 'admin_init', [ $this, 'reconnect_account' ], 0 );
		add_action( 'admin_init', [ $this, 'replace_account_id' ], 11 );
		add_filter( 'wpforms_update_providers_options', [ $this, 'update_scope_for_account' ], 10, 4 );
	}

	/**
	 * 1. Check whether the account_id in GET params equals to stored account_id.
	 * 2. If yes, remove the account from the provider options.
	 *     2.1 Handle saving providers options.
	 *     2.2 Set the account ID for replacing.
	 *     2.3 In the replace_account_id method do the replacement.
	 *     2.4 Clear the transient.
	 * 3. If no, do nothing.
	 *
	 * This method is called during the auth process.
	 * It is used to reconnect the account with new scopes.
	 *
	 * @since 1.0.0
	 */
	public function reconnect_account(): void { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		$reconnect = get_transient( self::TRANSIENT_RECONNECT );
		$reconnect = ! empty( $reconnect ) ? json_decode( $reconnect, true ) : [];

		if ( ! $reconnect ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$account_id = ! empty( $_GET['account_id'] ) ? sanitize_text_field( wp_unslash( $_GET['account_id'] ) ) : '';

		if ( $account_id !== $reconnect['account_id'] ) {
			return;
		}

		$this->account_id_replacement = $reconnect['key'];

		// Clear the current account.
		wpforms_dropbox()->get( 'account' )->remove( $reconnect['key'] );
		// Handle saving providers options.
		add_filter( 'wpforms_update_providers_options', [ $this, 'save_account_id_for_replacing' ], 10, 4 );
	}

	/**
	 * Saves the account ID for replacing and modifies provider options if applicable.
	 *
	 * @since 1.0.0
	 *
	 * @param array  $providers The array of provider configurations.
	 * @param string $provider  The slug of the current provider being processed.
	 * @param array  $options   The options for the current provider.
	 * @param string $id        The ID to be saved for replacing.
	 *
	 * @return array
	 *
	 * @noinspection PhpMissingParamTypeInspection
	 */
	public function save_account_id_for_replacing( $providers, $provider, $options, $id ): array { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks

		if ( $provider !== DropboxPlugin::SLUG && ! empty( $options ) ) {
			return (array) $providers;
		}

		// We can't replace the new account ID here since it should be used to finish the native Dropbox addon OAuth process.
		// Instead, we save the account ID for replacing and modify the provider options later.
		$this->account_id_for_replacing = $id;

		remove_filter( 'wpforms_update_providers_options', [ $this, 'save_account_id_for_replacing' ] );

		return (array) $providers;
	}

	/**
	 * Replaces the account ID being used with a new account ID in the provider options.
	 *
	 * @since 1.0.0
	 */
	public function replace_account_id(): void {

		// Early exit if no account ID needs replacing.
		if ( ! $this->account_id_for_replacing ) {
			return;
		}

		$providers = wpforms_get_providers_options();
		$provider  =& $providers[ DropboxPlugin::SLUG ];
		// Get the account details for the account being replaced.
		$account = $provider[ $this->account_id_for_replacing ];
		// Set the new account ID.
		$account['key'] = $this->account_id_replacement;

		// Remove old account ID.
		unset( $provider[ $this->account_id_for_replacing ] );

		// Add an account with a new ID.
		$provider[ $this->account_id_replacement ] = $account;

		update_option( 'wpforms_providers', $providers );
		delete_transient( self::TRANSIENT_RECONNECT );
	}

	/**
	 * Update the scope for all new Dropbox accounts.
	 *
	 * @since 1.0.0
	 *
	 * @param array  $providers The list of providers.
	 * @param string $provider  The current provider slug.
	 * @param mixed  $options   Additional options, if any.
	 * @param string $id        The account ID to update.
	 *
	 * @return array Updated list of providers.
	 *
	 * @noinspection PhpMissingParamTypeInspection
	 */
	public function update_scope_for_account( $providers, $provider, $options, $id ): array {

		$providers = (array) $providers;

		if ( $provider !== DropboxPlugin::SLUG && ! empty( $options ) ) {
			return $providers;
		}

		$provider =& $providers[ DropboxPlugin::SLUG ];

		// Save the current timestamp for tracking scope updates.
		$provider[ $id ]['updated_scopes'] = time();

		return $providers;
	}

	/**
	 * Handle AJAX request to reconnect a Dropbox account with new scopes.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function ajax_dropbox_reconnect(): array {

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		$account_id = ! empty( $_POST['accountId'] ) ? sanitize_text_field( wp_unslash( $_POST['accountId'] ) ) : '';

		if ( empty( $account_id ) ) {
			return [
				'error_msg' => esc_html__( 'Account ID is required.', 'wpforms-entry-automation' ),
			];
		}

		$account = wpforms_dropbox()->get( 'account' )->get( $account_id );

		set_transient(
			self::TRANSIENT_RECONNECT,
			wp_json_encode(
				[
					'account_id' => $account['account_id'],
					'key'        => $account['key'],
				]
			),
			HOUR_IN_SECONDS * 3
		);

		return [];
	}

	/**
	 * Retrieves a list of accounts along with their updated scopes.
	 *
	 * @since 1.0.0
	 *
	 * @return array Returns an array containing the accounts and their updated scopes.
	 */
	public function ajax_get_accounts_with_scopes(): array {

		$accounts          = wpforms_get_providers_options( DropboxPlugin::SLUG );
		$prepared_accounts = array_map(
			static function ( $account ) {

				return [
					'updated_scopes' => (bool) ( $account['updated_scopes'] ?? 0 ),
				];
			},
			$accounts
		);

		return [
			'accounts' => $prepared_accounts,
		];
	}
}