mirror of
https://github.com/shlinkio/shlink.git
synced 2024-12-22 15:13:59 -06:00
Create DeleteShortUrlVisitsCommand
This commit is contained in:
parent
6bb8c1b2f5
commit
02a8ef7dd9
@ -13,6 +13,7 @@ return [
|
|||||||
Command\ShortUrl\ListShortUrlsCommand::NAME => Command\ShortUrl\ListShortUrlsCommand::class,
|
Command\ShortUrl\ListShortUrlsCommand::NAME => Command\ShortUrl\ListShortUrlsCommand::class,
|
||||||
Command\ShortUrl\GetShortUrlVisitsCommand::NAME => Command\ShortUrl\GetShortUrlVisitsCommand::class,
|
Command\ShortUrl\GetShortUrlVisitsCommand::NAME => Command\ShortUrl\GetShortUrlVisitsCommand::class,
|
||||||
Command\ShortUrl\DeleteShortUrlCommand::NAME => Command\ShortUrl\DeleteShortUrlCommand::class,
|
Command\ShortUrl\DeleteShortUrlCommand::NAME => Command\ShortUrl\DeleteShortUrlCommand::class,
|
||||||
|
Command\ShortUrl\DeleteShortUrlVisitsCommand::NAME => Command\ShortUrl\DeleteShortUrlVisitsCommand::class,
|
||||||
|
|
||||||
Command\Visit\LocateVisitsCommand::NAME => Command\Visit\LocateVisitsCommand::class,
|
Command\Visit\LocateVisitsCommand::NAME => Command\Visit\LocateVisitsCommand::class,
|
||||||
Command\Visit\DownloadGeoLiteDbCommand::NAME => Command\Visit\DownloadGeoLiteDbCommand::class,
|
Command\Visit\DownloadGeoLiteDbCommand::NAME => Command\Visit\DownloadGeoLiteDbCommand::class,
|
||||||
|
@ -42,6 +42,7 @@ return [
|
|||||||
Command\ShortUrl\ListShortUrlsCommand::class => ConfigAbstractFactory::class,
|
Command\ShortUrl\ListShortUrlsCommand::class => ConfigAbstractFactory::class,
|
||||||
Command\ShortUrl\GetShortUrlVisitsCommand::class => ConfigAbstractFactory::class,
|
Command\ShortUrl\GetShortUrlVisitsCommand::class => ConfigAbstractFactory::class,
|
||||||
Command\ShortUrl\DeleteShortUrlCommand::class => ConfigAbstractFactory::class,
|
Command\ShortUrl\DeleteShortUrlCommand::class => ConfigAbstractFactory::class,
|
||||||
|
Command\ShortUrl\DeleteShortUrlVisitsCommand::class => ConfigAbstractFactory::class,
|
||||||
|
|
||||||
Command\Visit\DownloadGeoLiteDbCommand::class => ConfigAbstractFactory::class,
|
Command\Visit\DownloadGeoLiteDbCommand::class => ConfigAbstractFactory::class,
|
||||||
Command\Visit\LocateVisitsCommand::class => ConfigAbstractFactory::class,
|
Command\Visit\LocateVisitsCommand::class => ConfigAbstractFactory::class,
|
||||||
@ -88,6 +89,7 @@ return [
|
|||||||
],
|
],
|
||||||
Command\ShortUrl\GetShortUrlVisitsCommand::class => [Visit\VisitsStatsHelper::class],
|
Command\ShortUrl\GetShortUrlVisitsCommand::class => [Visit\VisitsStatsHelper::class],
|
||||||
Command\ShortUrl\DeleteShortUrlCommand::class => [ShortUrl\DeleteShortUrlService::class],
|
Command\ShortUrl\DeleteShortUrlCommand::class => [ShortUrl\DeleteShortUrlService::class],
|
||||||
|
Command\ShortUrl\DeleteShortUrlVisitsCommand::class => [ShortUrl\ShortUrlVisitsDeleter::class],
|
||||||
|
|
||||||
Command\Visit\DownloadGeoLiteDbCommand::class => [GeoLite\GeolocationDbUpdater::class],
|
Command\Visit\DownloadGeoLiteDbCommand::class => [GeoLite\GeolocationDbUpdater::class],
|
||||||
Command\Visit\LocateVisitsCommand::class => [
|
Command\Visit\LocateVisitsCommand::class => [
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
||||||
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
|
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
@ -39,10 +39,10 @@ class DisableKeyCommand extends Command
|
|||||||
try {
|
try {
|
||||||
$this->apiKeyService->disable($apiKey);
|
$this->apiKeyService->disable($apiKey);
|
||||||
$io->success(sprintf('API key "%s" properly disabled', $apiKey));
|
$io->success(sprintf('API key "%s" properly disabled', $apiKey));
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
$io->error($e->getMessage());
|
$io->error($e->getMessage());
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Api;
|
|||||||
|
|
||||||
use Cake\Chronos\Chronos;
|
use Cake\Chronos\Chronos;
|
||||||
use Shlinkio\Shlink\CLI\ApiKey\RoleResolverInterface;
|
use Shlinkio\Shlink\CLI\ApiKey\RoleResolverInterface;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
||||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
@ -109,6 +109,6 @@ class GenerateKeyCommand extends Command
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
||||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
@ -77,7 +77,7 @@ class ListKeysCommand extends Command
|
|||||||
'Roles',
|
'Roles',
|
||||||
]), $rows);
|
]), $rows);
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function determineMessagePattern(ApiKey $apiKey): string
|
private function determineMessagePattern(ApiKey $apiKey): string
|
||||||
|
@ -8,7 +8,7 @@ use Doctrine\DBAL\Connection;
|
|||||||
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
use Doctrine\DBAL\Platforms\SqlitePlatform;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
|
use Shlinkio\Shlink\CLI\Util\ProcessRunnerInterface;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
@ -57,7 +57,7 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
|
|||||||
|
|
||||||
if ($this->schemaExists()) {
|
if ($this->schemaExists()) {
|
||||||
$io->success('Database already exists. Run "db:migrate" command to make sure it is up to date.');
|
$io->success('Database already exists. Run "db:migrate" command to make sure it is up to date.');
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create database
|
// Create database
|
||||||
@ -65,7 +65,7 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
|
|||||||
$this->runPhpCommand($output, [self::DOCTRINE_SCRIPT, self::DOCTRINE_CREATE_SCHEMA_COMMAND]);
|
$this->runPhpCommand($output, [self::DOCTRINE_SCRIPT, self::DOCTRINE_CREATE_SCHEMA_COMMAND]);
|
||||||
$io->success('Database properly created!');
|
$io->success('Database properly created!');
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function checkDbExists(): void
|
private function checkDbExists(): void
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Db;
|
namespace Shlinkio\Shlink\CLI\Command\Db;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
@ -31,6 +31,6 @@ class MigrateDatabaseCommand extends AbstractDatabaseCommand
|
|||||||
$this->runPhpCommand($output, [self::DOCTRINE_MIGRATIONS_SCRIPT, self::DOCTRINE_MIGRATE_COMMAND]);
|
$this->runPhpCommand($output, [self::DOCTRINE_MIGRATIONS_SCRIPT, self::DOCTRINE_MIGRATE_COMMAND]);
|
||||||
$io->success('Database properly migrated!');
|
$io->success('Database properly migrated!');
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Domain;
|
namespace Shlinkio\Shlink\CLI\Command\Domain;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
|
use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
|
||||||
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
||||||
@ -109,6 +109,6 @@ class DomainRedirectsCommand extends Command
|
|||||||
|
|
||||||
$io->success(sprintf('"Not found" redirects properly set for "%s"', $domainAuthority));
|
$io->success(sprintf('"Not found" redirects properly set for "%s"', $domainAuthority));
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Domain;
|
namespace Shlinkio\Shlink\CLI\Command\Domain;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Core\Config\NotFoundRedirectConfigInterface;
|
use Shlinkio\Shlink\Core\Config\NotFoundRedirectConfigInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
||||||
@ -59,7 +59,7 @@ class ListDomainsCommand extends Command
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function notFoundRedirectsToString(NotFoundRedirectConfigInterface $config): string
|
private function notFoundRedirectsToString(NotFoundRedirectConfigInterface $config): string
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
||||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||||
@ -141,7 +141,7 @@ class CreateShortUrlCommand extends Command
|
|||||||
$longUrl = $input->getArgument('longUrl');
|
$longUrl = $input->getArgument('longUrl');
|
||||||
if (empty($longUrl)) {
|
if (empty($longUrl)) {
|
||||||
$io->error('A URL was not provided!');
|
$io->error('A URL was not provided!');
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$explodeWithComma = curry(explode(...))(',');
|
$explodeWithComma = curry(explode(...))(',');
|
||||||
@ -176,10 +176,10 @@ class CreateShortUrlCommand extends Command
|
|||||||
sprintf('Processed long URL: <info>%s</info>', $longUrl),
|
sprintf('Processed long URL: <info>%s</info>', $longUrl),
|
||||||
sprintf('Generated short URL: <info>%s</info>', $this->stringifier->stringify($result->shortUrl)),
|
sprintf('Generated short URL: <info>%s</info>', $this->stringifier->stringify($result->shortUrl)),
|
||||||
]);
|
]);
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (InvalidUrlException | NonUniqueSlugException $e) {
|
} catch (InvalidUrlException | NonUniqueSlugException $e) {
|
||||||
$io->error($e->getMessage());
|
$io->error($e->getMessage());
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception;
|
use Shlinkio\Shlink\Core\Exception;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\DeleteShortUrlServiceInterface;
|
use Shlinkio\Shlink\Core\ShortUrl\DeleteShortUrlServiceInterface;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
|
||||||
@ -55,10 +55,10 @@ class DeleteShortUrlCommand extends Command
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$this->runDelete($io, $identifier, $ignoreThreshold);
|
$this->runDelete($io, $identifier, $ignoreThreshold);
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (Exception\ShortUrlNotFoundException $e) {
|
} catch (Exception\ShortUrlNotFoundException $e) {
|
||||||
$io->error($e->getMessage());
|
$io->error($e->getMessage());
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
} catch (Exception\DeleteShortUrlException $e) {
|
} catch (Exception\DeleteShortUrlException $e) {
|
||||||
return $this->retry($io, $identifier, $e->getMessage());
|
return $this->retry($io, $identifier, $e->getMessage());
|
||||||
}
|
}
|
||||||
@ -75,7 +75,7 @@ class DeleteShortUrlCommand extends Command
|
|||||||
$io->warning('Short URL was not deleted.');
|
$io->warning('Short URL was not deleted.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $forceDelete ? ExitCodes::EXIT_SUCCESS : ExitCodes::EXIT_WARNING;
|
return $forceDelete ? ExitCode::EXIT_SUCCESS : ExitCode::EXIT_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function runDelete(SymfonyStyle $io, ShortUrlIdentifier $identifier, bool $ignoreThreshold): void
|
private function runDelete(SymfonyStyle $io, ShortUrlIdentifier $identifier, bool $ignoreThreshold): void
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||||
|
|
||||||
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
|
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
|
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
|
||||||
|
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlVisitsDeleterInterface;
|
||||||
|
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;
|
||||||
|
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
|
class DeleteShortUrlVisitsCommand extends Command
|
||||||
|
{
|
||||||
|
public const NAME = 'short-url:delete-visits';
|
||||||
|
|
||||||
|
public function __construct(private readonly ShortUrlVisitsDeleterInterface $deleter)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName(self::NAME)
|
||||||
|
->setDescription('Deletes visits from a short URL')
|
||||||
|
->addArgument(
|
||||||
|
'shortCode',
|
||||||
|
InputArgument::REQUIRED,
|
||||||
|
'The short code for the short URL which visits will be deleted',
|
||||||
|
)
|
||||||
|
->addOption(
|
||||||
|
'domain',
|
||||||
|
'd',
|
||||||
|
InputOption::VALUE_REQUIRED,
|
||||||
|
'The domain if the short code does not belong to the default one',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): ?int
|
||||||
|
{
|
||||||
|
$identifier = ShortUrlIdentifier::fromCli($input);
|
||||||
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
if (! $this->confirm($io)) {
|
||||||
|
$io->info('Operation aborted');
|
||||||
|
return ExitCode::EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $this->deleter->deleteShortUrlVisits($identifier);
|
||||||
|
$io->success(sprintf('Successfully deleted %s visits', $result->affectedItems));
|
||||||
|
|
||||||
|
return ExitCode::EXIT_SUCCESS;
|
||||||
|
} catch (ShortUrlNotFoundException) {
|
||||||
|
$io->warning(sprintf('Short URL not found for "%s"', $identifier->__toString()));
|
||||||
|
return ExitCode::EXIT_WARNING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function confirm(SymfonyStyle $io): bool
|
||||||
|
{
|
||||||
|
$io->warning('You are about to delete all visits for a short URL. This operation cannot be undone.');
|
||||||
|
return $io->confirm('<comment>Continue deleting visits?</comment>', false);
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
|||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Input\EndDateOption;
|
use Shlinkio\Shlink\CLI\Input\EndDateOption;
|
||||||
use Shlinkio\Shlink\CLI\Input\StartDateOption;
|
use Shlinkio\Shlink\CLI\Input\StartDateOption;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Common\Paginator\Paginator;
|
use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||||
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtilsTrait;
|
use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtilsTrait;
|
||||||
@ -173,7 +173,7 @@ class ListShortUrlsCommand extends Command
|
|||||||
$io->newLine();
|
$io->newLine();
|
||||||
$io->success('Short URLs properly listed');
|
$io->success('Short URLs properly listed');
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderPage(
|
private function renderPage(
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
namespace Shlinkio\Shlink\CLI\Command\ShortUrl;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlResolverInterface;
|
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlResolverInterface;
|
||||||
@ -56,10 +56,10 @@ class ResolveUrlCommand extends Command
|
|||||||
try {
|
try {
|
||||||
$url = $this->urlResolver->resolveShortUrl(ShortUrlIdentifier::fromCli($input));
|
$url = $this->urlResolver->resolveShortUrl(ShortUrlIdentifier::fromCli($input));
|
||||||
$output->writeln(sprintf('Long URL: <info>%s</info>', $url->getLongUrl()));
|
$output->writeln(sprintf('Long URL: <info>%s</info>', $url->getLongUrl()));
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (ShortUrlNotFoundException $e) {
|
} catch (ShortUrlNotFoundException $e) {
|
||||||
$io->error($e->getMessage());
|
$io->error($e->getMessage());
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Tag\TagServiceInterface;
|
use Shlinkio\Shlink\Core\Tag\TagServiceInterface;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@ -41,11 +41,11 @@ class DeleteTagsCommand extends Command
|
|||||||
|
|
||||||
if (empty($tagNames)) {
|
if (empty($tagNames)) {
|
||||||
$io->warning('You have to provide at least one tag name');
|
$io->warning('You have to provide at least one tag name');
|
||||||
return ExitCodes::EXIT_WARNING;
|
return ExitCode::EXIT_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->tagService->deleteTags($tagNames);
|
$this->tagService->deleteTags($tagNames);
|
||||||
$io->success('Tags properly deleted');
|
$io->success('Tags properly deleted');
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Core\Tag\Model\TagInfo;
|
use Shlinkio\Shlink\Core\Tag\Model\TagInfo;
|
||||||
use Shlinkio\Shlink\Core\Tag\Model\TagsParams;
|
use Shlinkio\Shlink\Core\Tag\Model\TagsParams;
|
||||||
@ -34,7 +34,7 @@ class ListTagsCommand extends Command
|
|||||||
protected function execute(InputInterface $input, OutputInterface $output): ?int
|
protected function execute(InputInterface $input, OutputInterface $output): ?int
|
||||||
{
|
{
|
||||||
ShlinkTable::default($output)->render(['Name', 'URLs amount', 'Visits amount'], $this->getTagsRows());
|
ShlinkTable::default($output)->render(['Name', 'URLs amount', 'Visits amount'], $this->getTagsRows());
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getTagsRows(): array
|
private function getTagsRows(): array
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
namespace Shlinkio\Shlink\CLI\Command\Tag;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\TagConflictException;
|
use Shlinkio\Shlink\Core\Exception\TagConflictException;
|
||||||
use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
|
use Shlinkio\Shlink\Core\Exception\TagNotFoundException;
|
||||||
use Shlinkio\Shlink\Core\Tag\Model\TagRenaming;
|
use Shlinkio\Shlink\Core\Tag\Model\TagRenaming;
|
||||||
@ -42,10 +42,10 @@ class RenameTagCommand extends Command
|
|||||||
try {
|
try {
|
||||||
$this->tagService->renameTag(TagRenaming::fromNames($oldName, $newName));
|
$this->tagService->renameTag(TagRenaming::fromNames($oldName, $newName));
|
||||||
$io->success('Tag properly renamed.');
|
$io->success('Tag properly renamed.');
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (TagNotFoundException | TagConflictException $e) {
|
} catch (TagNotFoundException | TagConflictException $e) {
|
||||||
$io->error($e->getMessage());
|
$io->error($e->getMessage());
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Command\Util;
|
namespace Shlinkio\Shlink\CLI\Command\Util;
|
||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
@ -28,7 +28,7 @@ abstract class AbstractLockedCommand extends Command
|
|||||||
$output->writeln(
|
$output->writeln(
|
||||||
sprintf('<comment>Command "%s" is already in progress. Skipping.</comment>', $lockConfig->lockName),
|
sprintf('<comment>Command "%s" is already in progress. Skipping.</comment>', $lockConfig->lockName),
|
||||||
);
|
);
|
||||||
return ExitCodes::EXIT_WARNING;
|
return ExitCode::EXIT_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Visit;
|
|||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Input\EndDateOption;
|
use Shlinkio\Shlink\CLI\Input\EndDateOption;
|
||||||
use Shlinkio\Shlink\CLI\Input\StartDateOption;
|
use Shlinkio\Shlink\CLI\Input\StartDateOption;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
|
||||||
use Shlinkio\Shlink\Common\Paginator\Paginator;
|
use Shlinkio\Shlink\Common\Paginator\Paginator;
|
||||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||||
@ -43,7 +43,7 @@ abstract class AbstractVisitsListCommand extends Command
|
|||||||
|
|
||||||
ShlinkTable::default($output)->render($headers, $rows);
|
ShlinkTable::default($output)->render($headers, $rows);
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function resolveRowsAndHeaders(Paginator $paginator): array
|
private function resolveRowsAndHeaders(Paginator $paginator): array
|
||||||
|
@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Visit;
|
|||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
||||||
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
|
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@ -56,7 +56,7 @@ class DownloadGeoLiteDbCommand extends Command
|
|||||||
$io->success('GeoLite2 db file properly downloaded.');
|
$io->success('GeoLite2 db file properly downloaded.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (GeolocationDbUpdateFailedException $e) {
|
} catch (GeolocationDbUpdateFailedException $e) {
|
||||||
$olderDbExists = $e->olderDbExists();
|
$olderDbExists = $e->olderDbExists();
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ class DownloadGeoLiteDbCommand extends Command
|
|||||||
$this->getApplication()?->renderThrowable($e, $io);
|
$this->getApplication()?->renderThrowable($e, $io);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $olderDbExists ? ExitCodes::EXIT_WARNING : ExitCodes::EXIT_FAILURE;
|
return $olderDbExists ? ExitCode::EXIT_WARNING : ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Visit;
|
|||||||
|
|
||||||
use Shlinkio\Shlink\CLI\Command\Util\AbstractLockedCommand;
|
use Shlinkio\Shlink\CLI\Command\Util\AbstractLockedCommand;
|
||||||
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
|
use Shlinkio\Shlink\CLI\Command\Util\LockedCommandConfig;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Common\Util\IpAddress;
|
use Shlinkio\Shlink\Common\Util\IpAddress;
|
||||||
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
|
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
|
||||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||||
@ -116,14 +116,14 @@ class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocat
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->io->success('Finished locating visits');
|
$this->io->success('Finished locating visits');
|
||||||
return ExitCodes::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
$this->io->error($e->getMessage());
|
$this->io->error($e->getMessage());
|
||||||
if ($this->io->isVerbose()) {
|
if ($this->io->isVerbose()) {
|
||||||
$this->getApplication()?->renderThrowable($e, $this->io);
|
$this->getApplication()?->renderThrowable($e, $this->io);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExitCodes::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ class LocateVisitsCommand extends AbstractLockedCommand implements VisitGeolocat
|
|||||||
$downloadDbCommand = $cliApp->find(DownloadGeoLiteDbCommand::NAME);
|
$downloadDbCommand = $cliApp->find(DownloadGeoLiteDbCommand::NAME);
|
||||||
$exitCode = $downloadDbCommand->run(new ArrayInput([]), $this->io);
|
$exitCode = $downloadDbCommand->run(new ArrayInput([]), $this->io);
|
||||||
|
|
||||||
if ($exitCode === ExitCodes::EXIT_FAILURE) {
|
if ($exitCode === ExitCode::EXIT_FAILURE) {
|
||||||
throw new RuntimeException('It is not possible to locate visits without a GeoLite2 db file.');
|
throw new RuntimeException('It is not possible to locate visits without a GeoLite2 db file.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Util;
|
namespace Shlinkio\Shlink\CLI\Util;
|
||||||
|
|
||||||
final class ExitCodes
|
final class ExitCode
|
||||||
{
|
{
|
||||||
public const EXIT_SUCCESS = 0;
|
public const EXIT_SUCCESS = 0;
|
||||||
public const EXIT_FAILURE = -1;
|
public const EXIT_FAILURE = -1;
|
@ -7,7 +7,7 @@ namespace ShlinkioCliTest\Shlink\CLI\Command;
|
|||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand;
|
use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand;
|
||||||
use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand;
|
use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
||||||
|
|
||||||
class CreateShortUrlTest extends CliTestCase
|
class CreateShortUrlTest extends CliTestCase
|
||||||
@ -22,7 +22,7 @@ class CreateShortUrlTest extends CliTestCase
|
|||||||
[CreateShortUrlCommand::NAME, 'https://example.com', '--domain', $defaultDomain, '--custom-slug', $slug],
|
[CreateShortUrlCommand::NAME, 'https://example.com', '--domain', $defaultDomain, '--custom-slug', $slug],
|
||||||
);
|
);
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode);
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $exitCode);
|
||||||
self::assertStringContainsString('Generated short URL: http://' . $defaultDomain . '/' . $slug, $output);
|
self::assertStringContainsString('Generated short URL: http://' . $defaultDomain . '/' . $slug, $output);
|
||||||
|
|
||||||
[$listOutput] = $this->exec([ListShortUrlsCommand::NAME, '--show-domain', '--search-term', $slug]);
|
[$listOutput] = $this->exec([ListShortUrlsCommand::NAME, '--show-domain', '--search-term', $slug]);
|
||||||
|
@ -6,7 +6,7 @@ namespace ShlinkioCliTest\Shlink\CLI\Command;
|
|||||||
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Shlinkio\Shlink\CLI\Command\Api\GenerateKeyCommand;
|
use Shlinkio\Shlink\CLI\Command\Api\GenerateKeyCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
||||||
|
|
||||||
class GenerateApiKeyTest extends CliTestCase
|
class GenerateApiKeyTest extends CliTestCase
|
||||||
@ -17,6 +17,6 @@ class GenerateApiKeyTest extends CliTestCase
|
|||||||
[$output, $exitCode] = $this->exec([GenerateKeyCommand::NAME]);
|
[$output, $exitCode] = $this->exec([GenerateKeyCommand::NAME]);
|
||||||
|
|
||||||
self::assertStringContainsString('[OK] Generated API key', $output);
|
self::assertStringContainsString('[OK] Generated API key', $output);
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode);
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $exitCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use Cake\Chronos\Chronos;
|
|||||||
use PHPUnit\Framework\Attributes\DataProvider;
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
|
use Shlinkio\Shlink\CLI\Command\Api\ListKeysCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
use Shlinkio\Shlink\TestUtils\CliTest\CliTestCase;
|
||||||
|
|
||||||
class ListApiKeysTest extends CliTestCase
|
class ListApiKeysTest extends CliTestCase
|
||||||
@ -19,7 +19,7 @@ class ListApiKeysTest extends CliTestCase
|
|||||||
[$output, $exitCode] = $this->exec([ListKeysCommand::NAME, ...$flags]);
|
[$output, $exitCode] = $this->exec([ListKeysCommand::NAME, ...$flags]);
|
||||||
|
|
||||||
self::assertEquals($expectedOutput, $output);
|
self::assertEquals($expectedOutput, $output);
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $exitCode);
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function provideFlags(): iterable
|
public static function provideFlags(): iterable
|
||||||
|
@ -9,7 +9,7 @@ use PHPUnit\Framework\Attributes\Test;
|
|||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Shlinkio\Shlink\CLI\Command\Domain\ListDomainsCommand;
|
use Shlinkio\Shlink\CLI\Command\Domain\ListDomainsCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
|
use Shlinkio\Shlink\Core\Config\NotFoundRedirects;
|
||||||
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
|
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
|
||||||
@ -53,7 +53,7 @@ class ListDomainsCommandTest extends TestCase
|
|||||||
$this->commandTester->execute($input);
|
$this->commandTester->execute($input);
|
||||||
|
|
||||||
self::assertEquals($expectedOutput, $this->commandTester->getDisplay());
|
self::assertEquals($expectedOutput, $this->commandTester->getDisplay());
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function provideInputsAndOutputs(): iterable
|
public static function provideInputsAndOutputs(): iterable
|
||||||
|
@ -11,7 +11,7 @@ use PHPUnit\Framework\Attributes\Test;
|
|||||||
use PHPUnit\Framework\MockObject\MockObject;
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand;
|
use Shlinkio\Shlink\CLI\Command\ShortUrl\CreateShortUrlCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
use Shlinkio\Shlink\Core\Exception\InvalidUrlException;
|
||||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||||
@ -65,7 +65,7 @@ class CreateShortUrlCommandTest extends TestCase
|
|||||||
], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||||
self::assertStringContainsString('stringified_short_url', $output);
|
self::assertStringContainsString('stringified_short_url', $output);
|
||||||
self::assertStringNotContainsString('but the real-time updates cannot', $output);
|
self::assertStringNotContainsString('but the real-time updates cannot', $output);
|
||||||
}
|
}
|
||||||
@ -82,7 +82,7 @@ class CreateShortUrlCommandTest extends TestCase
|
|||||||
$this->commandTester->execute(['longUrl' => $url]);
|
$this->commandTester->execute(['longUrl' => $url]);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_FAILURE, $this->commandTester->getStatusCode());
|
||||||
self::assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output);
|
self::assertStringContainsString('Provided URL http://domain.com/invalid is invalid.', $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class CreateShortUrlCommandTest extends TestCase
|
|||||||
$this->commandTester->execute(['longUrl' => 'http://domain.com/invalid', '--custom-slug' => 'my-slug']);
|
$this->commandTester->execute(['longUrl' => 'http://domain.com/invalid', '--custom-slug' => 'my-slug']);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_FAILURE, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_FAILURE, $this->commandTester->getStatusCode());
|
||||||
self::assertStringContainsString('Provided slug "my-slug" is already in use', $output);
|
self::assertStringContainsString('Provided slug "my-slug" is already in use', $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class CreateShortUrlCommandTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||||
self::assertStringContainsString('stringified_short_url', $output);
|
self::assertStringContainsString('stringified_short_url', $output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ class CreateShortUrlCommandTest extends TestCase
|
|||||||
$input['longUrl'] = 'http://domain.com/foo/bar';
|
$input['longUrl'] = 'http://domain.com/foo/bar';
|
||||||
$this->commandTester->execute($input);
|
$this->commandTester->execute($input);
|
||||||
|
|
||||||
self::assertEquals(ExitCodes::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
self::assertEquals(ExitCode::EXIT_SUCCESS, $this->commandTester->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function provideDomains(): iterable
|
public static function provideDomains(): iterable
|
||||||
|
@ -12,7 +12,7 @@ use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand;
|
|||||||
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
|
||||||
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
|
use Shlinkio\Shlink\CLI\GeoLite\GeolocationDbUpdaterInterface;
|
||||||
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
|
use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use ShlinkioTest\Shlink\CLI\CliTestUtilsTrait;
|
use ShlinkioTest\Shlink\CLI\CliTestUtilsTrait;
|
||||||
use Symfony\Component\Console\Tester\CommandTester;
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
@ -65,12 +65,12 @@ class DownloadGeoLiteDbCommandTest extends TestCase
|
|||||||
yield 'existing db' => [
|
yield 'existing db' => [
|
||||||
true,
|
true,
|
||||||
'[WARNING] GeoLite2 db file update failed. Visits will continue to be located',
|
'[WARNING] GeoLite2 db file update failed. Visits will continue to be located',
|
||||||
ExitCodes::EXIT_WARNING,
|
ExitCode::EXIT_WARNING,
|
||||||
];
|
];
|
||||||
yield 'not existing db' => [
|
yield 'not existing db' => [
|
||||||
false,
|
false,
|
||||||
'[ERROR] GeoLite2 db file download failed. It will not be possible to locate',
|
'[ERROR] GeoLite2 db file download failed. It will not be possible to locate',
|
||||||
ExitCodes::EXIT_FAILURE,
|
ExitCode::EXIT_FAILURE,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ class DownloadGeoLiteDbCommandTest extends TestCase
|
|||||||
$exitCode = $this->commandTester->getStatusCode();
|
$exitCode = $this->commandTester->getStatusCode();
|
||||||
|
|
||||||
self::assertStringContainsString($expectedMessage, $output);
|
self::assertStringContainsString($expectedMessage, $output);
|
||||||
self::assertSame(ExitCodes::EXIT_SUCCESS, $exitCode);
|
self::assertSame(ExitCode::EXIT_SUCCESS, $exitCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function provideSuccessParams(): iterable
|
public static function provideSuccessParams(): iterable
|
||||||
|
@ -10,7 +10,7 @@ use PHPUnit\Framework\MockObject\MockObject;
|
|||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand;
|
use Shlinkio\Shlink\CLI\Command\Visit\DownloadGeoLiteDbCommand;
|
||||||
use Shlinkio\Shlink\CLI\Command\Visit\LocateVisitsCommand;
|
use Shlinkio\Shlink\CLI\Command\Visit\LocateVisitsCommand;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCodes;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
|
use Shlinkio\Shlink\Core\Exception\IpCannotBeLocatedException;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
||||||
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
use Shlinkio\Shlink\Core\Visit\Entity\Visit;
|
||||||
@ -85,7 +85,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
$this->visitToLocation->expects(
|
$this->visitToLocation->expects(
|
||||||
$this->exactly($expectedUnlocatedCalls + $expectedEmptyCalls + $expectedAllCalls),
|
$this->exactly($expectedUnlocatedCalls + $expectedEmptyCalls + $expectedAllCalls),
|
||||||
)->method('resolveVisitLocation')->withAnyParameters()->willReturn(Location::emptyInstance());
|
)->method('resolveVisitLocation')->withAnyParameters()->willReturn(Location::emptyInstance());
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->commandTester->setInputs(['y']);
|
$this->commandTester->setInputs(['y']);
|
||||||
$this->commandTester->execute($args);
|
$this->commandTester->execute($args);
|
||||||
@ -118,7 +118,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
->withAnyParameters()
|
->withAnyParameters()
|
||||||
->willReturnCallback($this->invokeHelperMethods($visit, $location));
|
->willReturnCallback($this->invokeHelperMethods($visit, $location));
|
||||||
$this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->willThrowException($e);
|
$this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->willThrowException($e);
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
||||||
|
|
||||||
@ -147,7 +147,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
$this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->willThrowException(
|
$this->visitToLocation->expects($this->once())->method('resolveVisitLocation')->willThrowException(
|
||||||
IpCannotBeLocatedException::forError(WrongIpException::fromIpAddress('1.2.3.4')),
|
IpCannotBeLocatedException::forError(WrongIpException::fromIpAddress('1.2.3.4')),
|
||||||
);
|
);
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
|
|
||||||
$this->visitService->expects($this->never())->method('locateUnlocatedVisits');
|
$this->visitService->expects($this->never())->method('locateUnlocatedVisits');
|
||||||
$this->visitToLocation->expects($this->never())->method('resolveVisitLocation');
|
$this->visitToLocation->expects($this->never())->method('resolveVisitLocation');
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
$this->commandTester->execute([], ['verbosity' => OutputInterface::VERBOSITY_VERBOSE]);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
@ -186,7 +186,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
public function showsProperMessageWhenGeoLiteUpdateFails(): void
|
public function showsProperMessageWhenGeoLiteUpdateFails(): void
|
||||||
{
|
{
|
||||||
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
|
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_FAILURE);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_FAILURE);
|
||||||
$this->visitService->expects($this->never())->method('locateUnlocatedVisits');
|
$this->visitService->expects($this->never())->method('locateUnlocatedVisits');
|
||||||
|
|
||||||
$this->commandTester->execute([]);
|
$this->commandTester->execute([]);
|
||||||
@ -199,7 +199,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
public function providingAllFlagOnItsOwnDisplaysNotice(): void
|
public function providingAllFlagOnItsOwnDisplaysNotice(): void
|
||||||
{
|
{
|
||||||
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
|
$this->lock->method('acquire')->with($this->isFalse())->willReturn(true);
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->commandTester->execute(['--all' => true]);
|
$this->commandTester->execute(['--all' => true]);
|
||||||
$output = $this->commandTester->getDisplay();
|
$output = $this->commandTester->getDisplay();
|
||||||
@ -210,7 +210,7 @@ class LocateVisitsCommandTest extends TestCase
|
|||||||
#[Test, DataProvider('provideAbortInputs')]
|
#[Test, DataProvider('provideAbortInputs')]
|
||||||
public function processingAllCancelsCommandIfUserDoesNotActivelyAgreeToConfirmation(array $inputs): void
|
public function processingAllCancelsCommandIfUserDoesNotActivelyAgreeToConfirmation(array $inputs): void
|
||||||
{
|
{
|
||||||
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCodes::EXIT_SUCCESS);
|
$this->downloadDbCommand->method('run')->withAnyParameters()->willReturn(ExitCode::EXIT_SUCCESS);
|
||||||
|
|
||||||
$this->expectException(RuntimeException::class);
|
$this->expectException(RuntimeException::class);
|
||||||
$this->expectExceptionMessage('Execution aborted');
|
$this->expectExceptionMessage('Execution aborted');
|
||||||
|
@ -8,6 +8,8 @@ use Psr\Http\Message\ServerRequestInterface;
|
|||||||
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
final class ShortUrlIdentifier
|
final class ShortUrlIdentifier
|
||||||
{
|
{
|
||||||
private function __construct(public readonly string $shortCode, public readonly ?string $domain = null)
|
private function __construct(public readonly string $shortCode, public readonly ?string $domain = null)
|
||||||
@ -54,4 +56,13 @@ final class ShortUrlIdentifier
|
|||||||
{
|
{
|
||||||
return new self($shortCode, $domain);
|
return new self($shortCode, $domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
if ($this->domain === null) {
|
||||||
|
return $this->shortCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('%s/%s', $this->domain, $this->shortCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class ShortUrlVisitsDeleter implements ShortUrlVisitsDeleterInterface
|
|||||||
/**
|
/**
|
||||||
* @throws ShortUrlNotFoundException
|
* @throws ShortUrlNotFoundException
|
||||||
*/
|
*/
|
||||||
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey): BulkDeleteResult
|
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): BulkDeleteResult
|
||||||
{
|
{
|
||||||
$shortUrl = $this->resolver->resolveShortUrl($identifier, $apiKey);
|
$shortUrl = $this->resolver->resolveShortUrl($identifier, $apiKey);
|
||||||
return new BulkDeleteResult($this->repository->deleteShortUrlVisits($shortUrl));
|
return new BulkDeleteResult($this->repository->deleteShortUrlVisits($shortUrl));
|
||||||
|
@ -14,5 +14,5 @@ interface ShortUrlVisitsDeleterInterface
|
|||||||
/**
|
/**
|
||||||
* @throws ShortUrlNotFoundException
|
* @throws ShortUrlNotFoundException
|
||||||
*/
|
*/
|
||||||
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey): BulkDeleteResult;
|
public function deleteShortUrlVisits(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): BulkDeleteResult;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ class VisitDeleterRepositoryTest extends DatabaseTestCase
|
|||||||
|
|
||||||
$this->getEntityManager()->flush();
|
$this->getEntityManager()->flush();
|
||||||
|
|
||||||
self::assertEquals(0, $this->repo->deleteShortUrlVisits(ShortUrl::withLongUrl('https://invalid')->setId('99')));
|
|
||||||
self::assertEquals(2, $this->repo->deleteShortUrlVisits($shortUrl1));
|
self::assertEquals(2, $this->repo->deleteShortUrlVisits($shortUrl1));
|
||||||
self::assertEquals(0, $this->repo->deleteShortUrlVisits($shortUrl1));
|
self::assertEquals(0, $this->repo->deleteShortUrlVisits($shortUrl1));
|
||||||
self::assertEquals(4, $this->repo->deleteShortUrlVisits($shortUrl2));
|
self::assertEquals(4, $this->repo->deleteShortUrlVisits($shortUrl2));
|
||||||
|
@ -320,27 +320,6 @@ class CreateShortUrlTest extends ApiTestCase
|
|||||||
yield 'example domain' => ['example.com'];
|
yield 'example domain' => ['example.com'];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Test, DataProvider('provideTwitterUrls')]
|
|
||||||
public function urlsWithBotProtectionCanBeShortenedWithUrlValidationEnabled(string $longUrl): void
|
|
||||||
{
|
|
||||||
// Requests to Twitter are randomly failing from GitHub actions. Let's skip this test there.
|
|
||||||
// This is a deprecated and low-used feature anyway.
|
|
||||||
if (env('CI', false)) {
|
|
||||||
$this->markTestSkipped();
|
|
||||||
}
|
|
||||||
|
|
||||||
[$statusCode] = $this->createShortUrl(['longUrl' => $longUrl, 'validateUrl' => true]);
|
|
||||||
self::assertEquals(self::STATUS_OK, $statusCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function provideTwitterUrls(): iterable
|
|
||||||
{
|
|
||||||
yield ['https://twitter.com/shlinkio'];
|
|
||||||
yield ['https://mobile.twitter.com/shlinkio'];
|
|
||||||
yield ['https://twitter.com/shlinkio/status/1360637738421268481'];
|
|
||||||
yield ['https://mobile.twitter.com/shlinkio/status/1360637738421268481'];
|
|
||||||
}
|
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function canCreateShortUrlsWithEmojis(): void
|
public function canCreateShortUrlsWithEmojis(): void
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user