diff --git a/module/CLI/config/cli.config.php b/module/CLI/config/cli.config.php index 012c6800..9feeee7b 100644 --- a/module/CLI/config/cli.config.php +++ b/module/CLI/config/cli.config.php @@ -18,6 +18,7 @@ return [ Command\Visit\LocateVisitsCommand::NAME => Command\Visit\LocateVisitsCommand::class, Command\Visit\DownloadGeoLiteDbCommand::NAME => Command\Visit\DownloadGeoLiteDbCommand::class, Command\Visit\GetOrphanVisitsCommand::NAME => Command\Visit\GetOrphanVisitsCommand::class, + Command\Visit\DeleteOrphanVisitsCommand::NAME => Command\Visit\DeleteOrphanVisitsCommand::class, Command\Visit\GetNonOrphanVisitsCommand::NAME => Command\Visit\GetNonOrphanVisitsCommand::class, Command\Api\GenerateKeyCommand::NAME => Command\Api\GenerateKeyCommand::class, diff --git a/module/CLI/config/dependencies.config.php b/module/CLI/config/dependencies.config.php index 384df91d..6b7fc552 100644 --- a/module/CLI/config/dependencies.config.php +++ b/module/CLI/config/dependencies.config.php @@ -47,6 +47,7 @@ return [ Command\Visit\DownloadGeoLiteDbCommand::class => ConfigAbstractFactory::class, Command\Visit\LocateVisitsCommand::class => ConfigAbstractFactory::class, Command\Visit\GetOrphanVisitsCommand::class => ConfigAbstractFactory::class, + Command\Visit\DeleteOrphanVisitsCommand::class => ConfigAbstractFactory::class, Command\Visit\GetNonOrphanVisitsCommand::class => ConfigAbstractFactory::class, Command\Api\GenerateKeyCommand::class => ConfigAbstractFactory::class, @@ -98,6 +99,7 @@ return [ LockFactory::class, ], Command\Visit\GetOrphanVisitsCommand::class => [Visit\VisitsStatsHelper::class], + Command\Visit\DeleteOrphanVisitsCommand::class => [Visit\VisitsDeleter::class], Command\Visit\GetNonOrphanVisitsCommand::class => [Visit\VisitsStatsHelper::class, ShortUrlStringifier::class], Command\Api\GenerateKeyCommand::class => [ApiKeyService::class, ApiKey\RoleResolver::class], diff --git a/module/CLI/src/Command/Visit/DeleteOrphanVisitsCommand.php b/module/CLI/src/Command/Visit/DeleteOrphanVisitsCommand.php new file mode 100644 index 00000000..af1b7c66 --- /dev/null +++ b/module/CLI/src/Command/Visit/DeleteOrphanVisitsCommand.php @@ -0,0 +1,42 @@ +setName(self::NAME) + ->setDescription('Deletes all orphan visits'); + } + + protected function doExecute(InputInterface $input, SymfonyStyle $io): ?int + { + $result = $this->deleter->deleteOrphanVisits(); + $io->success(sprintf('Successfully deleted %s visits', $result->affectedItems)); + + return ExitCode::EXIT_SUCCESS; + } + + protected function getWarningMessage(): string + { + return 'You are about to delete all orphan visits. This operation cannot be undone.'; + } +} diff --git a/module/CLI/test/Command/Visit/DeleteOrphanVisitsCommandTest.php b/module/CLI/test/Command/Visit/DeleteOrphanVisitsCommandTest.php new file mode 100644 index 00000000..c18fe7f4 --- /dev/null +++ b/module/CLI/test/Command/Visit/DeleteOrphanVisitsCommandTest.php @@ -0,0 +1,43 @@ +deleter = $this->createMock(VisitsDeleterInterface::class); + $this->commandTester = $this->testerForCommand(new DeleteOrphanVisitsCommand($this->deleter)); + } + + #[Test] + public function successMessageIsPrintedAfterDeletion(): void + { + $this->deleter->expects($this->once())->method('deleteOrphanVisits')->willReturn(new BulkDeleteResult(5)); + $this->commandTester->setInputs(['yes']); + + $exitCode = $this->commandTester->execute([]); + $output = $this->commandTester->getDisplay(); + + self::assertEquals(ExitCode::EXIT_SUCCESS, $exitCode); + self::assertStringContainsString('You are about to delete all orphan visits.', $output); + self::assertStringContainsString('Successfully deleted 5 visits', $output); + } +}