1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-06-27 16:36:00 +00:00

add a Command to purge expired records of EntryDeletion

This commit is contained in:
Martin Chaine 2025-06-03 09:47:49 +02:00
parent b625a77783
commit 5c823c91a3
No known key found for this signature in database
GPG key ID: 2D04DFDC89D53FDE
3 changed files with 189 additions and 0 deletions

View file

@ -0,0 +1,94 @@
<?php
namespace Wallabag\Command;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Wallabag\Repository\EntryDeletionRepository;
class PurgeEntryDeletionsCommand extends Command
{
protected static $defaultName = 'wallabag:purge-entry-deletions';
protected static $defaultDescription = 'Purge old entry deletion records';
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly EntryDeletionRepository $entryDeletionRepository,
) {
parent::__construct();
}
protected function configure()
{
$this
->addOption(
'older-than',
null,
InputOption::VALUE_REQUIRED,
'Purge records older than this date (format: YYYY-MM-DD)',
'-30 days'
)
->addOption(
'dry-run',
null,
InputOption::VALUE_NONE,
'Do not actually delete records, just show what would be deleted'
);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$olderThan = $input->getOption('older-than');
$dryRun = (bool) $input->getOption('dry-run');
try {
$date = new \DateTime($olderThan);
} catch (\Exception $e) {
$io->error(sprintf('Invalid date format: %s.\nYou can use any format supported by PHP (e.g. YYYY-MM-DD).', $olderThan));
return 1;
}
$count = $this->entryDeletionRepository->countAllBefore($date);
if ($dryRun) {
$io->text('Dry run mode <info>enabled</info> (no records will be deleted)');
return 0;
}
if (0 === $count) {
$io->success('No entry deletion records found.');
return 0;
}
if ($dryRun) {
$io->success(sprintf('Would have deleted %d records.', $count));
return 0;
}
$confirmMessage = sprintf(
'Are you sure you want to delete records older than %s? (count: %d)',
$date->format('Y-m-d'),
$count,
);
if (!$io->confirm($confirmMessage)) {
return 0;
}
$this->entryDeletionRepository->deleteAllBefore($date);
$io->success(sprintf('Successfully deleted %d records.', $count));
return 0;
}
}

View file

@ -40,4 +40,24 @@ class EntryDeletionRepository extends ServiceEntityRepository
return $pager;
}
public function countAllBefore(\DateTime $date): int
{
return $this->createQueryBuilder('de')
->select('COUNT(de.id)')
->where('de.deletedAt < :date')
->setParameter('date', $date)
->getQuery()
->getSingleScalarResult();
}
public function deleteAllBefore(\DateTime $date)
{
$this->createQueryBuilder('de')
->delete()
->where('de.deletedAt < :date')
->setParameter('date', $date)
->getQuery()
->execute();
}
}

View file

@ -0,0 +1,75 @@
<?php
namespace Tests\Wallabag\Command;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Tester\CommandTester;
use Tests\Wallabag\WallabagTestCase;
use Wallabag\Entity\EntryDeletion;
/**
* Test the purge entry deletions command.
*
* The fixtures set up the following entry deletions:
* - Admin user: 1 deletion from 4 days ago (entry_id: 1004)
* - Admin user: 1 deletion from 1 day ago (entry_id: 1001)
* - Bob user: 1 deletion from 3 days ago (entry_id: 1003)
*/
class PurgeEntryDeletionsCommandTest extends WallabagTestCase
{
public function testRunPurgeEntryDeletionsCommandWithDryRun()
{
$application = new Application($this->getTestClient()->getKernel());
$command = $application->find('wallabag:purge-entry-deletions');
$dateStr = '-2 days';
$tester = new CommandTester($command);
$tester->execute([
'--older-than' => $dateStr,
'--dry-run' => true,
]);
$this->assertStringContainsString('Dry run mode enabled', $tester->getDisplay());
$this->assertSame(0, $tester->getStatusCode());
$em = $this->getEntityManager();
$count = $em->getRepository(EntryDeletion::class)->countAllBefore(new \DateTime($dateStr));
$this->assertSame(2, $count);
}
public function testRunPurgeEntryDeletionsCommand()
{
$application = new Application($this->getTestClient()->getKernel());
$command = $application->find('wallabag:purge-entry-deletions');
$dateStr = '-2 days';
$tester = new CommandTester($command);
$tester->setInputs(['yes']); // confirm deletion
$tester->execute(['--older-than' => $dateStr]);
$this->assertStringContainsString('Successfully deleted 2 records', $tester->getDisplay());
$this->assertSame(0, $tester->getStatusCode());
$em = $this->getEntityManager();
$count = $em->getRepository(EntryDeletion::class)->countAllBefore(new \DateTime($dateStr));
$this->assertSame(0, $count);
$count = $em->getRepository(EntryDeletion::class)->countAllBefore(new \DateTime('now'));
$this->assertSame(1, $count);
}
public function testRunPurgeEntryDeletionsCommandWithNoRecords()
{
$application = new Application($this->getTestClient()->getKernel());
$command = $application->find('wallabag:purge-entry-deletions');
$tester = new CommandTester($command);
$tester->execute([
'--older-than' => '-1 year',
]);
$this->assertStringContainsString('No entry deletion records found', $tester->getDisplay());
$this->assertSame(0, $tester->getStatusCode());
}
}