mirror of
https://github.com/maelgangloff/domain-watchdog.git
synced 2025-12-29 16:15:04 +00:00
refactor: move logic in RDAPService
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Entity\User;
|
|||||||
use App\Entity\WatchList;
|
use App\Entity\WatchList;
|
||||||
use App\Repository\DomainEventRepository;
|
use App\Repository\DomainEventRepository;
|
||||||
use App\Repository\WatchListRepository;
|
use App\Repository\WatchListRepository;
|
||||||
|
use App\Service\RDAPService;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Eluceo\iCal\Domain\Entity\Calendar;
|
use Eluceo\iCal\Domain\Entity\Calendar;
|
||||||
use Eluceo\iCal\Presentation\Component\Property;
|
use Eluceo\iCal\Presentation\Component\Property;
|
||||||
@@ -29,6 +30,7 @@ class WatchListController extends AbstractController
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly WatchListRepository $watchListRepository,
|
private readonly WatchListRepository $watchListRepository,
|
||||||
private readonly DomainEventRepository $domainEventRepository,
|
private readonly DomainEventRepository $domainEventRepository,
|
||||||
|
private readonly RDAPService $RDAPService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,9 +112,10 @@ class WatchListController extends AbstractController
|
|||||||
/** @var Domain $domain */
|
/** @var Domain $domain */
|
||||||
foreach ($watchList->getDomains()->getIterator() as $domain) {
|
foreach ($watchList->getDomains()->getIterator() as $domain) {
|
||||||
/** @var DomainEvent|null $exp */
|
/** @var DomainEvent|null $exp */
|
||||||
$exp = $this->domainEventRepository->findLastExpirationDomainEvent($domain);
|
$exp = $this->domainEventRepository->findLastDomainEvent($domain, 'expiration');
|
||||||
|
|
||||||
if (!$domain->getDeleted() && null !== $exp && !in_array($domain, $domains)) {
|
if (!$domain->getDeleted() && null !== $exp && !in_array($domain, $domains)) {
|
||||||
|
$domain->setExpiresInDays($this->RDAPService->getExpiresInDays($domain));
|
||||||
$domains[] = $domain;
|
$domains[] = $domain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ class Domain
|
|||||||
#[Groups(['domain:item'])]
|
#[Groups(['domain:item'])]
|
||||||
private Collection $dnsKey;
|
private Collection $dnsKey;
|
||||||
|
|
||||||
|
private ?int $expiresInDays;
|
||||||
|
|
||||||
private const IMPORTANT_EVENTS = [EventAction::Deletion->value, EventAction::Expiration->value];
|
private const IMPORTANT_EVENTS = [EventAction::Deletion->value, EventAction::Expiration->value];
|
||||||
private const IMPORTANT_STATUS = [
|
private const IMPORTANT_STATUS = [
|
||||||
'redemption period',
|
'redemption period',
|
||||||
@@ -507,122 +509,6 @@ class Domain
|
|||||||
return in_array('pending delete', $this->getStatus()) && !in_array('redemption period', $this->getStatus());
|
return in_array('pending delete', $this->getStatus()) && !in_array('redemption period', $this->getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \DateMalformedIntervalStringException
|
|
||||||
*/
|
|
||||||
private function calculateDaysFromStatus(\DateTimeImmutable $now): ?int
|
|
||||||
{
|
|
||||||
$lastStatus = $this->getDomainStatuses()->first();
|
|
||||||
if (false === $lastStatus) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isPendingDelete() && (
|
|
||||||
in_array('pending delete', $lastStatus->getAddStatus())
|
|
||||||
|| in_array('redemption period', $lastStatus->getDeleteStatus()))
|
|
||||||
) {
|
|
||||||
return self::daysBetween($now, $lastStatus->getCreatedAt()->add(new \DateInterval('P'. 5 .'D')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isRedemptionPeriod()
|
|
||||||
&& in_array('redemption period', $lastStatus->getAddStatus())
|
|
||||||
) {
|
|
||||||
return self::daysBetween($now, $lastStatus->getCreatedAt()->add(new \DateInterval('P'.(30 + 5).'D')));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
private function calculateDaysFromEvents(\DateTimeImmutable $now): ?int
|
|
||||||
{
|
|
||||||
$lastChangedEvent = $this->getEvents()->findFirst(fn (int $i, DomainEvent $e) => !$e->getDeleted() && EventAction::LastChanged->value === $e->getAction());
|
|
||||||
if (null === $lastChangedEvent) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->isRedemptionPeriod()) {
|
|
||||||
return self::daysBetween($now, $lastChangedEvent->getDate()->add(new \DateInterval('P'.(30 + 5).'D')));
|
|
||||||
}
|
|
||||||
if ($this->isPendingDelete()) {
|
|
||||||
return self::daysBetween($now, $lastChangedEvent->getDate()->add(new \DateInterval('P'. 5 .'D')));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static function daysBetween(\DateTimeImmutable $start, \DateTimeImmutable $end): int
|
|
||||||
{
|
|
||||||
$interval = $start->setTime(0, 0)->diff($end->setTime(0, 0));
|
|
||||||
|
|
||||||
return $interval->invert ? -$interval->days : $interval->days;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static function returnExpiresIn(array $guesses): ?int
|
|
||||||
{
|
|
||||||
$filteredGuesses = array_filter($guesses, function ($value) {
|
|
||||||
return null !== $value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (empty($filteredGuesses)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return max(min($filteredGuesses), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
private function getRelevantDates(): array
|
|
||||||
{
|
|
||||||
$expiredAt = $deletedAt = null;
|
|
||||||
foreach ($this->getEvents()->getIterator() as $event) {
|
|
||||||
if (!$event->getDeleted()) {
|
|
||||||
if ('expiration' === $event->getAction()) {
|
|
||||||
$expiredAt = $event->getDate();
|
|
||||||
} elseif ('deletion' === $event->getAction()) {
|
|
||||||
$deletedAt = $event->getDate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [$expiredAt, $deletedAt];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws \Exception
|
|
||||||
*/
|
|
||||||
#[Groups(['domain:item', 'domain:list'])]
|
|
||||||
public function getExpiresInDays(): ?int
|
|
||||||
{
|
|
||||||
if ($this->getDeleted()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$now = new \DateTimeImmutable();
|
|
||||||
[$expiredAt, $deletedAt] = $this->getRelevantDates();
|
|
||||||
|
|
||||||
if ($expiredAt) {
|
|
||||||
$guess = self::daysBetween($now, $expiredAt->add(new \DateInterval('P'.(45 + 30 + 5).'D')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($deletedAt) {
|
|
||||||
// It has been observed that AFNIC, on the last day, adds a "deleted" event and removes the redemption period status.
|
|
||||||
if (0 === self::daysBetween($now, $deletedAt) && $this->isPendingDelete()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$guess = self::daysBetween($now, $deletedAt->add(new \DateInterval('P'. 30 .'D')));
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::returnExpiresIn([
|
|
||||||
$guess ?? null,
|
|
||||||
$this->calculateDaysFromStatus($now),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Collection<int, DnsKey>
|
* @return Collection<int, DnsKey>
|
||||||
*/
|
*/
|
||||||
@@ -718,4 +604,17 @@ class Domain
|
|||||||
|
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Groups(['domain:item', 'domain:list'])]
|
||||||
|
public function getExpiresInDays(): ?int
|
||||||
|
{
|
||||||
|
return $this->expiresInDays;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setExpiresInDays(?int $expiresInDays): static
|
||||||
|
{
|
||||||
|
$this->expiresInDays = $expiresInDays;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,17 +17,18 @@ class DomainEventRepository extends ServiceEntityRepository
|
|||||||
parent::__construct($registry, DomainEvent::class);
|
parent::__construct($registry, DomainEvent::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findLastExpirationDomainEvent(Domain $domain)
|
public function findLastDomainEvent(Domain $domain, string $action)
|
||||||
{
|
{
|
||||||
return $this->createQueryBuilder('de')
|
return $this->createQueryBuilder('de')
|
||||||
->select()
|
->select()
|
||||||
->where('de.domain = :domain')
|
->where('de.domain = :domain')
|
||||||
->andWhere('de.action = \'expiration\'')
|
->andWhere('de.action = :action')
|
||||||
->andWhere('de.deleted = FALSE')
|
->andWhere('de.deleted = FALSE')
|
||||||
->orderBy('de.date', 'DESC')
|
->orderBy('de.date', 'DESC')
|
||||||
->setMaxResults(1)
|
->setMaxResults(1)
|
||||||
->getQuery()
|
->getQuery()
|
||||||
->setParameter('domain', $domain)
|
->setParameter('domain', $domain)
|
||||||
|
->setParameter('action', $action)
|
||||||
->getOneOrNullResult();
|
->getOneOrNullResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use App\Exception\UnknownRdapServerException;
|
|||||||
use App\Repository\DomainEntityRepository;
|
use App\Repository\DomainEntityRepository;
|
||||||
use App\Repository\DomainEventRepository;
|
use App\Repository\DomainEventRepository;
|
||||||
use App\Repository\DomainRepository;
|
use App\Repository\DomainRepository;
|
||||||
|
use App\Repository\DomainStatusRepository;
|
||||||
use App\Repository\EntityEventRepository;
|
use App\Repository\EntityEventRepository;
|
||||||
use App\Repository\EntityRepository;
|
use App\Repository\EntityRepository;
|
||||||
use App\Repository\IcannAccreditationRepository;
|
use App\Repository\IcannAccreditationRepository;
|
||||||
@@ -79,7 +80,7 @@ class RDAPService
|
|||||||
private readonly StatService $statService,
|
private readonly StatService $statService,
|
||||||
private readonly InfluxdbService $influxService,
|
private readonly InfluxdbService $influxService,
|
||||||
#[Autowire(param: 'influxdb_enabled')]
|
#[Autowire(param: 'influxdb_enabled')]
|
||||||
private readonly bool $influxdbEnabled,
|
private readonly bool $influxdbEnabled, private readonly DomainStatusRepository $domainStatusRepository,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,4 +717,113 @@ class RDAPService
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function calculateDaysFromStatus(Domain $domain, \DateTimeImmutable $now): ?int
|
||||||
|
{
|
||||||
|
/** @var ?DomainStatus $lastStatus */
|
||||||
|
$lastStatus = $this->domainStatusRepository->createQueryBuilder('ds')
|
||||||
|
->select()
|
||||||
|
->where('ds.domain = :domain')
|
||||||
|
->setParameter('domain', $domain)
|
||||||
|
->orderBy('ds.createdAt', 'DESC')
|
||||||
|
->setMaxResults(1)
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult();
|
||||||
|
|
||||||
|
if (null === $lastStatus) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($domain->isPendingDelete() && (
|
||||||
|
in_array('pending delete', $lastStatus->getAddStatus())
|
||||||
|
|| in_array('redemption period', $lastStatus->getDeleteStatus()))
|
||||||
|
) {
|
||||||
|
return self::daysBetween($now, $lastStatus->getCreatedAt()->add(new \DateInterval('P'. 5 .'D')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($domain->isRedemptionPeriod()
|
||||||
|
&& in_array('redemption period', $lastStatus->getAddStatus())
|
||||||
|
) {
|
||||||
|
return self::daysBetween($now, $lastStatus->getCreatedAt()->add(new \DateInterval('P'.(30 + 5).'D')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRelevantDates(Domain $domain): array
|
||||||
|
{
|
||||||
|
/** @var ?DomainEvent $expirationEvent */
|
||||||
|
$expirationEvent = $this->domainEventRepository->findLastDomainEvent($domain, 'expiration');
|
||||||
|
/** @var ?DomainEvent $deletionEvent */
|
||||||
|
$deletionEvent = $this->domainEventRepository->findLastDomainEvent($domain, 'deletion');
|
||||||
|
|
||||||
|
return [$expirationEvent?->getDate(), $deletionEvent?->getDate()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExpiresInDays(Domain $domain): ?int
|
||||||
|
{
|
||||||
|
if ($domain->getDeleted()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new \DateTimeImmutable();
|
||||||
|
[$expiredAt, $deletedAt] = $this->getRelevantDates($domain);
|
||||||
|
|
||||||
|
if ($expiredAt) {
|
||||||
|
$guess = self::daysBetween($now, $expiredAt->add(new \DateInterval('P'.(45 + 30 + 5).'D')));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($deletedAt) {
|
||||||
|
// It has been observed that AFNIC, on the last day, adds a "deleted" event and removes the redemption period status.
|
||||||
|
if (0 === self::daysBetween($now, $deletedAt) && $domain->isPendingDelete()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$guess = self::daysBetween($now, $deletedAt->add(new \DateInterval('P'. 30 .'D')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::returnExpiresIn([
|
||||||
|
$guess ?? null,
|
||||||
|
$this->calculateDaysFromStatus($domain, $now),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private function calculateDaysFromEvents(\DateTimeImmutable $now): ?int
|
||||||
|
{
|
||||||
|
$lastChangedEvent = $this->getEvents()->findFirst(fn (int $i, DomainEvent $e) => !$e->getDeleted() && EventAction::LastChanged->value === $e->getAction());
|
||||||
|
if (null === $lastChangedEvent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->isRedemptionPeriod()) {
|
||||||
|
return self::daysBetween($now, $lastChangedEvent->getDate()->add(new \DateInterval('P'.(30 + 5).'D')));
|
||||||
|
}
|
||||||
|
if ($this->isPendingDelete()) {
|
||||||
|
return self::daysBetween($now, $lastChangedEvent->getDate()->add(new \DateInterval('P'. 5 .'D')));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static function daysBetween(\DateTimeImmutable $start, \DateTimeImmutable $end): int
|
||||||
|
{
|
||||||
|
$interval = $start->setTime(0, 0)->diff($end->setTime(0, 0));
|
||||||
|
|
||||||
|
return $interval->invert ? -$interval->days : $interval->days;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function returnExpiresIn(array $guesses): ?int
|
||||||
|
{
|
||||||
|
$filteredGuesses = array_filter($guesses, function ($value) {
|
||||||
|
return null !== $value;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (empty($filteredGuesses)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max(min($filteredGuesses), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user