-
Notifications
You must be signed in to change notification settings - Fork 294
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #757 from google/feature/755-1.0-migration
Add 1.0 Migration
- Loading branch information
Showing
3 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?php | ||
/** | ||
* Migration for v1.0 | ||
* | ||
* @package Google\Site_Kit\Core\Util | ||
* @copyright 2019 Google LLC | ||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 | ||
* @link https://sitekit.withgoogle.com | ||
*/ | ||
|
||
namespace Google\Site_Kit\Core\Util; | ||
|
||
use Google\Site_Kit\Context; | ||
use Google\Site_Kit\Core\Authentication\Authentication; | ||
use Google\Site_Kit\Core\Authentication\Clients\OAuth_Client; | ||
use Google\Site_Kit\Core\Authentication\Credentials; | ||
use Google\Site_Kit\Core\Storage\Encrypted_Options; | ||
use Google\Site_Kit\Core\Storage\Options; | ||
use Google\Site_Kit\Core\Storage\User_Options; | ||
|
||
/** | ||
* Class Migration_1_0_0 | ||
* | ||
* @since 1.0.0 | ||
* @access private | ||
* @ignore | ||
*/ | ||
class Migration_1_0_0 { | ||
|
||
/** | ||
* Target DB version. | ||
*/ | ||
const DB_VERSION = '1.0.0'; | ||
|
||
/** | ||
* Context instance. | ||
* | ||
* @var Context | ||
*/ | ||
protected $context; | ||
|
||
/** | ||
* Options instance. | ||
* | ||
* @var Options | ||
*/ | ||
protected $options; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @since 1.0.0 | ||
* | ||
* @param Context $context Plugin context instance. | ||
*/ | ||
public function __construct( Context $context ) { | ||
$this->context = $context; | ||
$this->options = new Options( $context ); | ||
} | ||
|
||
/** | ||
* Registers hooks. | ||
* | ||
* @since 1.0.0 | ||
*/ | ||
public function register() { | ||
add_action( 'admin_init', array( $this, 'migrate' ) ); | ||
} | ||
|
||
/** | ||
* Migrates the DB. | ||
* | ||
* @since 1.0.0 | ||
*/ | ||
public function migrate() { | ||
$db_version = $this->options->get( 'googlesitekit_db_version' ); | ||
|
||
if ( ! $db_version || version_compare( $db_version, self::DB_VERSION, '<' ) ) { | ||
$this->migrate_install(); | ||
|
||
$this->options->set( 'googlesitekit_db_version', self::DB_VERSION ); | ||
} | ||
} | ||
|
||
/** | ||
* Migrates old credentials and disconnects users. | ||
* | ||
* @since 1.0.0 | ||
*/ | ||
private function migrate_install() { | ||
$credentials = ( new Encrypted_Options( $this->options ) )->get( Credentials::OPTION ); | ||
|
||
// Credentials can be filtered in so we must also check if there is a saved option present. | ||
if ( isset( $credentials['oauth2_client_id'] ) && strpos( $credentials['oauth2_client_id'], '.apps.sitekit.withgoogle.com' ) ) { | ||
$this->options->delete( Credentials::OPTION ); | ||
$this->options->set( Beta_Migration::OPTION_IS_PRE_PROXY_INSTALL, 1 ); | ||
|
||
$this->disconnect_users(); | ||
|
||
wp_cache_flush(); | ||
} | ||
} | ||
|
||
/** | ||
* Disconnects authenticated users. | ||
* | ||
* @since 1.0.0 | ||
*/ | ||
private function disconnect_users() { | ||
global $wpdb; | ||
|
||
$user_options = new User_Options( $this->context ); | ||
$authentication = new Authentication( $this->context, $this->options, $user_options ); | ||
|
||
// User option keys are prefixed in single site and multisite when not in network mode. | ||
$key_prefix = $this->context->is_network_mode() ? '' : $wpdb->get_blog_prefix(); | ||
$user_ids = ( new \WP_User_Query( | ||
array( | ||
'fields' => 'id', | ||
'meta_key' => $key_prefix . OAuth_Client::OPTION_ACCESS_TOKEN, | ||
'compare' => 'EXISTS', | ||
) | ||
) )->get_results(); | ||
|
||
foreach ( $user_ids as $user_id ) { | ||
$user_options->switch_user( (int) $user_id ); | ||
$authentication->disconnect(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
tests/phpunit/integration/Core/Util/Migration_1_0_0Test.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
<?php | ||
/** | ||
* \Google\Site_Kit\Core\Util\Migration_1_0_0Test | ||
* | ||
* @package Google\Site_Kit\Tests\Core\Util | ||
* @copyright 2019 Google LLC | ||
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 | ||
* @link https://sitekit.withgoogle.com | ||
*/ | ||
|
||
namespace Google\Site_Kit\Tests\Core\Util; | ||
|
||
use Google\Site_Kit\Context; | ||
use Google\Site_Kit\Core\Authentication\Clients\OAuth_Client; | ||
use Google\Site_Kit\Core\Authentication\Credentials; | ||
use Google\Site_Kit\Core\Storage\Options; | ||
use Google\Site_Kit\Core\Util\Migration_1_0_0; | ||
use Google\Site_Kit\Tests\TestCase; | ||
|
||
class Migration_1_0_0Test extends TestCase { | ||
|
||
public function test_register() { | ||
$migration = new Migration_1_0_0( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ); | ||
remove_all_actions( 'admin_init' ); | ||
|
||
$migration->register(); | ||
|
||
$this->assertTrue( has_action( 'admin_init' ) ); | ||
} | ||
|
||
public function test_migrate() { | ||
$context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); | ||
$options = new Options( $context ); | ||
$credentials = new Credentials( $options ); | ||
$migration = new Migration_1_0_0( $context ); | ||
|
||
// Upgrade will update the DB version if run. | ||
$this->delete_db_version(); | ||
|
||
$migration->migrate(); | ||
|
||
$this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); | ||
|
||
// The upgrade will NOT delete old GCP credentials if present. | ||
$this->delete_db_version(); | ||
$this->set_gcp_credentials(); | ||
$this->assertTrue( $credentials->has() ); | ||
|
||
$migration->migrate(); | ||
|
||
$this->assertTrue( $credentials->has() ); | ||
$this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); | ||
|
||
// The upgrade WILL delete proxy credentials if present. | ||
$this->delete_db_version(); | ||
$this->set_proxy_credentials(); | ||
$this->assertTrue( $credentials->has() ); | ||
|
||
$migration->migrate(); | ||
|
||
$this->assertFalse( $credentials->has() ); | ||
$this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); | ||
|
||
// The upgrade will not disconnect any user if GCP credentials are present. | ||
$this->delete_db_version(); | ||
$this->set_gcp_credentials(); | ||
|
||
$users_with_tokens = array( | ||
$this->create_user_with_access_token(), | ||
$this->create_user_with_access_token(), | ||
$this->create_user_with_access_token(), | ||
); | ||
$users_without = array( | ||
$this->factory()->user->create(), | ||
$this->factory()->user->create(), | ||
$this->factory()->user->create(), | ||
); | ||
|
||
$migration->migrate(); | ||
|
||
foreach ( $users_with_tokens as $user_with_token ) { | ||
$this->assertUserHasAccessToken( $user_with_token ); | ||
} | ||
|
||
// The upgrade will disconnect any user with an auth token if proxy credentials are present. | ||
$this->delete_db_version(); | ||
$this->set_proxy_credentials(); | ||
|
||
$migration->migrate(); | ||
|
||
foreach ( $users_with_tokens as $user_who_had_token ) { | ||
$this->assertUserNotHasAccessToken( $user_who_had_token ); | ||
} | ||
foreach ( $users_without as $user_without ) { | ||
$this->assertUserNotHasAccessToken( $user_without ); | ||
} | ||
} | ||
|
||
private function assertUserHasAccessToken( $user_id ) { | ||
$this->assertNotEmpty( get_user_option( OAuth_Client::OPTION_ACCESS_TOKEN, $user_id ) ); | ||
} | ||
|
||
private function assertUserNotHasAccessToken( $user_id ) { | ||
$this->assertEmpty( get_user_option( OAuth_Client::OPTION_ACCESS_TOKEN, $user_id ) ); | ||
} | ||
|
||
private function create_user_with_access_token() { | ||
$user_id = $this->factory()->user->create(); | ||
update_user_option( $user_id, OAuth_Client::OPTION_ACCESS_TOKEN, "test-access-token-$user_id" ); | ||
|
||
return $user_id; | ||
} | ||
|
||
private function get_db_version() { | ||
return ( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->get( 'googlesitekit_db_version' ); | ||
} | ||
|
||
private function delete_db_version() { | ||
( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->delete( 'googlesitekit_db_version' ); | ||
} | ||
|
||
private function delete_credentials() { | ||
( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->delete( Credentials::OPTION ); | ||
} | ||
|
||
private function set_gcp_credentials() { | ||
( new Credentials( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) ) )->set( array( | ||
'oauth2_client_id' => 'test-client-id.apps.googleusercontent.com', | ||
'oauth2_client_secret' => 'test-client-secret', | ||
) ); | ||
} | ||
|
||
private function set_proxy_credentials() { | ||
( new Credentials( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) ) )->set( array( | ||
'oauth2_client_id' => 'test-site-id.apps.sitekit.withgoogle.com', | ||
'oauth2_client_secret' => 'test-site-secret', | ||
) ); | ||
} | ||
} |