From 735e8687270c2d58f26297b5da5015d6c8a83cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Sat, 14 Jun 2025 00:09:41 +0200 Subject: [PATCH] refactor: use state processor --- src/Controller/ConnectorController.php | 125 ----------------------- src/Entity/Connector.php | 10 +- src/Entity/WatchList.php | 1 - src/State/AutoRegisterDomainProvider.php | 12 +-- src/State/ConnectorCreateProcessor.php | 100 ++++++++++++++++++ src/State/ConnectorDeleteProcessor.php | 51 +++++++++ src/State/WatchListUpdateProcessor.php | 18 ++-- 7 files changed, 174 insertions(+), 143 deletions(-) create mode 100644 src/State/ConnectorCreateProcessor.php create mode 100644 src/State/ConnectorDeleteProcessor.php diff --git a/src/Controller/ConnectorController.php b/src/Controller/ConnectorController.php index faf2e9a..d72fe69 100644 --- a/src/Controller/ConnectorController.php +++ b/src/Controller/ConnectorController.php @@ -2,34 +2,14 @@ namespace App\Controller; -use App\Config\ConnectorProvider; use App\Entity\Connector; use App\Entity\User; -use App\Service\Connector\AbstractProvider; -use App\Service\Connector\EppClientProvider; use Doctrine\Common\Collections\Collection; -use Doctrine\ORM\EntityManagerInterface; -use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; -use Symfony\Component\DependencyInjection\Attribute\Autowire; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\Serializer\Exception\ExceptionInterface; class ConnectorController extends AbstractController { - public function __construct( - private readonly EntityManagerInterface $em, - private readonly LoggerInterface $logger, - #[Autowire(service: 'service_container')] - private readonly ContainerInterface $locator, - private readonly KernelInterface $kernel, - ) { - } - #[Route( path: '/api/connectors', name: 'connector_get_all_mine', @@ -46,109 +26,4 @@ class ConnectorController extends AbstractController return $user->getConnectors(); } - - /** - * @throws ExceptionInterface - * @throws \Throwable - */ - #[Route( - path: '/api/connectors', - name: 'connector_create', - defaults: [ - '_api_resource_class' => Connector::class, - '_api_operation_name' => 'create', - ], - methods: ['POST'] - )] - public function createConnector(Connector $connector): Connector - { - /** @var User $user */ - $user = $this->getUser(); - $connector->setUser($user); - - $provider = $connector->getProvider(); - - $this->logger->info('User {username} wants to register a connector from provider {provider}.', [ - 'username' => $user->getUserIdentifier(), - 'provider' => $provider->value, - ]); - - if (null === $provider) { - throw new BadRequestHttpException('Provider not found'); - } - $authData = $connector->getAuthData(); - - if (ConnectorProvider::EPP === $provider) { - $filesystem = new Filesystem(); - $directory = EppClientProvider::buildEppCertificateFolder($this->kernel->getProjectDir(), $connector->getId()); - unset($authData['file_certificate_pem'], $authData['file_certificate_key']); // Prevent alteration from user - - if (isset($authData['certificate_pem'], $authData['certificate_key'])) { - $pemPath = $directory.'client.pem'; - $keyPath = $directory.'client.key'; - - $filesystem->mkdir($directory, 0755); - $filesystem->dumpFile($pemPath, $authData['certificate_pem']); - $filesystem->dumpFile($keyPath, $authData['certificate_key']); - $connector->setAuthData([...$authData, 'file_certificate_pem' => $pemPath, 'file_certificate_key' => $keyPath]); - } - - /** @var AbstractProvider $providerClient */ - $providerClient = $this->locator->get($provider->getConnectorProvider()); - - try { - $connector->setAuthData($providerClient->authenticate($authData)); - } catch (\Throwable $exception) { - $filesystem->remove($directory); - throw $exception; - } - } else { - /** @var AbstractProvider $providerClient */ - $providerClient = $this->locator->get($provider->getConnectorProvider()); - $connector->setAuthData($providerClient->authenticate($authData)); - } - - $this->logger->info('User {username} authentication data with the {provider} provider has been validated.', [ - 'username' => $user->getUserIdentifier(), - 'provider' => $provider->value, - ]); - - $connector->setCreatedAt(new \DateTimeImmutable('now')); - $this->em->persist($connector); - $this->em->flush(); - - return $connector; - } - - /** - * @throws \Exception - */ - #[Route( - path: '/api/connectors/{id}', - name: 'connector_delete', - defaults: [ - '_api_resource_class' => Connector::class, - '_api_operation_name' => 'delete', - ], - methods: ['DELETE'] - )] - public function deleteConnector(Connector $connector): void - { - foreach ($connector->getWatchLists()->getIterator() as $watchlist) { - $watchlist->setConnector(null); - } - - $provider = $connector->getProvider(); - - if (null === $provider) { - throw new BadRequestHttpException('Provider not found'); - } - - if (ConnectorProvider::EPP === $provider) { - (new Filesystem())->remove(EppClientProvider::buildEppCertificateFolder($this->kernel->getProjectDir(), $connector->getId())); - } - - $this->em->remove($connector); - $this->em->flush(); - } } diff --git a/src/Entity/Connector.php b/src/Entity/Connector.php index 5b58cd7..8588947 100644 --- a/src/Entity/Connector.php +++ b/src/Entity/Connector.php @@ -9,6 +9,8 @@ use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\Post; use App\Config\ConnectorProvider; use App\Repository\ConnectorRepository; +use App\State\ConnectorCreateProcessor; +use App\State\ConnectorDeleteProcessor; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -28,15 +30,15 @@ use Symfony\Component\Uid\Uuid; security: 'object.user == user' ), new Post( - routeName: 'connector_create', normalizationContext: ['groups' => ['connector:create', 'connector:list']], denormalizationContext: ['groups' => 'connector:create'], - name: 'create' + name: 'create', + processor: ConnectorCreateProcessor::class ), new Delete( - routeName: 'connector_delete', security: 'object.user == user', - name: 'delete' + name: 'delete', + processor: ConnectorDeleteProcessor::class ), ] )] diff --git a/src/Entity/WatchList.php b/src/Entity/WatchList.php index 47b7c69..cc8aec1 100644 --- a/src/Entity/WatchList.php +++ b/src/Entity/WatchList.php @@ -95,7 +95,6 @@ use Symfony\Component\Uid\Uuid; security: 'object.user == user', name: 'update', processor: WatchListUpdateProcessor::class, - extraProperties: ['standard_put' => false], ), new Delete( security: 'object.user == user' diff --git a/src/State/AutoRegisterDomainProvider.php b/src/State/AutoRegisterDomainProvider.php index 10a02a1..107e466 100644 --- a/src/State/AutoRegisterDomainProvider.php +++ b/src/State/AutoRegisterDomainProvider.php @@ -15,16 +15,16 @@ use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\RateLimiter\RateLimiterFactory; -class AutoRegisterDomainProvider implements ProviderInterface +readonly class AutoRegisterDomainProvider implements ProviderInterface { public function __construct( #[Autowire(service: 'api_platform.doctrine.orm.state.item_provider')] private ProviderInterface $itemProvider, - private readonly RDAPService $RDAPService, - private readonly EntityManagerInterface $entityManager, - private readonly KernelInterface $kernel, - private readonly ParameterBagInterface $parameterBag, - private readonly RateLimiterFactory $rdapRequestsLimiter, private readonly Security $security, + private RDAPService $RDAPService, + private EntityManagerInterface $entityManager, + private KernelInterface $kernel, + private ParameterBagInterface $parameterBag, + private RateLimiterFactory $rdapRequestsLimiter, private Security $security, ) { } diff --git a/src/State/ConnectorCreateProcessor.php b/src/State/ConnectorCreateProcessor.php new file mode 100644 index 0000000..cc11363 --- /dev/null +++ b/src/State/ConnectorCreateProcessor.php @@ -0,0 +1,100 @@ +security->getUser(); + $data->setUser($user); + + $provider = $data->getProvider(); + + $this->logger->info('User {username} wants to register a connector from provider {provider}.', [ + 'username' => $user->getUserIdentifier(), + 'provider' => $provider->value, + ]); + + if (null === $provider) { + throw new BadRequestHttpException('Provider not found'); + } + $authData = $data->getAuthData(); + + if (ConnectorProvider::EPP === $provider) { + $filesystem = new Filesystem(); + $directory = EppClientProvider::buildEppCertificateFolder($this->kernel->getProjectDir(), $data->getId()); + unset($authData['file_certificate_pem'], $authData['file_certificate_key']); // Prevent alteration from user + + if (isset($authData['certificate_pem'], $authData['certificate_key'])) { + $pemPath = $directory.'client.pem'; + $keyPath = $directory.'client.key'; + + $filesystem->mkdir($directory, 0755); + $filesystem->dumpFile($pemPath, $authData['certificate_pem']); + $filesystem->dumpFile($keyPath, $authData['certificate_key']); + $data->setAuthData([...$authData, 'file_certificate_pem' => $pemPath, 'file_certificate_key' => $keyPath]); + } + + /** @var AbstractProvider $providerClient */ + $providerClient = $this->locator->get($provider->getConnectorProvider()); + + try { + $data->setAuthData($providerClient->authenticate($authData)); + } catch (\Throwable $exception) { + $filesystem->remove($directory); + throw $exception; + } + } else { + /** @var AbstractProvider $providerClient */ + $providerClient = $this->locator->get($provider->getConnectorProvider()); + $data->setAuthData($providerClient->authenticate($authData)); + } + + $this->logger->info('User {username} authentication data with the {provider} provider has been validated.', [ + 'username' => $user->getUserIdentifier(), + 'provider' => $provider->value, + ]); + + $data->setCreatedAt(new \DateTimeImmutable('now')); + $this->persistProcessor->process($data, $operation, $uriVariables, $context); + + return $data; + } +} diff --git a/src/State/ConnectorDeleteProcessor.php b/src/State/ConnectorDeleteProcessor.php new file mode 100644 index 0000000..9f2ff14 --- /dev/null +++ b/src/State/ConnectorDeleteProcessor.php @@ -0,0 +1,51 @@ +getWatchLists()->getIterator() as $watchlist) { + $watchlist->setConnector(null); + } + + $provider = $data->getProvider(); + + if (null === $provider) { + throw new BadRequestHttpException('Provider not found'); + } + + if (ConnectorProvider::EPP === $provider) { + (new Filesystem())->remove(EppClientProvider::buildEppCertificateFolder($this->kernel->getProjectDir(), $data->getId())); + } + + $this->removeProcessor->process($data, $operation, $uriVariables, $context); + + return $data; + } +} diff --git a/src/State/WatchListUpdateProcessor.php b/src/State/WatchListUpdateProcessor.php index 78c9f2c..470f60a 100644 --- a/src/State/WatchListUpdateProcessor.php +++ b/src/State/WatchListUpdateProcessor.php @@ -17,18 +17,19 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\Serializer\Exception\ExceptionInterface; -class WatchListUpdateProcessor implements ProcessorInterface +readonly class WatchListUpdateProcessor implements ProcessorInterface { public function __construct( - private readonly Security $security, - private readonly ParameterBagInterface $parameterBag, + private Security $security, + private ParameterBagInterface $parameterBag, #[Autowire(service: 'api_platform.doctrine.orm.state.persist_processor')] - private readonly ProcessorInterface $persistProcessor, - private readonly LoggerInterface $logger, - private readonly ChatNotificationService $chatNotificationService, + private ProcessorInterface $persistProcessor, + private LoggerInterface $logger, + private ChatNotificationService $chatNotificationService, #[Autowire(service: 'service_container')] - private readonly ContainerInterface $locator, + private ContainerInterface $locator, ) { } @@ -36,6 +37,9 @@ class WatchListUpdateProcessor implements ProcessorInterface * @param WatchList $data * * @return WatchList + * + * @throws ExceptionInterface + * @throws \Exception */ public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed {