mirror of
https://github.com/shlinkio/shlink.git
synced 2025-12-10 11:05:50 -06:00
Create command to rename API keys
This commit is contained in:
parent
a661d05100
commit
b08c498b13
@ -28,6 +28,7 @@ return [
|
||||
Command\Api\DisableKeyCommand::NAME => Command\Api\DisableKeyCommand::class,
|
||||
Command\Api\ListKeysCommand::NAME => Command\Api\ListKeysCommand::class,
|
||||
Command\Api\InitialApiKeyCommand::NAME => Command\Api\InitialApiKeyCommand::class,
|
||||
Command\Api\RenameApiKeyCommand::NAME => Command\Api\RenameApiKeyCommand::class,
|
||||
|
||||
Command\Tag\ListTagsCommand::NAME => Command\Tag\ListTagsCommand::class,
|
||||
Command\Tag\RenameTagCommand::NAME => Command\Tag\RenameTagCommand::class,
|
||||
|
||||
@ -59,6 +59,7 @@ return [
|
||||
Command\Api\DisableKeyCommand::class => ConfigAbstractFactory::class,
|
||||
Command\Api\ListKeysCommand::class => ConfigAbstractFactory::class,
|
||||
Command\Api\InitialApiKeyCommand::class => ConfigAbstractFactory::class,
|
||||
Command\Api\RenameApiKeyCommand::class => ConfigAbstractFactory::class,
|
||||
|
||||
Command\Tag\ListTagsCommand::class => ConfigAbstractFactory::class,
|
||||
Command\Tag\RenameTagCommand::class => ConfigAbstractFactory::class,
|
||||
@ -120,6 +121,7 @@ return [
|
||||
Command\Api\DisableKeyCommand::class => [ApiKeyService::class],
|
||||
Command\Api\ListKeysCommand::class => [ApiKeyService::class],
|
||||
Command\Api\InitialApiKeyCommand::class => [ApiKeyService::class],
|
||||
Command\Api\RenameApiKeyCommand::class => [ApiKeyService::class],
|
||||
|
||||
Command\Tag\ListTagsCommand::class => [TagService::class],
|
||||
Command\Tag\RenameTagCommand::class => [TagService::class],
|
||||
|
||||
77
module/CLI/src/Command/Api/RenameApiKeyCommand.php
Normal file
77
module/CLI/src/Command/Api/RenameApiKeyCommand.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Shlinkio\Shlink\CLI\Command\Api;
|
||||
|
||||
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||
use Shlinkio\Shlink\Core\Exception\InvalidArgumentException;
|
||||
use Shlinkio\Shlink\Core\Model\Renaming;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
use function Shlinkio\Shlink\Core\ArrayUtils\map;
|
||||
|
||||
class RenameApiKeyCommand extends Command
|
||||
{
|
||||
public const NAME = 'api-key:rename';
|
||||
|
||||
public function __construct(private readonly ApiKeyServiceInterface $apiKeyService)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setName(self::NAME)
|
||||
->setDescription('Renames an API key by name')
|
||||
->addArgument('oldName', InputArgument::REQUIRED, 'Current name of the API key to rename')
|
||||
->addArgument('newName', InputArgument::REQUIRED, 'New name to set to the API key');
|
||||
}
|
||||
|
||||
protected function interact(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$oldName = $input->getArgument('oldName');
|
||||
$newName = $input->getArgument('newName');
|
||||
|
||||
if ($oldName === null) {
|
||||
$apiKeys = $this->apiKeyService->listKeys();
|
||||
$requestedOldName = $io->choice(
|
||||
'What API key do you want to rename?',
|
||||
map($apiKeys, static fn (ApiKey $apiKey) => $apiKey->name),
|
||||
);
|
||||
|
||||
$input->setArgument('oldName', $requestedOldName);
|
||||
}
|
||||
|
||||
if ($newName === null) {
|
||||
$requestedNewName = $io->ask(
|
||||
'What is the new name you want to set?',
|
||||
validator: static fn (string|null $value): string => $value !== null
|
||||
? $value
|
||||
: throw new InvalidArgumentException('The new name cannot be empty'),
|
||||
);
|
||||
|
||||
$input->setArgument('newName', $requestedNewName);
|
||||
}
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$oldName = $input->getArgument('oldName');
|
||||
$newName = $input->getArgument('newName');
|
||||
|
||||
$this->apiKeyService->renameApiKey(Renaming::fromNames($oldName, $newName));
|
||||
$io->success('API key properly renamed');
|
||||
|
||||
return ExitCode::EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -87,6 +87,9 @@ readonly class ApiKeyService implements ApiKeyServiceInterface
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @todo This method should be transactional and to a SELECT ... FROM UPDATE when checking if the new name exists,
|
||||
* to avoid a race condition where the method is called twice in parallel for a new name that doesn't exist,
|
||||
* causing two API keys to end up with the same name.
|
||||
*/
|
||||
public function renameApiKey(Renaming $apiKeyRenaming): ApiKey
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user