From c4f79bece80dc349a15dca66c8c8854907b34235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gangloff?= Date: Mon, 15 Sep 2025 23:04:28 +0200 Subject: [PATCH] feat: add ICANN accreditation status on domain result page --- assets/components/search/EntitiesList.tsx | 28 ++++- .../infrastructure/IcannRegistrarPage.tsx | 16 +-- assets/utils/api/icann-accreditations.ts | 2 +- assets/utils/api/index.ts | 17 +-- assets/utils/functions/rdapTranslation.ts | 7 ++ migrations/Version20250915192826.php | 61 ++++++++++ migrations/Version20250915200844.php | 31 +++++ .../NotNullAccreditationIcannExtension.php | 28 ----- src/Entity/Entity.php | 46 +------ src/Entity/IcannAccreditation.php | 113 ++++++++++++++++-- .../IcannAccreditationRepository.php | 43 +++++++ src/Service/RDAPService.php | 99 +++++++-------- 12 files changed, 338 insertions(+), 153 deletions(-) create mode 100644 migrations/Version20250915192826.php create mode 100644 migrations/Version20250915200844.php delete mode 100644 src/Api/Extension/NotNullAccreditationIcannExtension.php create mode 100644 src/Repository/IcannAccreditationRepository.php diff --git a/assets/components/search/EntitiesList.tsx b/assets/components/search/EntitiesList.tsx index 8ea11f7..b660ced 100644 --- a/assets/components/search/EntitiesList.tsx +++ b/assets/components/search/EntitiesList.tsx @@ -1,11 +1,16 @@ -import {Flex, List, Tag, Tooltip, Typography} from 'antd' +import {Flex, List, Tag, Tooltip} from 'antd' import React from 'react' import type {Domain} from '../../utils/api' -import {rdapRoleDetailTranslation, rdapRoleTranslation} from '../../utils/functions/rdapTranslation' +import { + icannAccreditationTranslation, + rdapRoleDetailTranslation, + rdapRoleTranslation +} from '../../utils/functions/rdapTranslation' import {roleToAvatar} from '../../utils/functions/roleToAvatar' import {rolesToColor} from '../../utils/functions/rolesToColor' import {sortDomainEntities} from '../../utils/functions/sortDomainEntities' import {extractDetailsFromJCard} from '../../utils/functions/extractDetailsFromJCard' +import {CheckCircleOutlined, CloseCircleOutlined, SettingOutlined} from "@ant-design/icons" export function EntitiesList({domain}: { domain: Domain }) { const rdapRoleTranslated = rdapRoleTranslation() @@ -27,11 +32,28 @@ export function EntitiesList({domain}: { domain: Domain }) { dataSource={sortDomainEntities(domain)} renderItem={(e) => { const details = extractDetailsFromJCard(e) + const icannAccreditationTranslated = icannAccreditationTranslation() + + const status = e.entity.icannAccreditation?.status as ('Terminated' | 'Accredited' | 'Reserved' | undefined) return {e.entity.handle}} + title={ + {e.entity.handle} + { + e.entity.icannAccreditation && status && + : + status === 'Accredited' ? : + } color={ + status === 'Terminated' ? 'red' : + status === 'Accredited' ? 'green' : 'yellow' + }>{e.entity.icannAccreditation.id} + + } + } description={<> {details.fn &&
👤 {details.fn}
} {details.organization &&
🏢 {details.organization}
} diff --git a/assets/pages/infrastructure/IcannRegistrarPage.tsx b/assets/pages/infrastructure/IcannRegistrarPage.tsx index 53d4cbe..3164be6 100644 --- a/assets/pages/infrastructure/IcannRegistrarPage.tsx +++ b/assets/pages/infrastructure/IcannRegistrarPage.tsx @@ -9,12 +9,12 @@ import {getIcannAccreditations} from "../../utils/api/icann-accreditations" const {Text, Paragraph} = Typography interface FiltersType { - 'icannAccreditation.status': 'Accredited' | 'Reserved' | 'Terminated', + status: 'Accredited' | 'Reserved' | 'Terminated', } function RegistrarListTable(filters: FiltersType) { interface TableRow { - key: string + key: number handle: number name: string } @@ -26,9 +26,9 @@ function RegistrarListTable(filters: FiltersType) { getIcannAccreditations(params).then((data) => { setTotal(data['hydra:totalItems']) setDataTable(data['hydra:member'].map((accreditation: IcannAccreditation) => ({ - key: accreditation.handle, - handle: parseInt(accreditation.handle), - name: accreditation.icannAccreditation.registrarName + key: accreditation.id, + handle: accreditation.id, + name: accreditation.registrarName }) ).sort((a, b) => a.handle - b.handle)) }) @@ -76,17 +76,17 @@ export default function IcannRegistrarPage() { Accredited: <> {t`An accredited number means that ICANN's contract with the registrar is ongoing.`} - + , Reserved: <> {t`A reserved number can be used by TLD registries for specific operations.`} - + , Terminated: <> {t`A terminated number means that ICANN's contract with the registrar has been terminated.`} - + } diff --git a/assets/utils/api/icann-accreditations.ts b/assets/utils/api/icann-accreditations.ts index d47770e..e99fb60 100644 --- a/assets/utils/api/icann-accreditations.ts +++ b/assets/utils/api/icann-accreditations.ts @@ -8,7 +8,7 @@ interface IcannAccreditationList { export async function getIcannAccreditations(params: object): Promise { return (await request({ - url: 'entities/icann-accreditations', + url: 'icann-accreditations', params })).data } diff --git a/assets/utils/api/index.ts b/assets/utils/api/index.ts index 40c021e..4250a53 100644 --- a/assets/utils/api/index.ts +++ b/assets/utils/api/index.ts @@ -32,6 +32,11 @@ export interface Entity { string, string | string[], ]>] | [] + remarks?: { + type: string + description: string + }[] + icannAccreditation?: IcannAccreditation } export interface Nameserver { @@ -125,13 +130,11 @@ export interface TrackedDomains { } export interface IcannAccreditation { - handle: string - icannAccreditation: { - registrarName: string - status: string - date?: string - updated?: string - } + id: number + registrarName: string + status: string + date?: string + updated?: string } export async function request, D = object>(config: AxiosRequestConfig): Promise { diff --git a/assets/utils/functions/rdapTranslation.ts b/assets/utils/functions/rdapTranslation.ts index 77e7229..875eb98 100644 --- a/assets/utils/functions/rdapTranslation.ts +++ b/assets/utils/functions/rdapTranslation.ts @@ -113,3 +113,10 @@ export const rdapStatusCodeDetailTranslation = () => ({ administrative: t`The object instance has been allocated administratively (i.e., not for use by the recipient in their own right in operational networks).`, reserved: t`The object instance has been allocated to an IANA special-purpose address registry.` }) + + +export const icannAccreditationTranslation = () => ({ + Terminated: t`Terminated`, + Accredited: t`Accredited`, + Reserved: t`Reserved` +}) diff --git a/migrations/Version20250915192826.php b/migrations/Version20250915192826.php new file mode 100644 index 0000000..e9aeb57 --- /dev/null +++ b/migrations/Version20250915192826.php @@ -0,0 +1,61 @@ +addSql('CREATE SEQUENCE icann_accreditation_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + $this->addSql('CREATE TABLE icann_accreditation (id INT NOT NULL, registrar_name VARCHAR(255) DEFAULT NULL, rdap_base_url VARCHAR(255) DEFAULT NULL, status VARCHAR(255) DEFAULT NULL, updated DATE DEFAULT NULL, date DATE DEFAULT NULL, PRIMARY KEY(id))'); + $this->addSql('COMMENT ON COLUMN icann_accreditation.updated IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN icann_accreditation.date IS \'(DC2Type:date_immutable)\''); + $this->addSql('ALTER TABLE entity ADD icann_accreditation_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE entity DROP icann_registrar_name'); + $this->addSql('ALTER TABLE entity DROP icann_rdap_base_url'); + $this->addSql('ALTER TABLE entity DROP icann_status'); + $this->addSql('ALTER TABLE entity DROP icann_updated'); + $this->addSql('ALTER TABLE entity DROP icann_date'); + + $this->addSql('DELETE FROM domain_entity de USING entity e WHERE de.entity_uid = e.id AND e.tld_id IS NULL'); + $this->addSql('DELETE FROM entity_event ee USING entity e WHERE ee.entity_uid = e.id AND e.tld_id IS NULL'); + $this->addSql('DELETE FROM nameserver_entity ne USING entity e WHERE ne.entity_uid = e.id AND e.tld_id IS NULL'); + $this->addSql('DELETE FROM entity e WHERE e.tld_id IS NULL;'); + + $this->addSql('ALTER TABLE entity ALTER tld_id SET NOT NULL'); + $this->addSql('ALTER TABLE entity ADD CONSTRAINT FK_E284468D77C9FEB FOREIGN KEY (icann_accreditation_id) REFERENCES icann_accreditation (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); + $this->addSql('CREATE INDEX IDX_E284468D77C9FEB ON entity (icann_accreditation_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE entity DROP CONSTRAINT FK_E284468D77C9FEB'); + $this->addSql('DROP SEQUENCE icann_accreditation_id_seq CASCADE'); + $this->addSql('DROP TABLE icann_accreditation'); + $this->addSql('DROP INDEX IDX_E284468D77C9FEB'); + $this->addSql('ALTER TABLE entity ADD icann_registrar_name VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE entity ADD icann_rdap_base_url VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE entity ADD icann_status VARCHAR(255) DEFAULT NULL'); + $this->addSql('ALTER TABLE entity ADD icann_updated DATE DEFAULT NULL'); + $this->addSql('ALTER TABLE entity ADD icann_date DATE DEFAULT NULL'); + $this->addSql('ALTER TABLE entity DROP icann_accreditation_id'); + $this->addSql('ALTER TABLE entity ALTER tld_id DROP NOT NULL'); + $this->addSql('COMMENT ON COLUMN entity.icann_updated IS \'(DC2Type:date_immutable)\''); + $this->addSql('COMMENT ON COLUMN entity.icann_date IS \'(DC2Type:date_immutable)\''); + } +} diff --git a/migrations/Version20250915200844.php b/migrations/Version20250915200844.php new file mode 100644 index 0000000..d37ef73 --- /dev/null +++ b/migrations/Version20250915200844.php @@ -0,0 +1,31 @@ +addSql('DROP SEQUENCE icann_accreditation_id_seq CASCADE'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('CREATE SEQUENCE icann_accreditation_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); + } +} diff --git a/src/Api/Extension/NotNullAccreditationIcannExtension.php b/src/Api/Extension/NotNullAccreditationIcannExtension.php deleted file mode 100644 index ac6451d..0000000 --- a/src/Api/Extension/NotNullAccreditationIcannExtension.php +++ /dev/null @@ -1,28 +0,0 @@ -getName()) { - $rootAlias = $queryBuilder->getRootAliases()[0]; - $queryBuilder->andWhere(sprintf('%s.icannAccreditation.status IS NOT NULL', $rootAlias)); - } - } -} diff --git a/src/Entity/Entity.php b/src/Entity/Entity.php index 3902463..29fc3cc 100644 --- a/src/Entity/Entity.php +++ b/src/Entity/Entity.php @@ -2,15 +2,11 @@ namespace App\Entity; -use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; -use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Metadata\ApiResource; -use ApiPlatform\Metadata\GetCollection; use App\Repository\EntityRepository; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use Doctrine\ORM\Mapping\Embedded; use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\SerializedName; @@ -20,31 +16,6 @@ use Symfony\Component\Serializer\Attribute\SerializedName; )] #[ApiResource( operations: [ - new GetCollection( - uriTemplate: '/entities/icann-accreditations', - openapiContext: [ - 'parameters' => [ - [ - 'name' => 'icannAccreditation.status', - 'in' => 'query', - 'required' => true, - 'schema' => [ - 'type' => 'array', - 'items' => [ - 'type' => 'string', - 'enum' => ['Accredited', 'Terminated', 'Reserved'], - ], - ], - 'style' => 'form', - 'explode' => true, - 'description' => 'Filter by ICANN accreditation status', - ], - ], - ], - description: 'ICANN Registrar IDs list', - normalizationContext: ['groups' => ['entity:list']], - name: 'icann_accreditations_collection' - ), /* new GetCollection( uriTemplate: '/entities', @@ -67,12 +38,6 @@ use Symfony\Component\Serializer\Attribute\SerializedName; */ ] )] -#[ApiFilter( - SearchFilter::class, - properties: [ - 'icannAccreditation.status' => 'exact', - ] -)] class Entity { #[ORM\Id] @@ -81,7 +46,7 @@ class Entity private ?int $id = null; #[ORM\ManyToOne(targetEntity: Tld::class, inversedBy: 'entities')] - #[ORM\JoinColumn(referencedColumnName: 'tld', nullable: true)] + #[ORM\JoinColumn(referencedColumnName: 'tld', nullable: false)] #[Groups(['entity:list', 'entity:item', 'domain:item'])] private ?Tld $tld = null; @@ -120,7 +85,7 @@ class Entity #[Groups(['entity:item', 'domain:item'])] private ?array $remarks = null; - #[Embedded(class: IcannAccreditation::class, columnPrefix: 'icann_')] + #[ORM\ManyToOne(inversedBy: 'entities')] #[Groups(['entity:list', 'entity:item', 'domain:item'])] private ?IcannAccreditation $icannAccreditation = null; @@ -129,7 +94,6 @@ class Entity $this->domainEntities = new ArrayCollection(); $this->nameserverEntities = new ArrayCollection(); $this->events = new ArrayCollection(); - $this->icannAccreditation = new IcannAccreditation(); } public function getHandle(): ?string @@ -284,11 +248,13 @@ class Entity public function getIcannAccreditation(): ?IcannAccreditation { - return null === $this->icannAccreditation->getStatus() ? null : $this->icannAccreditation; + return $this->icannAccreditation; } - public function setIcannAccreditation(?IcannAccreditation $icannAccreditation): void + public function setIcannAccreditation(?IcannAccreditation $icannAccreditation): static { $this->icannAccreditation = $icannAccreditation; + + return $this; } } diff --git a/src/Entity/IcannAccreditation.php b/src/Entity/IcannAccreditation.php index 541d123..664730d 100644 --- a/src/Entity/IcannAccreditation.php +++ b/src/Entity/IcannAccreditation.php @@ -2,35 +2,92 @@ namespace App\Entity; +use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; +use ApiPlatform\Metadata\ApiFilter; +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\GetCollection; use App\Config\RegistrarStatus; +use App\Repository\IcannAccreditationRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; -use Doctrine\ORM\Mapping\Embeddable; use Symfony\Component\Serializer\Attribute\Groups; -#[Embeddable] +#[ApiResource( + operations: [ + new GetCollection( + uriTemplate: '/icann-accreditations', + openapiContext: [ + 'parameters' => [ + [ + 'name' => 'status', + 'in' => 'query', + 'required' => true, + 'schema' => [ + 'type' => 'array', + 'items' => [ + 'type' => 'string', + 'enum' => ['Accredited', 'Terminated', 'Reserved'], + ], + ], + 'style' => 'form', + 'explode' => true, + 'description' => 'Filter by ICANN accreditation status', + ], + ], + ], + shortName: 'ICANN Accreditation', + description: 'ICANN Registrar IDs list', + normalizationContext: ['groups' => ['icann:list']] + ), + ] +)] +#[ApiFilter( + SearchFilter::class, + properties: [ + 'status' => 'exact', + ] +)] +#[ORM\Entity(repositoryClass: IcannAccreditationRepository::class)] class IcannAccreditation { + #[ORM\Id] + #[ORM\Column] + #[Groups(['icann:item', 'icann:list', 'domain:item'])] + private ?int $id = null; + #[ORM\Column(length: 255, nullable: true)] - #[Groups(['entity:item', 'entity:list', 'domain:item'])] + #[Groups(['icann:item', 'icann:list', 'domain:item'])] private ?string $registrarName = null; #[ORM\Column(length: 255, nullable: true)] - #[Groups(['entity:item', 'domain:item'])] + #[Groups(['icann:item'])] private ?string $rdapBaseUrl = null; #[ORM\Column(nullable: true, enumType: RegistrarStatus::class)] - #[Groups(['entity:item', 'entity:list', 'domain:item'])] + #[Groups(['icann:item', 'icann:list', 'domain:item'])] private ?RegistrarStatus $status = null; #[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)] - #[Groups(['entity:item', 'entity:list', 'domain:item'])] + #[Groups(['icann:item', 'icann:list', 'domain:item'])] private ?\DateTimeImmutable $updated = null; #[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)] - #[Groups(['entity:item', 'entity:list', 'domain:item'])] + #[Groups(['icann:item', 'icann:list', 'domain:item'])] private ?\DateTimeImmutable $date = null; + /** + * @var Collection + */ + #[ORM\OneToMany(targetEntity: Entity::class, mappedBy: 'icannAccreditation')] + private Collection $entities; + + public function __construct() + { + $this->entities = new ArrayCollection(); + } + public function getRegistrarName(): ?string { return $this->registrarName; @@ -90,4 +147,46 @@ class IcannAccreditation return $this; } + + public function getId(): ?int + { + return $this->id; + } + + public function setId(?int $id): static + { + $this->id = $id; + + return $this; + } + + /** + * @return Collection + */ + public function getEntities(): Collection + { + return $this->entities; + } + + public function addEntity(Entity $entity): static + { + if (!$this->entities->contains($entity)) { + $this->entities->add($entity); + $entity->setIcannAccreditation($this); + } + + return $this; + } + + public function removeEntity(Entity $entity): static + { + if ($this->entities->removeElement($entity)) { + // set the owning side to null (unless already changed) + if ($entity->getIcannAccreditation() === $this) { + $entity->setIcannAccreditation(null); + } + } + + return $this; + } } diff --git a/src/Repository/IcannAccreditationRepository.php b/src/Repository/IcannAccreditationRepository.php new file mode 100644 index 0000000..e79561d --- /dev/null +++ b/src/Repository/IcannAccreditationRepository.php @@ -0,0 +1,43 @@ + + */ +class IcannAccreditationRepository extends ServiceEntityRepository +{ + public function __construct(ManagerRegistry $registry) + { + parent::__construct($registry, IcannAccreditation::class); + } + + // /** + // * @return Connector[] Returns an array of Connector objects + // */ + // public function findByExampleField($value): array + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->orderBy('c.id', 'ASC') + // ->setMaxResults(10) + // ->getQuery() + // ->getResult() + // ; + // } + + // public function findOneBySomeField($value): ?Connector + // { + // return $this->createQueryBuilder('c') + // ->andWhere('c.exampleField = :val') + // ->setParameter('val', $value) + // ->getQuery() + // ->getOneOrNullResult() + // ; + // } +} diff --git a/src/Service/RDAPService.php b/src/Service/RDAPService.php index 64446d5..8550863 100644 --- a/src/Service/RDAPService.php +++ b/src/Service/RDAPService.php @@ -14,6 +14,7 @@ use App\Entity\DomainEvent; use App\Entity\DomainStatus; use App\Entity\Entity; use App\Entity\EntityEvent; +use App\Entity\IcannAccreditation; use App\Entity\Nameserver; use App\Entity\NameserverEntity; use App\Entity\RdapServer; @@ -23,6 +24,7 @@ use App\Repository\DomainEventRepository; use App\Repository\DomainRepository; use App\Repository\EntityEventRepository; use App\Repository\EntityRepository; +use App\Repository\IcannAccreditationRepository; use App\Repository\NameserverEntityRepository; use App\Repository\NameserverRepository; use App\Repository\RdapServerRepository; @@ -105,6 +107,7 @@ class RDAPService private DomainEntityRepository $domainEntityRepository, private RdapServerRepository $rdapServerRepository, private TldRepository $tldRepository, + private IcannAccreditationRepository $icannAccreditationRepository, private EntityManagerInterface $em, private LoggerInterface $logger, private StatService $statService, @@ -344,7 +347,6 @@ class RDAPService } /** - * @throws \DateMalformedStringException * @throws \Exception */ private function updateDomainEvents(Domain $domain, array $rdapData): void @@ -380,7 +382,6 @@ class RDAPService } /** - * @throws \DateMalformedStringException * @throws \Exception */ private function updateDomainEntities(Domain $domain, array $rdapData): void @@ -418,7 +419,7 @@ class RDAPService } /** - * @throws \DateMalformedStringException + * @throws \Exception */ private function updateDomainNameservers(Domain $domain, array $rdapData): void { @@ -461,7 +462,7 @@ class RDAPService } /** - * @throws \DateMalformedStringException + * @throws \Exception */ private function updateNameserverEntities(Nameserver $nameserver, array $rdapNameserver, Tld $tld): void { @@ -517,36 +518,10 @@ class RDAPService } /** - * @throws \DateMalformedStringException * @throws \Exception */ private function registerEntity(array $rdapEntity, array $roles, string $domain, Tld $tld): Entity { - $entity = null; - - /** - * If the RDAP server transmits the entity's IANA number, it is used as a priority to identify the entity. - * - * @see https://datatracker.ietf.org/doc/html/rfc7483#section-4.8 - */ - $isIANAid = false; - if (isset($rdapEntity['publicIds'])) { - foreach ($rdapEntity['publicIds'] as $publicId) { - if ('IANA Registrar ID' === $publicId['type'] && isset($publicId['identifier']) && '' !== $publicId['identifier']) { - $entity = $this->entityRepository->findOneBy([ - 'handle' => $publicId['identifier'], - 'tld' => null, - ]); - - if (null !== $entity) { - $rdapEntity['handle'] = $publicId['identifier']; - $isIANAid = true; - break; - } - } - } - } - /* * If there is no number to identify the entity, one is generated from the domain name and the roles associated with this entity */ @@ -559,16 +534,10 @@ class RDAPService ]); } - if (null === $entity) { - $entity = $this->entityRepository->findOneBy([ - 'handle' => $rdapEntity['handle'], - 'tld' => $tld, - ]); - } - - if ($isIANAid && null !== $entity) { - return $entity; - } + $entity = $this->entityRepository->findOneBy([ + 'handle' => $rdapEntity['handle'], + 'tld' => $tld, + ]); if (null === $entity) { $entity = (new Entity())->setTld($tld); @@ -578,7 +547,23 @@ class RDAPService ]); } - $entity->setHandle($rdapEntity['handle']); + /** + * If the RDAP server transmits the entity's IANA number, it is used as a priority to identify the entity. + * + * @see https://datatracker.ietf.org/doc/html/rfc7483#section-4.8 + */ + $icannAccreditation = null; + if (isset($rdapEntity['publicIds'])) { + foreach ($rdapEntity['publicIds'] as $publicId) { + if ('IANA Registrar ID' === $publicId['type'] && isset($publicId['identifier']) && '' !== $publicId['identifier']) { + $icannAccreditation = $this->icannAccreditationRepository->findOneBy([ + 'id' => (int) $publicId['identifier'], + ]); + } + } + } + + $entity->setHandle($rdapEntity['handle'])->setIcannAccreditation($icannAccreditation); if (isset($rdapEntity['remarks']) && is_array($rdapEntity['remarks'])) { $entity->setRemarks($rdapEntity['remarks']); @@ -719,7 +704,7 @@ class RDAPService * @throws RedirectionExceptionInterface * @throws DecodingExceptionInterface * @throws ClientExceptionInterface - * @throws ORMException + * @throws \Exception */ public function updateRDAPServersFromIANA(): void { @@ -733,7 +718,6 @@ class RDAPService } /** - * @throws ORMException * @throws \Exception */ private function updateRDAPServers(array $dnsRoot): void @@ -772,6 +756,7 @@ class RDAPService /** * @throws ORMException + * @throws \Exception */ public function updateRDAPServersFromFile(string $fileName): void { @@ -836,7 +821,6 @@ class RDAPService * @throws TransportExceptionInterface * @throws ServerExceptionInterface * @throws RedirectionExceptionInterface - * @throws DecodingExceptionInterface * @throws ClientExceptionInterface * @throws \Exception */ @@ -850,23 +834,20 @@ class RDAPService $data = new \SimpleXMLElement($registrarList->getContent()); foreach ($data->registry->record as $registrar) { - $entity = $this->entityRepository->findOneBy(['handle' => $registrar->value, 'tld' => null]); - if (null === $entity) { - $entity = new Entity(); + $icannAcreditation = $this->icannAccreditationRepository->findOneBy(['id' => (int) $registrar->value]); + if (null === $icannAcreditation) { + $icannAcreditation = new IcannAccreditation(); } - $entity - ->setHandle($registrar->value) - ->setTld(null) - ->setJCard(['vcard', [['version', [], 'text', '4.0'], ['fn', [], 'text', (string) $registrar->name]]]) - ->setRemarks(null) - ->getIcannAccreditation() - ->setRegistrarName($registrar->name) - ->setStatus(RegistrarStatus::from($registrar->status)) - ->setRdapBaseUrl($registrar->rdapurl->count() ? ($registrar->rdapurl->server) : null) - ->setUpdated(null !== $registrar->attributes()->updated ? new \DateTimeImmutable($registrar->attributes()->updated) : null) - ->setDate(null !== $registrar->attributes()->date ? new \DateTimeImmutable($registrar->attributes()->date) : null); - $this->em->persist($entity); + $icannAcreditation + ->setId((int) $registrar->value) + ->setRegistrarName($registrar->name) + ->setStatus(RegistrarStatus::from($registrar->status)) + ->setRdapBaseUrl($registrar->rdapurl->count() ? ($registrar->rdapurl->server) : null) + ->setUpdated(null !== $registrar->attributes()->updated ? new \DateTimeImmutable($registrar->attributes()->updated) : null) + ->setDate(null !== $registrar->attributes()->date ? new \DateTimeImmutable($registrar->attributes()->date) : null); + + $this->em->persist($icannAcreditation); } $this->em->flush(); }