Skip to content

Commit

Permalink
Merge pull request PrestaShop#28 from jolelievre/external-server-refacto
Browse files Browse the repository at this point in the history
Update tests, and add API client listing
  • Loading branch information
jolelievre authored Apr 11, 2024
2 parents e975bca + f379b4c commit 428e5cb
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

declare(strict_types=1);

namespace PrestaShop\Module\APIResources\ApiPlatform\Resources;
namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\ApiClient;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
Expand All @@ -39,52 +39,12 @@
new CQRSGet(
uriTemplate: '/api-client/{apiClientId}',
requirements: ['apiClientId' => '\d+'],
openapiContext: [
'summary' => 'Get API Client details',
'description' => 'Get API Client public details only, sensitive information like secrets is not returned',
'parameters' => [
[
'name' => 'apiClientId',
'in' => 'path',
'required' => true,
'schema' => [
'type' => 'string',
],
'description' => 'Id of the API Client you are requesting the details from',
],
[
'name' => 'Authorization',
'in' => 'scopes',
'description' => 'api_client_read',
],
],
],
CQRSQuery: GetApiClientForEditing::class,
scopes: ['api_client_read']
),
new CQRSDelete(
uriTemplate: '/api-client/{apiClientId}',
requirements: ['apiClientId' => '\d+'],
openapiContext: [
'summary' => 'Delete API Client details',
'description' => 'Delete API Client public details only, sensitive information like secrets is not returned',
'parameters' => [
[
'name' => 'apiClientId',
'in' => 'path',
'required' => true,
'schema' => [
'type' => 'string',
],
'description' => 'Id of the API Client you are deleting',
],
[
'name' => 'Authorization',
'in' => 'scopes',
'description' => 'api_client_write',
],
],
],
output: false,
CQRSQuery: DeleteApiClientCommand::class,
scopes: ['api_client_write']
Expand All @@ -102,24 +62,32 @@
scopes: ['api_client_write']
),
],
normalizationContext: ['skip_null_values' => false],
exceptionToStatus: [ApiClientNotFoundException::class => 404],
)]
class ApiClient
{
#[ApiProperty(identifier: true)]
public int $apiClientId;

public string $secret;

public string $clientId;

public string $clientName;

public string $description;

public ?string $externalIssuer;

public bool $enabled;

public int $lifetime;

public array $scopes;

/**
* Only used for the return of created API Client, it is the only endpoint where the secret is returned.
*
* @var string
*/
public string $secret;
}
72 changes: 72 additions & 0 deletions src/ApiPlatform/Resources/ApiClient/ApiClientList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License version 3.0
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/AFL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @author PrestaShop SA and Contributors <[email protected]>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0
*/

declare(strict_types=1);

namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\ApiClient;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use PrestaShop\PrestaShop\Core\Grid\Query\ApiClientQueryBuilder;
use PrestaShop\PrestaShop\Core\Search\Filters\ApiClientFilters;
use PrestaShopBundle\ApiPlatform\Metadata\DQBPaginatedList;

#[ApiResource(
operations: [
new DQBPaginatedList(
uriTemplate: '/api-clients',
scopes: [
'api_client_read',
],
ApiResourceMapping: [
'[id_api_client]' => '[apiClientId]',
'[client_id]' => '[clientId]',
'[client_name]' => '[clientName]',
'[external_issuer]' => '[externalIssuer]',
],
queryBuilder: ApiClientQueryBuilder::class,
filtersClass: ApiClientFilters::class,
filtersMapping: [
'[apiClientId]' => '[id_api_client]',
'[clientId]' => '[client_id]',
'[clientName]' => '[client_name]',
'[externalIssuer]' => '[external_issuer]',
],
),
],
normalizationContext: ['skip_null_values' => false],
)]
class ApiClientList
{
#[ApiProperty(identifier: true)]
public int $apiClientId;

public string $clientId;

public string $clientName;

public string $description;

public ?string $externalIssuer;

public bool $enabled;

public int $lifetime;
}
40 changes: 40 additions & 0 deletions tests/Integration/ApiPlatform/ApiClientEndpointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public function getProtectedEndpoints(): iterable
'DELETE',
'/api-client/1',
];

yield 'list endpoint' => [
'GET',
'/api-clients',
];
}

public function testAddApiClient(): int
Expand Down Expand Up @@ -111,6 +116,7 @@ public function testGetApiClient(int $apiClientId): int
'clientId' => 'client_id_test',
'clientName' => 'Client name test',
'description' => 'Client description test',
'externalIssuer' => null,
'enabled' => true,
'lifetime' => 3600,
'scopes' => [
Expand Down Expand Up @@ -161,6 +167,7 @@ public function testUpdateApiClient(int $apiClientId): int
'clientId' => 'client_id_test_updated',
'clientName' => 'Client name test updated',
'description' => 'Client description test updated',
'externalIssuer' => null,
'enabled' => false,
'lifetime' => 1800,
'scopes' => [
Expand All @@ -177,6 +184,7 @@ public function testUpdateApiClient(int $apiClientId): int
'json' => [
'description' => 'Client description test partially updated',
'lifetime' => 900,
'externalIssuer' => 'http://not-possible-to-modify',
],
]);
self::assertResponseStatusCodeSame(200);
Expand All @@ -190,6 +198,7 @@ public function testUpdateApiClient(int $apiClientId): int
'clientId' => 'client_id_test_updated',
'clientName' => 'Client name test updated',
'description' => 'Client description test partially updated',
'externalIssuer' => null,
'enabled' => false,
'lifetime' => 900,
'scopes' => [
Expand Down Expand Up @@ -226,6 +235,7 @@ public function testGetUpdatedApiClient(int $apiClientId): int
'clientId' => 'client_id_test_updated',
'clientName' => 'Client name test updated',
'description' => 'Client description test partially updated',
'externalIssuer' => null,
'enabled' => false,
'lifetime' => 900,
'scopes' => [
Expand All @@ -243,6 +253,36 @@ public function testGetUpdatedApiClient(int $apiClientId): int
* @depends testGetUpdatedApiClient
*
* @param int $apiClientId
*
* @return int
*/
public function testListApiClients(int $apiClientId): int
{
$apiClients = $this->listItems('/api-clients', ['api_client_read']);
// Two APi Clients, the one created for test to actually use the API and the one created in the previous test
$this->assertEquals(2, $apiClients['totalItems']);

// Test content from the second (most recent) api client created
$this->assertEquals(
[
'apiClientId' => $apiClientId,
'clientId' => 'client_id_test_updated',
'clientName' => 'Client name test updated',
'description' => 'Client description test partially updated',
'externalIssuer' => null,
'enabled' => false,
'lifetime' => 900,
],
$apiClients['items'][1],
);

return $apiClientId;
}

/**
* @depends testListApiClients
*
* @param int $apiClientId
*/
public function testDeleteApiClient(int $apiClientId): void
{
Expand Down
2 changes: 1 addition & 1 deletion tests/Integration/ApiPlatform/ApiTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function testProtectedEndpoints(string $method, string $uri, string $cont

$content = $response->getContent(false);
$this->assertNotEmpty($content);
$this->assertEquals('No Authorization header provided', $content);
$this->assertEquals('"No Authorization header provided"', $content);

// Test same endpoint with a token but without scopes
$emptyBearerToken = $this->getBearerToken();
Expand Down

0 comments on commit 428e5cb

Please sign in to comment.