From 796c52018f59e4d1be5522cec7ebfcbd34103c13 Mon Sep 17 00:00:00 2001 From: Rommel Castro Date: Wed, 17 Aug 2022 02:21:16 -0600 Subject: [PATCH] Add `wc com connect` command (#34073) --- .../changelog/add-wc-com-connect-command | 4 + .../includes/admin/helper/class-wc-helper.php | 98 +++++++++++++++---- .../includes/cli/class-wc-cli-com-command.php | 76 ++++++++++++++ 3 files changed, 158 insertions(+), 20 deletions(-) create mode 100644 plugins/woocommerce/changelog/add-wc-com-connect-command diff --git a/plugins/woocommerce/changelog/add-wc-com-connect-command b/plugins/woocommerce/changelog/add-wc-com-connect-command new file mode 100644 index 00000000000..925bbd892c8 --- /dev/null +++ b/plugins/woocommerce/changelog/add-wc-com-connect-command @@ -0,0 +1,4 @@ +Significance: minor +Type: dev + +Add `wc com connect` command to allow stores to connect to WCCOM via CLI diff --git a/plugins/woocommerce/includes/admin/helper/class-wc-helper.php b/plugins/woocommerce/includes/admin/helper/class-wc-helper.php index c6f9a6d3d9c..d06c3a7b4ab 100644 --- a/plugins/woocommerce/includes/admin/helper/class-wc-helper.php +++ b/plugins/woocommerce/includes/admin/helper/class-wc-helper.php @@ -809,26 +809,7 @@ class WC_Helper { wp_die( 'Something went wrong' ); } - WC_Helper_Options::update( - 'auth', - array( - 'access_token' => $access_token['access_token'], - 'access_token_secret' => $access_token['access_token_secret'], - 'site_id' => $access_token['site_id'], - 'user_id' => get_current_user_id(), - 'updated' => time(), - ) - ); - - // Obtain the connected user info. - if ( ! self::_flush_authentication_cache() ) { - self::log( 'Could not obtain connected user info in _helper_auth_return' ); - WC_Helper_Options::update( 'auth', array() ); - wp_die( 'Something went wrong.' ); - } - - self::_flush_subscriptions_cache(); - self::_flush_updates_cache(); + self::update_auth_option( $access_token['access_token'], $access_token['access_token_secret'], $access_token['site_id'] ); /** * Fires when the Helper connection process has completed successfully. @@ -1697,6 +1678,83 @@ class WC_Helper { // If `access_token` is empty, there's no active connection. return ! empty( $auth['access_token'] ); } + + /** + * Allows to connect with WCCOM using application password. used it to connect via CLI + * + * @param string $password The application password. + * + * @return void|WP_Error + */ + public static function connect_with_password( string $password ) { + $request = WC_Helper_API::post( + 'connect', + array( + 'headers' => array( + 'X-API-Key' => $password, + 'Content-Type' => 'application/json', + ), + 'body' => wp_json_encode( array( 'home_url' => home_url() ) ), + 'authenticated' => false, + ) + ); + + $code = wp_remote_retrieve_response_code( $request ); + + if ( $code === 403 ) { + $message = 'Invalid password'; + self::log( $message ); + + return new WP_Error( 'connect-with-password-invalid-password', $message ); + } elseif ( $code !== 200 ) { + $message = sprintf( 'Call to /connect returned a non-200 response code (%d)', $code ); + self::log( $message ); + + return new WP_Error( 'connect-with-password-' . $code, $message ); + } + + $access_data = json_decode( wp_remote_retrieve_body( $request ), true ); + if ( empty( $access_data['access_token'] ) || empty( $access_data['access_token_secret'] ) ) { + $message = sprintf( 'Call to /connect returned an invalid body: %s', wp_remote_retrieve_body( $request ) ); + self::log( $message ); + + return new WP_Error( 'connect-with-password-invalid-response', $message ); + } + + self::update_auth_option( $access_data['access_token'], $access_data['access_token_secret'], $access_data['site_id'] ); + } + + /** + * Updates auth options and flushes cache + * + * @param string $access_token The access token. + * @param string $access_token_secret The secret access token. + * @param int $site_id The site id returned by the API. + * + * @return void + */ + public static function update_auth_option( string $access_token, string $access_token_secret, int $site_id ): void { + WC_Helper_Options::update( + 'auth', + array( + 'access_token' => $access_token, + 'access_token_secret' => $access_token_secret, + 'site_id' => $site_id, + 'user_id' => get_current_user_id(), + 'updated' => time(), + ) + ); + + // Obtain the connected user info. + if ( ! self::_flush_authentication_cache() ) { + self::log( 'Could not obtain connected user info in _helper_auth_return.' ); + WC_Helper_Options::update( 'auth', array() ); + wp_die( 'Something went wrong. Could not obtain connected user info in _helper_auth_return.' ); + } + + self::_flush_subscriptions_cache(); + self::_flush_updates_cache(); + } } WC_Helper::load(); diff --git a/plugins/woocommerce/includes/cli/class-wc-cli-com-command.php b/plugins/woocommerce/includes/cli/class-wc-cli-com-command.php index 29f55d23ec3..8ef6fd250a2 100644 --- a/plugins/woocommerce/includes/cli/class-wc-cli-com-command.php +++ b/plugins/woocommerce/includes/cli/class-wc-cli-com-command.php @@ -22,6 +22,7 @@ class WC_CLI_COM_Command { public static function register_commands() { WP_CLI::add_command( 'wc com extension list', array( 'WC_CLI_COM_Command', 'list_extensions' ) ); WP_CLI::add_command( 'wc com disconnect', array( 'WC_CLI_COM_Command', 'disconnect' ) ); + WP_CLI::add_command( 'wc com connect', array( 'WC_CLI_COM_Command', 'connect' ) ); } /** @@ -116,4 +117,79 @@ class WC_CLI_COM_Command { WC_Helper::disconnect(); WP_CLI::success( 'You have successfully disconnected your store from WooCommerce.com' ); } + + /** + * Connects to WooCommerce.com with application-password. + * + * [--password] + * : If set, password won't be prompt. + * + * [--force] + * : If set, site will be disconnected and a new connection will be forced. + * + * ## EXAMPLES + * + * # Connect to WCCOM using password. + * $ wp wc com connect + * + * # force connecting to WCCOM even if site is already connected. + * $ wp wc com connect --force + * + * # Pass password to comman. + * $ wp wc com connect --password=PASSWORD + * + * @param array $args Positional arguments to include when calling the command. + * @param array $assoc_args Associative arguments to include when calling the command. + * + * @return void + * @throws \WP_CLI\ExitException If WP_CLI::$capture_exit is true. + */ + public static function connect( array $args, array $assoc_args ) { + $password = \WP_CLI\Utils\get_flag_value( $assoc_args, 'password' ); + $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false ); + + if ( WC_Helper::is_site_connected() ) { + if ( $force ) { + WC_Helper::disconnect(); + } else { + WP_CLI::error( 'Your store is already connected.' ); + + return; + } + } + + // @todo add URL to application password section + if ( empty( $password ) ) { + $password = self::ask( 'Connection password:' ); + } + $password = sanitize_text_field( $password ); + if ( empty( $password ) ) { + WP_CLI::error( 'Invalid password.' ); + } + + $auth = WC_Helper::connect_with_password( $password ); + if ( is_wp_error( $auth ) ) { + WP_CLI::error( $auth->get_error_message() ); + } + + if ( WC_Helper::is_site_connected() ) { + WP_CLI::success( 'Store connected successfully.' ); + } + } + + /** + * We are asking a question and returning an answer as a string. + * + * @param string $question The question being prompt. + * + * @return string + */ + protected static function ask( $question ) { + // phpcs:disable WordPress.WP.AlternativeFunctions.file_system_read_fwrite + // Adding space to question and showing it. + fwrite( STDOUT, $question . ' ' ); + + return trim( fgets( STDIN ) ); + // phpcs:enable + } }