feat: ovh API implement

This commit is contained in:
Maël Gangloff
2024-07-29 15:28:05 +02:00
parent ffe063413f
commit c89e9a78b3
10 changed files with 207 additions and 111 deletions

View File

@@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240728210044 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->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');
}
}

View File

@@ -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');
}

View File

@@ -1,11 +1,13 @@
<?php
namespace App\Config;
namespace App\Config\Connector;
use App\Entity\Domain;
interface ConnectorInterface
{
public static function verifyAuthData(array $authData): array;
public function orderDomain(Domain $domain,
bool $acceptConditions,
bool $ownerLegalAge,

View File

@@ -1,17 +1,19 @@
<?php
namespace App\Entity;
namespace App\Config\Connector;
use App\Config\ConnectorInterface;
use App\Repository\OVHConnectorRepository;
use Doctrine\ORM\Mapping\Entity;
use App\Entity\Domain;
use Exception;
use Ovh\Api;
#[Entity(repositoryClass: OVHConnectorRepository::class)]
class OVHConnector extends Connector implements ConnectorInterface
readonly class OvhConnector implements ConnectorInterface
{
public function __construct(private array $authData)
{
}
/**
* Order a domain name with the OVH API
* @throws Exception
@@ -23,12 +25,12 @@ class OVHConnector extends Connector implements ConnectorInterface
bool $dryRyn = false
): void
{
if (!$domain->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
];
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace App\Controller;
use App\Config\Connector\OvhConnector;
use App\Config\ConnectorProvider;
use App\Entity\Connector;
use App\Entity\User;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Serializer\SerializerInterface;
class ConnectorController extends AbstractController
{
public function __construct(
private readonly SerializerInterface $serializer, private readonly EntityManagerInterface $em
)
{
}
#[Route(
path: '/api/connectors',
name: 'connector_get_all_mine',
defaults: [
'_api_resource_class' => 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;
}
}

View File

@@ -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;
}
}

View File

@@ -61,7 +61,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
/**
* @var Collection<int, Connector>
*/
#[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);
}
}

View File

@@ -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");
}
}
}

View File

@@ -1,21 +0,0 @@
<?php
namespace App\Repository;
use App\Entity\OVHConnector;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method OVHConnector|null find($id, $lockMode = null, $lockVersion = null)
* @method OVHConnector|null findOneBy(array $criteria, array $orderBy = null)
* @method OVHConnector[] findAll()
* @method OVHConnector[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class OVHConnectorRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, OVHConnector::class);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Service;
readonly class ConnectorService
{
}