diff --git a/migrations/Version20240728210044.php b/migrations/Version20240728210044.php deleted file mode 100644 index 2163e0e..0000000 --- a/migrations/Version20240728210044.php +++ /dev/null @@ -1,37 +0,0 @@ -addSql('CREATE SEQUENCE connector_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); - $this->addSql('CREATE TABLE connector (id INT NOT NULL, user_id INT NOT NULL, auth_data JSON NOT NULL, provider VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); - $this->addSql('CREATE INDEX IDX_148C456EA76ED395 ON connector (user_id)'); - $this->addSql('ALTER TABLE connector ADD CONSTRAINT FK_148C456EA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('CREATE SCHEMA public'); - $this->addSql('DROP SEQUENCE connector_id_seq CASCADE'); - $this->addSql('ALTER TABLE connector DROP CONSTRAINT FK_148C456EA76ED395'); - $this->addSql('DROP TABLE connector'); - } -} diff --git a/migrations/Version20240729093649.php b/migrations/Version20240729131244.php similarity index 59% rename from migrations/Version20240729093649.php rename to migrations/Version20240729131244.php index 2802517..27295c2 100644 --- a/migrations/Version20240729093649.php +++ b/migrations/Version20240729131244.php @@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20240729093649 extends AbstractMigration +final class Version20240729131244 extends AbstractMigration { public function getDescription(): string { @@ -20,7 +20,12 @@ final class Version20240729093649 extends AbstractMigration public function up(Schema $schema): void { // this up() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE watch_list_trigger ADD connector_id INT DEFAULT NULL'); + $this->addSql('CREATE TABLE connector (id UUID NOT NULL, user_id INT NOT NULL, auth_data JSON NOT NULL, provider VARCHAR(255) NOT NULL, PRIMARY KEY(id))'); + $this->addSql('CREATE INDEX IDX_148C456EA76ED395 ON connector (user_id)'); + $this->addSql('COMMENT ON COLUMN connector.id IS \'(DC2Type:uuid)\''); + $this->addSql('ALTER TABLE connector ADD CONSTRAINT FK_148C456EA76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('ALTER TABLE watch_list_trigger ADD connector_id UUID DEFAULT NULL'); + $this->addSql('COMMENT ON COLUMN watch_list_trigger.connector_id IS \'(DC2Type:uuid)\''); $this->addSql('ALTER TABLE watch_list_trigger ADD CONSTRAINT FK_CF857A4C4D085745 FOREIGN KEY (connector_id) REFERENCES connector (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); $this->addSql('CREATE INDEX IDX_CF857A4C4D085745 ON watch_list_trigger (connector_id)'); } @@ -30,6 +35,8 @@ final class Version20240729093649 extends AbstractMigration // this down() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SCHEMA public'); $this->addSql('ALTER TABLE watch_list_trigger DROP CONSTRAINT FK_CF857A4C4D085745'); + $this->addSql('ALTER TABLE connector DROP CONSTRAINT FK_148C456EA76ED395'); + $this->addSql('DROP TABLE connector'); $this->addSql('DROP INDEX IDX_CF857A4C4D085745'); $this->addSql('ALTER TABLE watch_list_trigger DROP connector_id'); } diff --git a/src/Config/ConnectorInterface.php b/src/Config/Connector/ConnectorInterface.php similarity index 77% rename from src/Config/ConnectorInterface.php rename to src/Config/Connector/ConnectorInterface.php index 51f96aa..5bdc244 100644 --- a/src/Config/ConnectorInterface.php +++ b/src/Config/Connector/ConnectorInterface.php @@ -1,11 +1,13 @@ getDeleted()) throw new Exception('The domain name still appears in the WHOIS database.'); + if (!$domain->getDeleted()) throw new Exception('The domain name still appears in the WHOIS database'); $ldhName = $domain->getLdhName(); - if (!$ldhName) throw new Exception("Domain name cannot be null."); + if (!$ldhName) throw new Exception("Domain name cannot be null"); - $authData = $this->getAuthData(); + $authData = self::verifyAuthData($this->authData); $appKey = $authData['appKey']; $appSecret = $authData['appSecret']; @@ -37,14 +39,6 @@ class OVHConnector extends Connector implements ConnectorInterface $ovhSubsidiary = $authData['ovhSubsidiary']; $pricingMode = $authData['pricingMode']; - if (!$appKey || - !$appSecret || - !$apiEndpoint || - !$consumerKey || - !$ovhSubsidiary || - !$pricingMode - ) throw new Exception("Auth data cannot be null."); - $conn = new Api( $appKey, $appSecret, @@ -65,7 +59,7 @@ class OVHConnector extends Connector implements ConnectorInterface $offer['orderable'] === true && $offers['pricingMode'] === $pricingMode ); - if (empty($offer)) throw new Exception('Cannot buy this domain name.'); + if (empty($offer)) throw new Exception('Cannot buy this domain name'); $item = $conn->post("/order/cart/{$cartId}/domain", [ "domain" => $ldhName, @@ -98,4 +92,34 @@ class OVHConnector extends Connector implements ConnectorInterface "waiveRetractationPeriod" => $waiveRetractationPeriod ]); } + + /** + * @throws Exception + */ + public static function verifyAuthData(array $authData): array + { + $appKey = $authData['appKey']; + $appSecret = $authData['appSecret']; + $apiEndpoint = $authData['apiEndpoint']; + $consumerKey = $authData['consumerKey']; + $ovhSubsidiary = $authData['ovhSubsidiary']; + $pricingMode = $authData['pricingMode']; + + if (!is_string($appKey) || empty($appKey) || + !is_string($appSecret) || empty($appSecret) || + !is_string($consumerKey) || empty($consumerKey) || + !is_string($apiEndpoint) || empty($apiEndpoint) || + !is_string($ovhSubsidiary) || empty($ovhSubsidiary) || + !is_string($pricingMode) || empty($pricingMode) + ) throw new Exception("Bad data schema."); + + return [ + "appKey" => $appKey, + "appSecret" => $appSecret, + "apiEndpoint" => $apiEndpoint, + "consumerKey" => $consumerKey, + "ovhSubsidiary" => $ovhSubsidiary, + "pricingMode" => $pricingMode + ]; + } } \ No newline at end of file diff --git a/src/Controller/ConnectorController.php b/src/Controller/ConnectorController.php new file mode 100644 index 0000000..0a94c45 --- /dev/null +++ b/src/Controller/ConnectorController.php @@ -0,0 +1,68 @@ + Connector::class, + '_api_operation_name' => 'get_all_mine', + ], + methods: ['GET'] + )] + public function getConnector(): Collection + { + /** @var User $user */ + $user = $this->getUser(); + return $user->getConnectors(); + } + + /** + * @throws Exception + */ + #[Route( + path: '/api/connectors', + name: 'connector_create', + defaults: [ + '_api_resource_class' => Connector::class, + '_api_operation_name' => 'create', + ], + methods: ['POST'] + )] + public function createConnector(Request $request): Connector + { + $connector = $this->serializer->deserialize($request->getContent(), Connector::class, 'json', ['groups' => 'connector:create']); + $connector->setUser($this->getUser()); + + if ($connector->getProvider() === ConnectorProvider::OVH) { + $connector->setAuthData(OvhConnector::verifyAuthData($connector->getAuthData())); + } else throw new Exception('Unknown provider'); + + $this->em->persist($connector); + $this->em->flush(); + + return $connector; + } + +} \ No newline at end of file diff --git a/src/Entity/Connector.php b/src/Entity/Connector.php index aee9571..452c28b 100644 --- a/src/Entity/Connector.php +++ b/src/Entity/Connector.php @@ -2,32 +2,61 @@ namespace App\Entity; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\Delete; +use ApiPlatform\Metadata\Get; +use ApiPlatform\Metadata\GetCollection; +use ApiPlatform\Metadata\Patch; +use ApiPlatform\Metadata\Post; use App\Config\ConnectorProvider; use App\Repository\ConnectorRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use Doctrine\ORM\Mapping\DiscriminatorColumn; -use Doctrine\ORM\Mapping\DiscriminatorMap; -use Doctrine\ORM\Mapping\InheritanceType; +use Symfony\Component\Serializer\Attribute\Groups; +use Symfony\Component\Uid\Uuid; +#[ApiResource( + shortName: 'Connector', + operations: [ + new GetCollection( + routeName: 'connector_get_all_mine', + normalizationContext: ['groups' => 'connector:list'], + name: 'get_all_mine', + ), + new Get( + normalizationContext: ['groups' => 'connector:list'] + ), + new Post( + routeName: 'connector_create', normalizationContext: ['groups' => 'connector:create'], + denormalizationContext: ['groups' => 'connector:create'], + name: 'create' + ), + new Patch( + normalizationContext: ['groups' => 'connector:list'], + denormalizationContext: ['groups' => 'connector:create'] + ), + new Delete() + ] +)] #[ORM\Entity(repositoryClass: ConnectorRepository::class)] -#[InheritanceType('SINGLE_TABLE')] -#[DiscriminatorColumn(name: 'provider', enumType: ConnectorProvider::class)] -#[DiscriminatorMap([ConnectorProvider::OVH->value => OVHConnector::class])] class Connector { #[ORM\Id] - #[ORM\GeneratedValue] - #[ORM\Column] - private ?int $id = null; - - private ?string $provider = null; + #[ORM\Column(type: 'uuid')] + #[Groups(['connector:list'])] + private ?string $id; #[ORM\ManyToOne(inversedBy: 'connectors')] #[ORM\JoinColumn(nullable: false)] private ?User $user = null; + + #[Groups(['connector:list', 'connector:create'])] + #[ORM\Column(enumType: ConnectorProvider::class)] + private ?ConnectorProvider $provider = null; + + #[Groups(['connector:create'])] #[ORM\Column] private array $authData = []; @@ -37,28 +66,18 @@ class Connector #[ORM\OneToMany(targetEntity: WatchListTrigger::class, mappedBy: 'connector')] private Collection $watchListTriggers; + public function __construct() { + $this->id = Uuid::v4(); $this->watchListTriggers = new ArrayCollection(); } - public function getId(): ?int + public function getId(): ?string { return $this->id; } - public function getProvider(): ?string - { - return $this->provider; - } - - public function setProvider(?string $provider): static - { - $this->provider = $provider; - - return $this; - } - public function getUser(): ?User { return $this->user; @@ -113,4 +132,16 @@ class Connector return $this; } + public function getProvider(): ?ConnectorProvider + { + return $this->provider; + } + + public function setProvider(ConnectorProvider $provider): static + { + $this->provider = $provider; + + return $this; + } + } diff --git a/src/Entity/User.php b/src/Entity/User.php index 79a3710..571489c 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -61,7 +61,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface /** * @var Collection */ - #[ORM\OneToMany(targetEntity: Connector::class, mappedBy: 'userr', orphanRemoval: true)] + #[ORM\OneToMany(targetEntity: Connector::class, mappedBy: 'user', orphanRemoval: true)] private Collection $connectors; public function __construct() @@ -188,7 +188,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface { if (!$this->connectors->contains($connector)) { $this->connectors->add($connector); - $connector->setUserr($this); + $connector->setUser($this); } return $this; @@ -198,8 +198,8 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface { if ($this->connectors->removeElement($connector)) { // set the owning side to null (unless already changed) - if ($connector->getUserr() === $this) { - $connector->setUserr(null); + if ($connector->getUser() === $this) { + $connector->setUser(null); } } diff --git a/src/MessageHandler/ProcessDomainTriggerHandler.php b/src/MessageHandler/ProcessDomainTriggerHandler.php index 93b8477..1d749c5 100644 --- a/src/MessageHandler/ProcessDomainTriggerHandler.php +++ b/src/MessageHandler/ProcessDomainTriggerHandler.php @@ -2,10 +2,11 @@ namespace App\MessageHandler; +use App\Config\Connector\OvhConnector; +use App\Config\ConnectorProvider; use App\Config\TriggerAction; use App\Entity\Domain; use App\Entity\DomainEvent; -use App\Entity\OVHConnector; use App\Entity\User; use App\Entity\WatchList; use App\Entity\WatchListTrigger; @@ -14,6 +15,7 @@ use App\Repository\DomainRepository; use App\Repository\WatchListRepository; use Exception; use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\HttpKernel\KernelInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Messenger\Attribute\AsMessageHandler; @@ -27,6 +29,7 @@ final readonly class ProcessDomainTriggerHandler private MailerInterface $mailer, private WatchListRepository $watchListRepository, private DomainRepository $domainRepository, + private KernelInterface $kernel ) { @@ -58,9 +61,18 @@ final readonly class ProcessDomainTriggerHandler case TriggerAction::BuyDomain : if ($watchListTrigger->getConnector() === null) throw new Exception('Connector is missing'); $connector = $watchListTrigger->getConnector(); - if ($connector::class === OVHConnector::class) { - $connector->orderDomain($domain, true, true, true, true); - } + if ($connector->getProvider() === ConnectorProvider::OVH) { + $ovh = new OVHConnector($connector->getAuthData()); + $isDebug = $this->kernel->isDebug(); + $ovh->orderDomain( + $domain, + true, + true, + true, + $isDebug + ); + + } else throw new Exception("Unknown provider"); } } } diff --git a/src/Repository/OVHConnectorRepository.php b/src/Repository/OVHConnectorRepository.php deleted file mode 100644 index a3aa611..0000000 --- a/src/Repository/OVHConnectorRepository.php +++ /dev/null @@ -1,21 +0,0 @@ -