feat: add app:entity:privacy-protection command

This commit is contained in:
Maël Gangloff
2025-12-13 15:41:50 +01:00
parent 94a29bc8df
commit a814cdc444
8 changed files with 139 additions and 7 deletions

View File

@@ -0,0 +1,31 @@
<?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 Version20251213142040 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add privacy_protection column on entity';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE entity ADD privacy_protection BOOLEAN NOT NULL DEFAULT FALSE');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE entity DROP privacy_protection');
}
}

View File

@@ -15,7 +15,7 @@ use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\TransportNamesStamp;
#[AsCommand(
name: 'app:batch-register-domains',
name: 'app:domains:import',
description: 'Register a domain list',
)]
class BatchRegisterDomainCommand extends Command

View File

@@ -0,0 +1,83 @@
<?php
namespace App\Command;
use App\Entity\DomainEntity;
use App\Repository\EntityRepository;
use App\Service\RDAPService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:entity:privacy-protection',
description: 'Enable or disable privacy protection for an entity',
)]
class EntityPrivacyCommand extends Command
{
public function __construct(
private readonly EntityManagerInterface $em,
private readonly EntityRepository $entityRepository,
private readonly RDAPService $RDAPService,
) {
parent::__construct();
}
protected function configure(): void
{
$this->addArgument('handle', InputArgument::REQUIRED, 'Entity handle')
->addArgument('tld', InputArgument::REQUIRED, 'Entity TLD')
->addOption('enable', 'ep', InputOption::VALUE_NEGATABLE, 'Enable or disable privacy protection', true);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$entity = $this->entityRepository->findOneBy(['handle' => $input->getArgument('handle'), 'tld' => $input->getArgument('tld')]);
$enable = $input->getOption('enable');
if (null === $entity) {
$io->error('Entity not found in the database.');
return Command::FAILURE;
}
if ($entity->isPrivacyProtection() && $enable || !$entity->isPrivacyProtection() && !$enable) {
$io->warning('Privacy protection is already in the requested state.');
return Command::INVALID;
}
$entity->setPrivacyProtection($enable);
if ($enable) {
$entity->setJCard([]);
$entity->setRemarks([]);
} else {
$domainEntity = $entity->getDomainEntities()->findFirst(fn (int $key, DomainEntity $de) => null === $de->getDeletedAt() && !$de->getDomain()->getDeleted());
if (null !== $domainEntity) {
try {
$this->RDAPService->registerDomain($domainEntity->getDomain()->getLdhName());
} catch (\Exception) {
$io->warning('Failed to update the jCard using a linked domain.');
}
}
}
$this->em->flush();
$io->success(sprintf(
'Privacy protection %s for entity %s (%s).',
$enable ? 'enabled' : 'disabled',
$entity->getHandle(),
$entity->getTld()->getTld()
));
return Command::SUCCESS;
}
}

View File

@@ -12,7 +12,7 @@ use Symfony\Component\Messenger\Exception\ExceptionInterface;
use Symfony\Component\Messenger\MessageBusInterface;
#[AsCommand(
name: 'app:process-watchlist',
name: 'app:watchlist:process',
description: 'Process watchlist and send emails if necessary',
)]
class ProcessWatchlistCommand extends Command

View File

@@ -17,7 +17,7 @@ use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Messenger\MessageBusInterface;
#[AsCommand(
name: 'app:register-domain',
name: 'app:domain:register',
description: 'Register a domain name in the database',
)]
class RegisterDomainCommand extends Command

View File

@@ -12,7 +12,7 @@ use Symfony\Component\Messenger\Exception\ExceptionInterface;
use Symfony\Component\Messenger\MessageBusInterface;
#[AsCommand(
name: 'app:update-rdap-servers',
name: 'app:rdap-server:update',
description: 'Updates the RDAP servers cache (requires MQ to be running)',
)]
class UpdateRdapServersCommand extends Command

View File

@@ -67,15 +67,17 @@ class Entity
#[ORM\Column(
type: 'string',
nullable: true,
insertable: false,
updatable: false,
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (UPPER(jsonb_path_query_first(j_card, '$[1]?(@[0] == \"fn\")[3]') #>> '{}')) STORED",
generated: 'ALWAYS',
generated: 'ALWAYS'
)]
private ?string $jCardFn;
#[ORM\Column(
type: 'string',
nullable: true,
insertable: false,
updatable: false,
columnDefinition: "VARCHAR(255) GENERATED ALWAYS AS (UPPER(jsonb_path_query_first(j_card, '$[1]?(@[0] == \"org\")[3]') #>> '{}')) STORED",
@@ -91,6 +93,10 @@ class Entity
#[Groups(['entity:list', 'entity:item', 'domain:item'])]
private ?IcannAccreditation $icannAccreditation = null;
#[ORM\Column]
#[Groups(['entity:item', 'domain:item', 'watchlist:item'])]
private ?bool $privacyProtection = null;
public function __construct()
{
$this->domainEntities = new ArrayCollection();
@@ -283,4 +289,16 @@ class Entity
return $this;
}
public function isPrivacyProtection(): ?bool
{
return $this->privacyProtection;
}
public function setPrivacyProtection(bool $privacyProtection): static
{
$this->privacyProtection = $privacyProtection;
return $this;
}
}

View File

@@ -588,11 +588,11 @@ class RDAPService
$entity->setHandle($rdapEntity['handle'])->setIcannAccreditation($icannAccreditation);
if (isset($rdapEntity['remarks']) && is_array($rdapEntity['remarks'])) {
if (isset($rdapEntity['remarks']) && is_array($rdapEntity['remarks']) && !$entity->isPrivacyProtection()) {
$entity->setRemarks($rdapEntity['remarks']);
}
if (isset($rdapEntity['vcardArray'])) {
if (isset($rdapEntity['vcardArray']) && !$entity->isPrivacyProtection()) {
if (empty($entity->getJCard())) {
if (!array_key_exists('elements', $rdapEntity['vcardArray'])) {
$entity->setJCard($rdapEntity['vcardArray']);