refactor: add AbstractProvider

This commit is contained in:
Maël Gangloff 2024-08-23 02:35:09 +02:00
parent adb67d2e24
commit b59c1c61dc
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
10 changed files with 95 additions and 67 deletions

View File

@ -43,7 +43,7 @@ export function DomainResult({domain}: { domain: Domain }) {
<Tooltip <Tooltip
placement='bottomLeft' placement='bottomLeft'
title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}> title={s in rdapStatusCodeDetailTranslated ? rdapStatusCodeDetailTranslated[s as keyof typeof rdapStatusCodeDetailTranslated] : undefined}>
<Tag color={s === 'active' ? 'green' : 'blue'}>{s}</Tag> <Tag color={['active', 'ok'].includes(s) ? 'green' : 'blue'}>{s}</Tag>
</Tooltip> </Tooltip>
) )
} }

View File

@ -84,7 +84,8 @@
"symfony/zulip-notifier": "7.1.*", "symfony/zulip-notifier": "7.1.*",
"symfonycasts/verify-email-bundle": "*", "symfonycasts/verify-email-bundle": "*",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0" "twig/twig": "^2.12|^3.0",
"ext-http": "*"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

View File

@ -1,18 +0,0 @@
<?php
namespace App\Config\Connector;
use App\Entity\Domain;
use App\Entity\Tld;
use Symfony\Contracts\HttpClient\HttpClientInterface;
interface ConnectorInterface
{
public function __construct(array $authData, HttpClientInterface $client);
public function orderDomain(Domain $domain, bool $dryRun): void;
public static function verifyAuthData(array $authData, HttpClientInterface $client): array;
public function isSupported(Tld ...$tld): bool;
}

View File

@ -2,8 +2,8 @@
namespace App\Config; namespace App\Config;
use App\Config\Connector\GandiConnector; use App\Config\Provider\GandiProvider;
use App\Config\Connector\OvhConnector; use App\Config\Provider\OvhProvider;
enum ConnectorProvider: string enum ConnectorProvider: string
{ {
@ -13,8 +13,8 @@ enum ConnectorProvider: string
public function getConnectorProvider(): string public function getConnectorProvider(): string
{ {
return match ($this) { return match ($this) {
ConnectorProvider::OVH => OvhConnector::class, ConnectorProvider::OVH => OvhProvider::class,
ConnectorProvider::GANDI => GandiConnector::class ConnectorProvider::GANDI => GandiProvider::class
}; };
} }
} }

View File

@ -0,0 +1,52 @@
<?php
namespace App\Config\Provider;
use App\Entity\Domain;
use App\Entity\Tld;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
abstract class AbstractProvider
{
public function __construct(
protected array $authData,
protected HttpClientInterface $client,
protected CacheItemPoolInterface $cacheItemPool,
protected KernelInterface $kernel
) {
}
abstract public static function verifyAuthData(array $authData, HttpClientInterface $client): array;
abstract public function orderDomain(Domain $domain, bool $dryRun): void;
public function isSupported(Tld ...$tldList): bool
{
$item = $this->getCachedTldList();
if (!$item->isHit()) {
$supportedTldList = $this->getSupportedTldList();
$item
->set($supportedTldList)
->expiresAfter(new \DateInterval('P1M'));
$this->cacheItemPool->saveDeferred($item);
} else {
$supportedTldList = $item->get();
}
/** @var string $tldString */
foreach (array_unique(array_map(fn (Tld $tld) => $tld->getTld(), $tldList)) as $tldString) {
if (!in_array($tldString, $supportedTldList)) {
return false;
}
}
return true;
}
abstract protected function getCachedTldList(): CacheItemInterface;
abstract protected function getSupportedTldList(): array;
}

View File

@ -1,10 +1,10 @@
<?php <?php
namespace App\Config\Connector; namespace App\Config\Provider;
use App\Entity\Domain; use App\Entity\Domain;
use App\Entity\Tld;
use http\Exception\InvalidArgumentException; use http\Exception\InvalidArgumentException;
use Psr\Cache\CacheItemInterface;
use Symfony\Component\HttpClient\HttpOptions; use Symfony\Component\HttpClient\HttpOptions;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
@ -16,14 +16,10 @@ use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\HttpClientInterface;
readonly class GandiConnector implements ConnectorInterface class GandiProvider extends AbstractProvider
{ {
private const BASE_URL = 'https://api.gandi.net'; private const BASE_URL = 'https://api.gandi.net';
public function __construct(private array $authData, private HttpClientInterface $client)
{
}
/** /**
* Order a domain name with the Gandi API. * Order a domain name with the Gandi API.
* *
@ -142,7 +138,7 @@ readonly class GandiConnector implements ConnectorInterface
* @throws DecodingExceptionInterface * @throws DecodingExceptionInterface
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
*/ */
public function isSupported(Tld ...$tldList): bool protected function getSupportedTldList(): array
{ {
$authData = self::verifyAuthData($this->authData, $this->client); $authData = self::verifyAuthData($this->authData, $this->client);
@ -152,15 +148,14 @@ readonly class GandiConnector implements ConnectorInterface
->setBaseUri(self::BASE_URL) ->setBaseUri(self::BASE_URL)
->toArray())->toArray(); ->toArray())->toArray();
$supportedTldList = array_map(fn ($tld) => $tld['name'], $response); return array_map(fn ($tld) => $tld['name'], $response);
/** @var string $tldString */
foreach (array_unique(array_map(fn (Tld $tld) => $tld->getTld(), $tldList)) as $tldString) {
if (!in_array($tldString, $supportedTldList)) {
return false;
}
} }
return true; /**
* @throws \Psr\Cache\InvalidArgumentException
*/
protected function getCachedTldList(): CacheItemInterface
{
return $this->cacheItemPool->getItem('app.provider.ovh.supported-tld');
} }
} }

View File

@ -1,17 +1,18 @@
<?php <?php
namespace App\Config\Connector; namespace App\Config\Provider;
use App\Entity\Domain; use App\Entity\Domain;
use App\Entity\Tld;
use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\ClientException;
use Ovh\Api; use Ovh\Api;
use Ovh\Exceptions\InvalidParameterException; use Ovh\Exceptions\InvalidParameterException;
use Psr\Cache\CacheItemInterface;
use Psr\Cache\InvalidArgumentException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\HttpClientInterface;
readonly class OvhConnector implements ConnectorInterface class OvhProvider extends AbstractProvider
{ {
public const REQUIRED_ROUTES = [ public const REQUIRED_ROUTES = [
[ [
@ -40,10 +41,6 @@ readonly class OvhConnector implements ConnectorInterface
], ],
]; ];
public function __construct(private array $authData, private HttpClientInterface $client)
{
}
/** /**
* Order a domain name with the OVH API. * Order a domain name with the OVH API.
* *
@ -219,7 +216,7 @@ readonly class OvhConnector implements ConnectorInterface
* @throws \JsonException * @throws \JsonException
* @throws \Exception * @throws \Exception
*/ */
public function isSupported(Tld ...$tldList): bool protected function getSupportedTldList(): array
{ {
$authData = self::verifyAuthData($this->authData, $this->client); $authData = self::verifyAuthData($this->authData, $this->client);
@ -230,17 +227,16 @@ readonly class OvhConnector implements ConnectorInterface
$authData['consumerKey'] $authData['consumerKey']
); );
$supportedTldList = $conn->get('/domain/extensions', [ return $conn->get('/domain/extensions', [
'ovhSubsidiary' => $authData['ovhSubsidiary'], 'ovhSubsidiary' => $authData['ovhSubsidiary'],
]); ]);
/** @var string $tldString */
foreach (array_unique(array_map(fn (Tld $tld) => $tld->getTld(), $tldList)) as $tldString) {
if (!in_array($tldString, $supportedTldList)) {
return false;
}
} }
return true; /**
* @throws InvalidArgumentException
*/
protected function getCachedTldList(): CacheItemInterface
{
return $this->cacheItemPool->getItem('app.provider.ovh.supported-tld');
} }
} }

View File

@ -2,7 +2,7 @@
namespace App\Controller; namespace App\Controller;
use App\Config\Connector\ConnectorInterface; use App\Config\Provider\AbstractProvider;
use App\Entity\Connector; use App\Entity\Connector;
use App\Entity\User; use App\Entity\User;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
@ -70,7 +70,7 @@ class ConnectorController extends AbstractController
throw new \Exception('Provider not found'); throw new \Exception('Provider not found');
} }
/** @var ConnectorInterface $connectorProviderClass */ /** @var AbstractProvider $connectorProviderClass */
$connectorProviderClass = $provider->getConnectorProvider(); $connectorProviderClass = $provider->getConnectorProvider();
$authData = $connectorProviderClass::verifyAuthData($connector->getAuthData(), $client); $authData = $connectorProviderClass::verifyAuthData($connector->getAuthData(), $client);

View File

@ -2,7 +2,7 @@
namespace App\Controller; namespace App\Controller;
use App\Config\Connector\ConnectorInterface; use App\Config\Provider\AbstractProvider;
use App\Config\WebhookScheme; use App\Config\WebhookScheme;
use App\Entity\Connector; use App\Entity\Connector;
use App\Entity\Domain; use App\Entity\Domain;
@ -27,6 +27,7 @@ use Eluceo\iCal\Domain\ValueObject\Timestamp;
use Eluceo\iCal\Presentation\Component\Property; use Eluceo\iCal\Presentation\Component\Property;
use Eluceo\iCal\Presentation\Component\Property\Value\TextValue; use Eluceo\iCal\Presentation\Component\Property\Value\TextValue;
use Eluceo\iCal\Presentation\Factory\CalendarFactory; use Eluceo\iCal\Presentation\Factory\CalendarFactory;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Sabre\VObject\EofException; use Sabre\VObject\EofException;
use Sabre\VObject\InvalidDataException; use Sabre\VObject\InvalidDataException;
@ -37,6 +38,7 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Component\Notifier\Exception\InvalidArgumentException; use Symfony\Component\Notifier\Exception\InvalidArgumentException;
use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\Dsn;
@ -50,7 +52,7 @@ class WatchListController extends AbstractController
private readonly SerializerInterface $serializer, private readonly SerializerInterface $serializer,
private readonly EntityManagerInterface $em, private readonly EntityManagerInterface $em,
private readonly WatchListRepository $watchListRepository, private readonly WatchListRepository $watchListRepository,
private readonly LoggerInterface $logger, private readonly HttpClientInterface $httpClient private readonly LoggerInterface $logger, private readonly HttpClientInterface $httpClient, private readonly CacheItemPoolInterface $cacheItemPool, private readonly KernelInterface $kernel
) { ) {
} }
@ -198,8 +200,8 @@ class WatchListController extends AbstractController
} }
$connectorProviderClass = $connector->getProvider()->getConnectorProvider(); $connectorProviderClass = $connector->getProvider()->getConnectorProvider();
/** @var ConnectorInterface $connectorProvider */ /** @var AbstractProvider $connectorProvider */
$connectorProvider = new $connectorProviderClass($connector->getAuthData(), $this->httpClient); $connectorProvider = new $connectorProviderClass($connector->getAuthData(), $this->httpClient, $this->cacheItemPool, $this->kernel);
$tldList = []; $tldList = [];
/** @var Domain $domain */ /** @var Domain $domain */

View File

@ -2,7 +2,7 @@
namespace App\MessageHandler; namespace App\MessageHandler;
use App\Config\Connector\ConnectorInterface; use App\Config\Provider\AbstractProvider;
use App\Config\TriggerAction; use App\Config\TriggerAction;
use App\Config\WebhookScheme; use App\Config\WebhookScheme;
use App\Entity\Domain; use App\Entity\Domain;
@ -76,8 +76,8 @@ final readonly class ProcessDomainTriggerHandler
$connectorProviderClass = $provider->getConnectorProvider(); $connectorProviderClass = $provider->getConnectorProvider();
/** @var ConnectorInterface $connectorProvider */ /** @var AbstractProvider $connectorProvider */
$connectorProvider = new $connectorProviderClass($connector->getAuthData(), $this->client); $connectorProvider = new $connectorProviderClass($connector->getAuthData(), $this->client, $this->cacheItemPool, $this->kernel);
$connectorProvider->orderDomain($domain, $this->kernel->isDebug()); $connectorProvider->orderDomain($domain, $this->kernel->isDebug());