diff --git a/src/sanctum/src/HasApiTokens.php b/src/sanctum/src/HasApiTokens.php index 90f3795a7..03eabc2d6 100644 --- a/src/sanctum/src/HasApiTokens.php +++ b/src/sanctum/src/HasApiTokens.php @@ -55,10 +55,7 @@ public function tokenCant(BackedEnum|string $ability): bool */ public function createToken(string $name, array $abilities = ['*'], ?DateTimeInterface $expiresAt = null): NewAccessToken { - $abilities = array_map( - fn ($ability) => $ability instanceof BackedEnum ? $ability->value : $ability, - $abilities - ); + $abilities = Str::fromAll($abilities); $plainTextToken = $this->generateTokenString(); diff --git a/src/sanctum/src/PersonalAccessToken.php b/src/sanctum/src/PersonalAccessToken.php index 3f60f83bf..e0a761464 100644 --- a/src/sanctum/src/PersonalAccessToken.php +++ b/src/sanctum/src/PersonalAccessToken.php @@ -14,6 +14,7 @@ use Hypervel\Context\ApplicationContext; use Hypervel\Database\Eloquent\Model; use Hypervel\Sanctum\Contracts\HasAbilities; +use Hypervel\Support\Str; /** * @property int|string $id @@ -155,7 +156,7 @@ public static function findTokenable(PersonalAccessToken $accessToken): ?Authent */ public function can(BackedEnum|string $ability): bool { - $ability = $ability instanceof BackedEnum ? $ability->value : $ability; + $ability = Str::from($ability); return in_array('*', $this->abilities) || array_key_exists($ability, array_flip($this->abilities)); diff --git a/tests/Sanctum/HasApiTokensTest.php b/tests/Sanctum/HasApiTokensTest.php index 61d9eca1f..7d96f5c92 100644 --- a/tests/Sanctum/HasApiTokensTest.php +++ b/tests/Sanctum/HasApiTokensTest.php @@ -7,6 +7,7 @@ use Hypervel\Sanctum\PersonalAccessToken; use Hypervel\Sanctum\TransientToken; use Hypervel\Testbench\TestCase; +use Hypervel\Tests\Sanctum\Stub\TokenAbility; use Hypervel\Tests\Sanctum\Stub\UserWithApiTokens; /** @@ -52,4 +53,41 @@ public function testCurrentAccessTokenGetter(): void $this->assertSame($token, $user->currentAccessToken()); } + + public function testTokenCanWithBackedEnum(): void + { + $user = new UserWithApiTokens(); + + $token = new PersonalAccessToken(); + $token->abilities = ['posts:read', 'posts:write']; + + $user->withAccessToken($token); + + $this->assertTrue($user->tokenCan(TokenAbility::PostsRead)); + $this->assertTrue($user->tokenCan(TokenAbility::PostsWrite)); + $this->assertFalse($user->tokenCan(TokenAbility::UsersRead)); + } + + public function testTokenCantWithBackedEnum(): void + { + $user = new UserWithApiTokens(); + + $token = new PersonalAccessToken(); + $token->abilities = ['posts:read']; + + $user->withAccessToken($token); + + $this->assertFalse($user->tokenCant(TokenAbility::PostsRead)); + $this->assertTrue($user->tokenCant(TokenAbility::PostsWrite)); + } + + public function testTransientTokenCanWithBackedEnum(): void + { + $user = new UserWithApiTokens(); + $user->withAccessToken(new TransientToken()); + + // TransientToken allows everything + $this->assertTrue($user->tokenCan(TokenAbility::PostsRead)); + $this->assertTrue($user->tokenCan(TokenAbility::UsersWrite)); + } } diff --git a/tests/Sanctum/PersonalAccessTokenTest.php b/tests/Sanctum/PersonalAccessTokenTest.php index 950ba8d01..0711976e3 100644 --- a/tests/Sanctum/PersonalAccessTokenTest.php +++ b/tests/Sanctum/PersonalAccessTokenTest.php @@ -5,6 +5,7 @@ namespace Hypervel\Tests\Sanctum; use Hypervel\Sanctum\PersonalAccessToken; +use Hypervel\Tests\Sanctum\Stub\TokenAbility; use PHPUnit\Framework\TestCase; /** @@ -33,4 +34,46 @@ public function testCanDetermineWhatItCanAndCantDo(): void $this->assertTrue($token->can('foo')); $this->assertTrue($token->can('bar')); } + + public function testCanCheckAbilitiesWithBackedEnum(): void + { + $token = new PersonalAccessToken(); + $token->abilities = ['posts:read', 'posts:write']; + + $this->assertTrue($token->can(TokenAbility::PostsRead)); + $this->assertTrue($token->can(TokenAbility::PostsWrite)); + $this->assertFalse($token->can(TokenAbility::UsersRead)); + } + + public function testCantCheckAbilitiesWithBackedEnum(): void + { + $token = new PersonalAccessToken(); + $token->abilities = ['posts:read']; + + $this->assertFalse($token->cant(TokenAbility::PostsRead)); + $this->assertTrue($token->cant(TokenAbility::PostsWrite)); + } + + public function testWildcardAbilityWorksWithBackedEnum(): void + { + $token = new PersonalAccessToken(); + $token->abilities = ['*']; + + $this->assertTrue($token->can(TokenAbility::PostsRead)); + $this->assertTrue($token->can(TokenAbility::PostsWrite)); + $this->assertTrue($token->can(TokenAbility::UsersRead)); + } + + public function testMixedStringAndEnumAbilitiesWork(): void + { + $token = new PersonalAccessToken(); + $token->abilities = ['posts:read', 'legacy-ability']; + + // Enum check + $this->assertTrue($token->can(TokenAbility::PostsRead)); + // String check for same value + $this->assertTrue($token->can('posts:read')); + // String check for legacy + $this->assertTrue($token->can('legacy-ability')); + } } diff --git a/tests/Sanctum/Stub/TokenAbility.php b/tests/Sanctum/Stub/TokenAbility.php new file mode 100644 index 000000000..540b3fbc7 --- /dev/null +++ b/tests/Sanctum/Stub/TokenAbility.php @@ -0,0 +1,13 @@ +