diff --git a/src/Uplink/Auth/Admin/Connect_Controller.php b/src/Uplink/Auth/Admin/Connect_Controller.php index 7eed335c..361fbdd4 100644 --- a/src/Uplink/Auth/Admin/Connect_Controller.php +++ b/src/Uplink/Auth/Admin/Connect_Controller.php @@ -179,5 +179,14 @@ public function maybe_store_token_data(): void { * @param \StellarWP\Uplink\Resources\Resource $plugin The plugin that was connected. */ do_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $slug . '/connected', $plugin ); + + /** + * Fires after a plugin has been connected. + * + * @since 2.2.2 + * + * @param \StellarWP\Uplink\Resources\Resource $plugin The plugin that was connected. + */ + do_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected', $plugin ); } } diff --git a/src/Uplink/Auth/Admin/Disconnect_Controller.php b/src/Uplink/Auth/Admin/Disconnect_Controller.php index 2bc2d4e3..91370acf 100644 --- a/src/Uplink/Auth/Admin/Disconnect_Controller.php +++ b/src/Uplink/Auth/Admin/Disconnect_Controller.php @@ -9,6 +9,7 @@ use StellarWP\Uplink\Notice\Notice_Handler; use StellarWP\Uplink\Notice\Notice; use StellarWP\Uplink\Resources\Resource; +use StellarWP\Uplink\Config; final class Disconnect_Controller { @@ -111,6 +112,24 @@ public function maybe_disconnect(): void { true ) ); + + /** + * Fires after a plugin has been disconnected. + * + * @since 2.2.2 + * + * @param string $slug The plugin slug that was disconnected. + */ + do_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $_GET[ self::SLUG ] . '/disconnected', $_GET[ self::SLUG ] ); + + /** + * Fires after a plugin has been disconnected. + * + * @since 2.2.2 + * + * @param string $slug The plugin slug that was disconnected. + */ + do_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/disconnected', $_GET[ self::SLUG ] ); } else { $this->notice->add( new Notice( Notice::ERROR, diff --git a/tests/wpunit/Auth/Admin/ConnectControllerTest.php b/tests/wpunit/Auth/Admin/ConnectControllerTest.php index 7712437c..f40db29d 100644 --- a/tests/wpunit/Auth/Admin/ConnectControllerTest.php +++ b/tests/wpunit/Auth/Admin/ConnectControllerTest.php @@ -83,6 +83,7 @@ public function test_it_stores_basic_token_data(): void { $this->assertSame( $token, $this->token_manager->get( $this->plugin ) ); $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } public function test_it_sets_additional_license_key(): void { @@ -113,6 +114,7 @@ public function test_it_sets_additional_license_key(): void { $this->assertSame( $token, $this->token_manager->get( $this->plugin ) ); $this->assertSame( $this->plugin->get_license_key(), $license ); $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } public function test_it_does_not_store_with_an_invalid_nonce(): void { @@ -134,6 +136,7 @@ public function test_it_does_not_store_with_an_invalid_nonce(): void { $this->assertNull( $this->token_manager->get( $this->plugin ) ); $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } public function test_it_does_not_store_an_invalid_token(): void { @@ -159,6 +162,7 @@ public function test_it_does_not_store_an_invalid_token(): void { $this->assertNull( $this->token_manager->get( $this->plugin ) ); $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } public function test_it_does_not_stores_token_or_license_with_a_slug_that_does_not_exist(): void { @@ -224,6 +228,7 @@ public function test_it_stores_token_but_not_license_without_a_license(): void { $this->assertSame( $token, $this->token_manager->get( $this->plugin ) ); $this->assertEmpty( $this->plugin->get_license_key() ); $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } /** @@ -266,6 +271,7 @@ public function test_it_sets_token_and_additional_license_key_on_multisite_netwo $this->assertSame( $token, $this->token_manager->get( $this->plugin ) ); $this->assertSame( $this->plugin->get_license_key( 'network' ), $license ); $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } /** @@ -310,6 +316,7 @@ public function test_it_stores_token_data_on_subfolder_subsite(): void { $this->assertSame( $token, $this->token_manager->get( $this->plugin ) ); $this->assertSame( $this->plugin->get_license_key( 'network' ), $license ); $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/connected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected' ) ); } } diff --git a/tests/wpunit/Auth/Admin/DisconnectControllerTest.php b/tests/wpunit/Auth/Admin/DisconnectControllerTest.php new file mode 100644 index 00000000..e630b1b6 --- /dev/null +++ b/tests/wpunit/Auth/Admin/DisconnectControllerTest.php @@ -0,0 +1,224 @@ +assertSame( + 'kadence_' . Token_Manager::TOKEN_SUFFIX, + $this->container->get( Config::TOKEN_OPTION_NAME ) + ); + + $this->token_manager = $this->container->get( Token_Manager::class ); + + // Register the sample plugin as a developer would in their plugin. + $this->plugin = Register::plugin( + $this->slug, + 'Lib Sample', + '1.0.10', + 'uplink/index.php', + Sample_Plugin::class + ); + + // Set a license key. + $this->plugin->set_license_key( '123456', 'network' ); + + // Set a token. + $this->token_manager->store( $this->token, $this->plugin ); + } + + public function test_it_disconnects_data(): void { + global $_GET; + + wp_set_current_user( 1 ); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + + // Mock these were passed via the query string. + $_GET[ Disconnect_Controller::ARG ] = 1; + $_GET[ Disconnect_Controller::CACHE_KEY ] = 'nada'; + $_GET[ Disconnect_Controller::SLUG ] = $this->slug; + $_GET['_wpnonce'] = wp_create_nonce( Disconnect_Controller::ARG ); + + // Mock we're an admin inside the dashboard. + $this->admin_init(); + + // Fire off the specification action tied to this slug. + do_action( $this->container->get( Action_Manager::class )->get_hook_name( $this->slug ) ); + + $this->assertNull( $this->token_manager->get( $this->plugin ) ); + // see how the license is still stored! + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/disconnected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/disconnected' ) ); + } + + public function test_it_does_not_disconnect_with_an_invalid_nonce(): void { + global $_GET; + + wp_set_current_user( 1 ); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + + // Mock these were passed via the query string. + $_GET[ Disconnect_Controller::ARG ] = 1; + $_GET[ Disconnect_Controller::CACHE_KEY ] = 'nada'; + $_GET[ Disconnect_Controller::SLUG ] = $this->slug; + $_GET['_wpnonce'] = 'invalid-nonce'; + + // Mock we're an admin inside the dashboard. + $this->admin_init(); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/disconnected' ) ); + $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/disconnected' ) ); + } + + public function test_it_does_not_disconnect_with_a_slug_that_does_not_exist(): void { + global $_GET; + + wp_set_current_user( 1 ); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + + // Mock these were passed via the query string. + $_GET[ Disconnect_Controller::ARG ] = 1; + $_GET[ Disconnect_Controller::CACHE_KEY ] = 'nada'; + $_GET[ Disconnect_Controller::SLUG ] = 'a-plugin-slug-that-does-not-exist'; + $_GET['_wpnonce'] = wp_create_nonce( Disconnect_Controller::ARG ); + + // Mock we're an admin inside the dashboard. + $this->admin_init(); + + // Fire off the specification action tied to this slug. + do_action( $this->container->get( Action_Manager::class )->get_hook_name( $this->slug ) ); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + $this->assertEmpty( did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/a-plugin-slug-that-does-not-exist/disconnected' ) ); + } + + /** + * @env multisite + */ + public function test_it_disconnects_on_multisite_network(): void { + global $_GET; + + // Create a subsite, but we won't use it. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + $this->assertTrue( is_multisite() ); + wp_set_current_user( 1 ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->assertTrue( update_site_option( 'active_sitewide_plugins', [ + 'uplink/index.php' => time(), + ] ) ); + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + + // Mock these were passed via the query string. + $_GET[ Disconnect_Controller::ARG ] = 1; + $_GET[ Disconnect_Controller::CACHE_KEY ] = 'nada'; + $_GET[ Disconnect_Controller::SLUG ] = $this->slug; + $_GET['_wpnonce'] = wp_create_nonce( Disconnect_Controller::ARG ); + + // Mock we're an admin inside the NETWORK dashboard. + $this->admin_init( true ); + + // Fire off the specification action tied to this slug. + do_action( $this->container->get( Action_Manager::class )->get_hook_name( $this->slug ) ); + + $this->assertNull( $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/disconnected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/disconnected' ) ); + } + + /** + * @env multisite + */ + public function test_it_disconnects_on_subfolder_subsite(): void { + global $_GET; + + // Create a subsite. + $sub_site_id = wpmu_create_blog( 'wordpress.test', '/sub1', 'Test Subsite', 1 ); + $this->assertNotInstanceOf( WP_Error::class, $sub_site_id ); + $this->assertGreaterThan( 1, $sub_site_id ); + $this->assertTrue( is_multisite() ); + + // Use this site, which should not allow a token to be set. + switch_to_blog( $sub_site_id ); + wp_set_current_user( 1 ); + + // Mock our sample plugin is network activated, otherwise license key check fails. + $this->mock_activate_plugin( 'uplink/index.php', true ); + + $this->assertEquals( $this->token, $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + + // Mock these were passed via the query string. + $_GET[ Disconnect_Controller::ARG ] = 1; + $_GET[ Disconnect_Controller::CACHE_KEY ] = 'nada'; + $_GET[ Disconnect_Controller::SLUG ] = $this->slug; + $_GET['_wpnonce'] = wp_create_nonce( Disconnect_Controller::ARG ); + + // Mock we're in the subsite admin. + $this->admin_init(); + + // Fire off the specification action tied to this slug. + do_action( $this->container->get( Action_Manager::class )->get_hook_name( $this->slug ) ); + + $this->assertNull( $this->token_manager->get( $this->plugin ) ); + $this->assertEquals( '123456', $this->plugin->get_license_key( 'network' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/' . $this->slug . '/disconnected' ) ); + $this->assertEquals( 1, did_action( 'stellarwp/uplink/' . Config::get_hook_prefix() . '/disconnected' ) ); + } + +}