Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Multiple tokens #73

Merged
merged 76 commits into from
Jul 22, 2024

Conversation

dpanta94
Copy link
Member

Modify library in order to be able to support multiple oAuth Tokens.

Current implementation would assume always ONE oAuth field per instance of the Uplink Library, which for the case of TEC for example can be problematic since every next auth would overwrite every previous.

@dpanta94 dpanta94 added the enhancement New feature or request label Jul 16, 2024
@dpanta94 dpanta94 requested a review from redscar July 16, 2024 12:43
@dpanta94 dpanta94 self-assigned this Jul 16, 2024
@tarecord tarecord requested review from borkweb and tarecord July 16, 2024 13:33
@dpanta94 dpanta94 marked this pull request as ready for review July 16, 2024 19:28
/**
* @test
*/
public function it_should_have_backwards_compatibility_with_single_and_multiple_tokens(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this backwards compatibility test check that this works with existing site tokens?
It seems like it's only checking that the token option can be updated with a single token vs multiple tokens.

We want to make sure that the Token_Manager is able to retrieve the old tokens right?

i.e.

update_network_option( get_current_network_id(), 'custom_uplink_auth_token', 'single-token');

// Token_Manager::get() without slug.
$this->assertSame( 'single-token', $this->token_manager->get() );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I'll either add in another test or alter the above to add in this logic.

Copy link
Member Author

@dpanta94 dpanta94 Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being covered by existing tests though. see for example test_it_stores_and_retrieves_a_token_from_the_network in tests/wpunit/Auth/Token/CustomDomainMultisiteTokenMangerTest.php and test_it_stores_and_retrieves_a_token in tests/wpunit/Auth/Token/SingleSiteTokenMangerTest.php

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added one more set of tests in this PR #75

@borkweb borkweb requested a review from defunctl July 17, 2024 03:04
redscar and others added 2 commits July 17, 2024 08:58
Copy link
Contributor

@defunctl defunctl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this!

I have an older PR Kadence is using right now where this might affect some things: #51

I wonder if this should be adjusted to pass around a Resource instance instead, that way we get access to everything on that resource without having to add additional parameters to methods.

e.g.

  1. My Connect Controller: https://github.com/stellarwp/uplink/pull/51/files#diff-2e3f301aebd5969dffb8de7ff6884dd1ea1d52547c53465beff122ccf2bad276R121
  2. To the Connector: https://github.com/stellarwp/uplink/pull/51/files#diff-b079829dc4be105a4544cf7ce80219d8d1e914ae770b5ac2c0e19ba67261f86eR27

Of course, this means the Token Manager should be taking in a nullable Resource instance where we can then use $resource->slug if not null and still provided that backwards compatibility.

Let me know if you have any questions or want to discuss.

* @test
*/
public function it_should_have_backwards_compatibility_with_single_and_multiple_tokens(): void {
$collection = Config::get_container()->get( Collection::class );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anywhere in this test.

*
* @return null|string|array
*/
public function get_all() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to think about what to do about this. On one hand, we've already modified the existing Token_Manager Contract, but in a backwards compatible way.

So, rather than just adding this to the contract, I think we're going to need a new Multiple_Token_Manager interface that extends the existing Token_Manager Contract and the container bindings updated and pass around that new interface instead so anyone asking for the original contract externally shouldn't be affected.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @defunctl ! First of all thank you so much for your detailed review.

Have a question about this. The reason i didn't add this in the existing interface (or any other interface) in the first place, is that this method is acting in a way that serves both installations storing a single token or multiple tokens.

So it could return

null when no option stored
string when still in the schema of storing a single token only
array when storing multiple tokens in the same option.

In the interface i cant declare mixed as the return type since 7.X version of php don't support it.

I could still create an interface but without type hinting the return value. Let me know what do you think please.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also i don't think we should update the binding in the container. Rather i would update Token_Manager to implement the new interface instead.

Since Token_Manager is a final class i am thinking there shouldn't be any dangers doing that.

* @return string
*/
protected function validate_slug( string $slug = '' ): string {
return $slug && Config::get_container()->get( Collection::class )->offsetExists( $slug ) ? $slug : '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should utilize dependency injection instead of a service locator anti-pattern, pass Collection to the constructor of this class instead.

Update the container bindings to fetch the singleton instance.

Suggested change
return $slug && Config::get_container()->get( Collection::class )->offsetExists( $slug ) ? $slug : '';
return $slug && $this->collection->offsetExists( $slug ) ? $slug : '';

/**
* @before
*/
protected function multiple_tokens_setup(): void {
Copy link
Contributor

@defunctl defunctl Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given my DI suggestion for the Token Manager, this entire method should be replaced with the following so we are using the correct container instance that all tests are using:

	/**
	 * @var Collection
	 */
	private $collection;

	protected function setUp(): void {
		parent::setUp();

		Config::set_token_auth_prefix( 'custom_' );

		// Run init again to reload the Token/Provider.
		Uplink::init();

		$this->collection    = $this->container->get( Collection::class );
		$this->token_manager = $this->container->get( Token_Manager::class );
	}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The protected function multiple_tokens_setup(): void method can be completely removed now.

* @return mixed
*/
public function setup_container_get_slug( array $resource ) {
$collection = Config::get_container()->get( Collection::class );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$collection = Config::get_container()->get( Collection::class );

@@ -48,7 +48,7 @@ public function test_it_stores_and_retrieves_a_token_from_the_network(): void {

$this->assertSame( $token, $this->token_manager->get() );

$this->assertSame( $token, get_network_option( get_current_network_id(), $this->token_manager->option_name() ) );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )[0] );

@@ -48,7 +48,7 @@ public function test_it_stores_and_retrieves_a_token_from_the_network(): void {

$this->assertSame( $token, $this->token_manager->get() );

$this->assertSame( $token, get_network_option( get_current_network_id(), $this->token_manager->option_name() ) );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )[0] );

@@ -48,7 +48,7 @@ public function test_it_stores_and_retrieves_a_token_from_the_network(): void {

$this->assertSame( $token, $this->token_manager->get() );

$this->assertSame( $token, get_network_option( get_current_network_id(), $this->token_manager->option_name() ) );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )['0'] );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $this->token_manager->option_name() ) )[0] );

@@ -73,7 +73,7 @@ public function test_it_does_not_authorize_a_subsite_with_an_existing_network_to
// Store a token while on the main site.
$this->assertTrue( $token_manager->store( '695be4b3-ad6e-4863-9287-3052f597b1f6' ) );

$this->assertSame( $token, get_network_option( get_current_network_id(), $token_manager->option_name() ) );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $token_manager->option_name() ) )['0'] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $token_manager->option_name() ) )['0'] );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $token_manager->option_name() ) )[0] );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this one.

$slug = $this->validate_slug( $slug );

if ( ! $slug ) {
return delete_network_option( get_current_network_id(), $this->option_name );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this saying that if we don't have the slug in the resource collection, we delete all the data?

Wouldn't that delete other slug data as well or am I missing something?

@redscar redscar mentioned this pull request Jul 17, 2024
@@ -73,7 +73,7 @@ public function test_it_does_not_authorize_a_subsite_with_an_existing_network_to
// Store a token while on the main site.
$this->assertTrue( $token_manager->store( '695be4b3-ad6e-4863-9287-3052f597b1f6' ) );

$this->assertSame( $token, get_network_option( get_current_network_id(), $token_manager->option_name() ) );
$this->assertSame( $token, array_values( get_network_option( get_current_network_id(), $token_manager->option_name() ) )['0'] );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this one.

/**
* @before
*/
protected function multiple_tokens_setup(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The protected function multiple_tokens_setup(): void method can be completely removed now.

@dpanta94 dpanta94 merged commit 4375b18 into feat/fluent-form-builder Jul 22, 2024
13 checks passed
@dpanta94 dpanta94 deleted the feat/support-multiple-tokens branch July 22, 2024 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants