From c78c6478563d99cb735ea41049970454dc8c2bb2 Mon Sep 17 00:00:00 2001 From: Fran Garcia-Linares Date: Mon, 19 Feb 2024 16:32:22 +0000 Subject: [PATCH 1/5] Add supporting classes. --- src/Api/PersonalAccessTokens.php | 152 +++++++++++++++++++++++++++++++ src/Client.php | 9 ++ 2 files changed, 161 insertions(+) create mode 100644 src/Api/PersonalAccessTokens.php diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php new file mode 100644 index 00000000..a8462c96 --- /dev/null +++ b/src/Api/PersonalAccessTokens.php @@ -0,0 +1,152 @@ + +* (c) Graham Campbell +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +namespace Gitlab\Api; + +use Symfony\Component\OptionsResolver\Options; + +class PersonalAccessTokens extends AbstractApi +{ + /** + * @param array $parameters { + * + * @var string $search search for user by email or username + * @var string $username lookup for user by username + * @var bool $external search for external users only + * @var string $extern_uid lookup for users by external uid + * @var string $provider lookup for users by provider + * @var \DateTimeInterface $created_before return users created before the given time (inclusive) + * @var \DateTimeInterface $created_after return users created after the given time (inclusive) + * @var bool $active Return only active users. It does not support filtering inactive users. + * @var bool $blocked Return only blocked users. It does not support filtering non-blocked users. + * } + * + * @return mixed + */ + public function all(array $parameters = []) + { + $resolver = $this->createOptionsResolver(); + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + return $value->format('c'); + }; + $booleanNormalizer = function (Options $resolver, $value): string { + return $value ? 'true' : 'false'; + }; + + $resolver->setDefined('search'); + $resolver->setDefined('state') + ->setAllowedValues('state', ['active', 'inactive']); + $resolver->setDefined('user_id') + ->setAllowedTypes('user_id', 'int') + ->setAllowedValues('user_id', function ($value): bool { + return $value > 0; + }) + ; + $resolver->setDefined('created_before') + ->setAllowedTypes('created_before', \DateTimeInterface::class) + ->setNormalizer('created_before', $datetimeNormalizer) + ; + $resolver->setDefined('created_after') + ->setAllowedTypes('created_after', \DateTimeInterface::class) + ->setNormalizer('created_after', $datetimeNormalizer) + ; + $resolver->setDefined('last_used_after') + ->setAllowedTypes('last_used_after', \DateTimeInterface::class) + ->setNormalizer('last_used_after', $datetimeNormalizer) + ; + $resolver->setDefined('last_used_before') + ->setAllowedTypes('last_used_before', \DateTimeInterface::class) + ->setNormalizer('last_used_before', $datetimeNormalizer) + ; + $resolver->setDefined('revoked') + ->setAllowedTypes('revoked', 'bool') + ->setNormalizer('revoked', $booleanNormalizer); + ; + + return $this->get('personal_access_tokens', $resolver->resolve($parameters)); + } + + /** + * @param int $id + * + * @return mixed + */ + public function show(int $id) + { + return $this->get('personal_access_tokens/'.self::encodePath($id)); + } + + /** + * @return mixed + */ + public function current() + { + return $this->get('personal_access_tokens/self'); + } + + + /** + * @param int $id + * + * @return mixed + */ + public function rotate(int $id, array $params = []) + { + $resolver = $this->createOptionsResolver(); + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + return $value->format('c'); + }; + $resolver->setDefined('expires_at') + ->setAllowedTypes('expires_at', \DateTimeInterface::class) + ->setNormalizer('expires_at', $datetimeNormalizer) + ; + return $this->post('personal_access_tokens/'.self::encodePath($id).'/rotate', $params); + } + + /** + * @param int $id + * + * @return mixed + */ + public function rotateCurrent(array $params = []) + { + $resolver = $this->createOptionsResolver(); + $datetimeNormalizer = function (Options $resolver, \DateTimeInterface $value): string { + return $value->format('c'); + }; + $resolver->setDefined('expires_at') + ->setAllowedTypes('expires_at', \DateTimeInterface::class) + ->setNormalizer('expires_at', $datetimeNormalizer) + ; + return $this->post('personal_access_tokens/self/rotate', $params); + } + + /** + * @param int $id + * + * @return mixed + */ + public function remove(int $id) + { + return $this->delete('personal_access_tokens/'.self::encodePath($id)); + } + + /** + * @return mixed + */ + public function removeCurrent() + { + return $this->delete('personal_access_tokens/self'); + } +} diff --git a/src/Client.php b/src/Client.php index 4082f1ac..0b5d759d 100644 --- a/src/Client.php +++ b/src/Client.php @@ -30,6 +30,7 @@ use Gitlab\Api\Keys; use Gitlab\Api\MergeRequests; use Gitlab\Api\Milestones; +use Gitlab\Api\PersonalAccessTokens; use Gitlab\Api\ProjectNamespaces; use Gitlab\Api\Projects; use Gitlab\Api\Repositories; @@ -400,6 +401,14 @@ public function users(): Users return new Users($this); } + /** + * @return PersonalAccessTokens + */ + public function personal_access_tokens(): PersonalAccessTokens + { + return new PersonalAccessTokens($this); + } + /** * @return Version */ From e74ad8d3a8ef5a98fe9c65e6dbea9c0805196785 Mon Sep 17 00:00:00 2001 From: Fran Garcia-Linares Date: Tue, 20 Feb 2024 08:02:50 +0000 Subject: [PATCH 2/5] Update comments. --- src/Api/PersonalAccessTokens.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php index a8462c96..24ae517d 100644 --- a/src/Api/PersonalAccessTokens.php +++ b/src/Api/PersonalAccessTokens.php @@ -21,15 +21,14 @@ class PersonalAccessTokens extends AbstractApi /** * @param array $parameters { * - * @var string $search search for user by email or username - * @var string $username lookup for user by username - * @var bool $external search for external users only - * @var string $extern_uid lookup for users by external uid - * @var string $provider lookup for users by provider - * @var \DateTimeInterface $created_before return users created before the given time (inclusive) - * @var \DateTimeInterface $created_after return users created after the given time (inclusive) - * @var bool $active Return only active users. It does not support filtering inactive users. - * @var bool $blocked Return only blocked users. It does not support filtering non-blocked users. + * @var string $search search text + * @var string $state state of the token + * @var int $user_id tokens belonging to the given user + * @var book $revoked whether the token is revoked or not + * @var \DateTimeInterface $created_before return tokens created before the given time (inclusive) + * @var \DateTimeInterface $created_after return tokens created after the given time (inclusive) + * @var \DateTimeInterface $last_used_after return tokens used before the given time (inclusive) + * @var \DateTimeInterface $last_used_before return tokens used after the given time (inclusive) * } * * @return mixed @@ -98,6 +97,8 @@ public function current() /** * @param int $id + * + * @param array $params * * @return mixed */ @@ -115,7 +116,7 @@ public function rotate(int $id, array $params = []) } /** - * @param int $id + * @param array $params * * @return mixed */ From 2d4f293700f201aa5d97171c7734586d8ebc2320 Mon Sep 17 00:00:00 2001 From: Fran Garcia-Linares Date: Tue, 20 Feb 2024 08:05:07 +0000 Subject: [PATCH 3/5] Typo. --- src/Api/PersonalAccessTokens.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php index 24ae517d..e401324d 100644 --- a/src/Api/PersonalAccessTokens.php +++ b/src/Api/PersonalAccessTokens.php @@ -24,7 +24,7 @@ class PersonalAccessTokens extends AbstractApi * @var string $search search text * @var string $state state of the token * @var int $user_id tokens belonging to the given user - * @var book $revoked whether the token is revoked or not + * @var bool $revoked whether the token is revoked or not * @var \DateTimeInterface $created_before return tokens created before the given time (inclusive) * @var \DateTimeInterface $created_after return tokens created after the given time (inclusive) * @var \DateTimeInterface $last_used_after return tokens used before the given time (inclusive) From 0f3cd2c00496742d2c92e418aed0d7521d574041 Mon Sep 17 00:00:00 2001 From: Fran Garcia-Linares Date: Tue, 20 Feb 2024 08:35:44 +0000 Subject: [PATCH 4/5] Use resolvers. --- src/Api/PersonalAccessTokens.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php index e401324d..82490e43 100644 --- a/src/Api/PersonalAccessTokens.php +++ b/src/Api/PersonalAccessTokens.php @@ -112,7 +112,7 @@ public function rotate(int $id, array $params = []) ->setAllowedTypes('expires_at', \DateTimeInterface::class) ->setNormalizer('expires_at', $datetimeNormalizer) ; - return $this->post('personal_access_tokens/'.self::encodePath($id).'/rotate', $params); + return $this->post('personal_access_tokens/'.self::encodePath($id).'/rotate', $resolver->resolve($params)); } /** @@ -130,7 +130,7 @@ public function rotateCurrent(array $params = []) ->setAllowedTypes('expires_at', \DateTimeInterface::class) ->setNormalizer('expires_at', $datetimeNormalizer) ; - return $this->post('personal_access_tokens/self/rotate', $params); + return $this->post('personal_access_tokens/self/rotate', $resolver->resolve($params)); } /** From 12326caeb54636e3ddaefa7d363c9d8552f7049d Mon Sep 17 00:00:00 2001 From: Fran Garcia-Linares Date: Wed, 21 Feb 2024 15:36:46 +0100 Subject: [PATCH 5/5] Added tests. --- src/Api/PersonalAccessTokens.php | 22 ++-- tests/Api/PersonalAccessTokensTest.php | 167 +++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 11 deletions(-) create mode 100644 tests/Api/PersonalAccessTokensTest.php diff --git a/src/Api/PersonalAccessTokens.php b/src/Api/PersonalAccessTokens.php index 82490e43..d42cbaac 100644 --- a/src/Api/PersonalAccessTokens.php +++ b/src/Api/PersonalAccessTokens.php @@ -42,10 +42,10 @@ public function all(array $parameters = []) $booleanNormalizer = function (Options $resolver, $value): string { return $value ? 'true' : 'false'; }; - + $resolver->setDefined('search'); $resolver->setDefined('state') - ->setAllowedValues('state', ['active', 'inactive']); + ->setAllowedValues('state', ['all', 'active', 'inactive']); $resolver->setDefined('user_id') ->setAllowedTypes('user_id', 'int') ->setAllowedValues('user_id', function ($value): bool { @@ -72,10 +72,10 @@ public function all(array $parameters = []) ->setAllowedTypes('revoked', 'bool') ->setNormalizer('revoked', $booleanNormalizer); ; - + return $this->get('personal_access_tokens', $resolver->resolve($parameters)); } - + /** * @param int $id * @@ -85,7 +85,7 @@ public function show(int $id) { return $this->get('personal_access_tokens/'.self::encodePath($id)); } - + /** * @return mixed */ @@ -93,11 +93,11 @@ public function current() { return $this->get('personal_access_tokens/self'); } - - + + /** * @param int $id - * + * * @param array $params * * @return mixed @@ -114,7 +114,7 @@ public function rotate(int $id, array $params = []) ; return $this->post('personal_access_tokens/'.self::encodePath($id).'/rotate', $resolver->resolve($params)); } - + /** * @param array $params * @@ -132,7 +132,7 @@ public function rotateCurrent(array $params = []) ; return $this->post('personal_access_tokens/self/rotate', $resolver->resolve($params)); } - + /** * @param int $id * @@ -142,7 +142,7 @@ public function remove(int $id) { return $this->delete('personal_access_tokens/'.self::encodePath($id)); } - + /** * @return mixed */ diff --git a/tests/Api/PersonalAccessTokensTest.php b/tests/Api/PersonalAccessTokensTest.php new file mode 100644 index 00000000..b3bde36b --- /dev/null +++ b/tests/Api/PersonalAccessTokensTest.php @@ -0,0 +1,167 @@ + + * (c) Graham Campbell + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gitlab\Tests\Api; + +use Gitlab\Api\PersonalAccessTokens; + +class PersonalAccessTokensTest extends TestCase +{ + protected function getApiClass() + { + return PersonalAccessTokens::class; + } + + /** + * @test + */ + public function shouldGetAllTokens(): void + { + $expectedArray = [ + ['id' => 1, 'name' => 'Token 1', 'state' => 'active'], + ['id' => 2, 'name' => 'Token 2', 'state' => 'revoked'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('personal_access_tokens', []) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->all()); + } + + /** + * @test + */ + public function shouldGetActiveTokens(): void + { + $expectedArray = [ + ['id' => 1, 'name' => 'Token 1', 'state' => 'active'], + ]; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('personal_access_tokens', ['state' => 'active']) + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->all(['state' => 'active'])); + } + + /** + * @test + */ + public function shouldShowToken(): void + { + $expectedArray = ['id' => 1, 'name' => 'Token 1', 'state' => 'active']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('personal_access_tokens/1') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->show(1)); + } + + /** + * @test + */ + public function shouldShowCurrent(): void + { + $expectedArray = ['id' => 1, 'name' => 'Token 1', 'state' => 'active']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('get') + ->with('personal_access_tokens/self') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->current()); + } + + /** + * @test + */ + public function shouldRotate(): void + { + $expectedArray = ['id' => 4, 'name' => 'Token 4']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('personal_access_tokens/3/rotate') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->rotate(3)); + } + + /** + * @test + */ + public function shouldRotateCurrent(): void + { + $expectedArray = ['id' => 4, 'name' => 'Token 4']; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('post') + ->with('personal_access_tokens/self/rotate') + ->will($this->returnValue($expectedArray)) + ; + + $this->assertEquals($expectedArray, $api->rotateCurrent()); + } + + /** + * @test + */ + public function shouldRemoveToken(): void + { + $expectedBool = true; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('personal_access_tokens/1') + ->will($this->returnValue($expectedBool)) + ; + + $this->assertEquals($expectedBool, $api->remove(1)); + } + + /** + * @test + */ + public function shouldRemoveCurrentToken(): void + { + $expectedBool = true; + + $api = $this->getApiMock(); + $api->expects($this->once()) + ->method('delete') + ->with('personal_access_tokens/self') + ->will($this->returnValue($expectedBool)) + ; + + $this->assertEquals($expectedBool, $api->removeCurrent()); + } + +}