mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-22 08:56:42 -06:00
Create command to edit existing short URLs
This commit is contained in:
parent
8917ed5c2e
commit
5bccdded8a
@ -93,7 +93,7 @@ return [
|
|||||||
ShortUrlStringifier::class,
|
ShortUrlStringifier::class,
|
||||||
UrlShortenerOptions::class,
|
UrlShortenerOptions::class,
|
||||||
],
|
],
|
||||||
Command\ShortUrl\EditShortUrlCommand::class => [ShortUrl\ShortUrlService::class],
|
Command\ShortUrl\EditShortUrlCommand::class => [ShortUrl\ShortUrlService::class, ShortUrlStringifier::class],
|
||||||
Command\ShortUrl\ResolveUrlCommand::class => [ShortUrl\ShortUrlResolver::class],
|
Command\ShortUrl\ResolveUrlCommand::class => [ShortUrl\ShortUrlResolver::class],
|
||||||
Command\ShortUrl\ListShortUrlsCommand::class => [
|
Command\ShortUrl\ListShortUrlsCommand::class => [
|
||||||
ShortUrl\ShortUrlListService::class,
|
ShortUrl\ShortUrlListService::class,
|
||||||
|
@ -9,8 +9,6 @@ use Shlinkio\Shlink\CLI\Util\ExitCode;
|
|||||||
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException;
|
||||||
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
|
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\UrlShortenerInterface;
|
use Shlinkio\Shlink\Core\ShortUrl\UrlShortenerInterface;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
@ -95,29 +93,17 @@ class CreateShortUrlCommand extends Command
|
|||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$io = $this->getIO($input, $output);
|
$io = $this->getIO($input, $output);
|
||||||
$longUrl = $this->shortUrlDataInput->longUrl($input);
|
|
||||||
if (empty($longUrl)) {
|
|
||||||
$io->error('A URL was not provided!');
|
|
||||||
return ExitCode::EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
$shortCodeLength = $input->getOption('short-code-length') ?? $this->options->defaultShortCodesLength;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = $this->urlShortener->shorten(ShortUrlCreation::fromRawData([
|
$result = $this->urlShortener->shorten($this->shortUrlDataInput->toShortUrlCreation(
|
||||||
ShortUrlInputFilter::LONG_URL => $longUrl,
|
$input,
|
||||||
ShortUrlInputFilter::VALID_SINCE => $this->shortUrlDataInput->validSince($input),
|
$this->options,
|
||||||
ShortUrlInputFilter::VALID_UNTIL => $this->shortUrlDataInput->validUntil($input),
|
customSlugField: 'custom-slug',
|
||||||
ShortUrlInputFilter::MAX_VISITS => $this->shortUrlDataInput->maxVisits($input),
|
shortCodeLengthField: 'short-code-length',
|
||||||
ShortUrlInputFilter::CUSTOM_SLUG => $input->getOption('custom-slug'),
|
pathPrefixField: 'path-prefix',
|
||||||
ShortUrlInputFilter::PATH_PREFIX => $input->getOption('path-prefix'),
|
findIfExistsField: 'find-if-exists',
|
||||||
ShortUrlInputFilter::FIND_IF_EXISTS => $input->getOption('find-if-exists'),
|
domainField: 'domain',
|
||||||
ShortUrlInputFilter::DOMAIN => $input->getOption('domain'),
|
));
|
||||||
ShortUrlInputFilter::SHORT_CODE_LENGTH => $shortCodeLength,
|
|
||||||
ShortUrlInputFilter::TAGS => $this->shortUrlDataInput->tags($input),
|
|
||||||
ShortUrlInputFilter::CRAWLABLE => $this->shortUrlDataInput->crawlable($input),
|
|
||||||
ShortUrlInputFilter::FORWARD_QUERY => !$this->shortUrlDataInput->noForwardQuery($input),
|
|
||||||
], $this->options));
|
|
||||||
|
|
||||||
$result->onEventDispatchingError(static fn () => $io->isVerbose() && $io->warning(
|
$result->onEventDispatchingError(static fn () => $io->isVerbose() && $io->warning(
|
||||||
'Short URL properly created, but the real-time updates cannot be notified when generating the '
|
'Short URL properly created, but the real-time updates cannot be notified when generating the '
|
||||||
@ -125,7 +111,7 @@ class CreateShortUrlCommand extends Command
|
|||||||
));
|
));
|
||||||
|
|
||||||
$io->writeln([
|
$io->writeln([
|
||||||
sprintf('Processed long URL: <info>%s</info>', $longUrl),
|
sprintf('Processed long URL: <info>%s</info>', $result->shortUrl->getLongUrl()),
|
||||||
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 ExitCode::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
|
@ -8,12 +8,15 @@ use Shlinkio\Shlink\CLI\Input\ShortUrlDataInput;
|
|||||||
use Shlinkio\Shlink\CLI\Input\ShortUrlIdentifierInput;
|
use Shlinkio\Shlink\CLI\Input\ShortUrlIdentifierInput;
|
||||||
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
use Shlinkio\Shlink\CLI\Util\ExitCode;
|
||||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
|
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlServiceInterface;
|
use Shlinkio\Shlink\Core\ShortUrl\ShortUrlServiceInterface;
|
||||||
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;
|
||||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
use function sprintf;
|
||||||
|
|
||||||
class EditShortUrlCommand extends Command
|
class EditShortUrlCommand extends Command
|
||||||
{
|
{
|
||||||
public const NAME = 'short-url:edit';
|
public const NAME = 'short-url:edit';
|
||||||
@ -21,8 +24,10 @@ class EditShortUrlCommand extends Command
|
|||||||
private readonly ShortUrlDataInput $shortUrlDataInput;
|
private readonly ShortUrlDataInput $shortUrlDataInput;
|
||||||
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;
|
private readonly ShortUrlIdentifierInput $shortUrlIdentifierInput;
|
||||||
|
|
||||||
public function __construct(private readonly ShortUrlServiceInterface $shortUrlService)
|
public function __construct(
|
||||||
{
|
private readonly ShortUrlServiceInterface $shortUrlService,
|
||||||
|
private readonly ShortUrlStringifierInterface $stringifier,
|
||||||
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->shortUrlDataInput = new ShortUrlDataInput($this, longUrlAsOption: true);
|
$this->shortUrlDataInput = new ShortUrlDataInput($this, longUrlAsOption: true);
|
||||||
@ -43,17 +48,23 @@ class EditShortUrlCommand extends Command
|
|||||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
{
|
{
|
||||||
$io = new SymfonyStyle($input, $output);
|
$io = new SymfonyStyle($input, $output);
|
||||||
|
$identifier = $this->shortUrlIdentifierInput->toShortUrlIdentifier($input);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$shortUrl = $this->shortUrlService->updateShortUrl(
|
$shortUrl = $this->shortUrlService->updateShortUrl(
|
||||||
$this->shortUrlIdentifierInput->toShortUrlIdentifier($input),
|
$identifier,
|
||||||
$this->shortUrlDataInput->toShortUrlEdition($input),
|
$this->shortUrlDataInput->toShortUrlEdition($input),
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO Print success
|
$io->success(sprintf('Short URL "%s" properly edited', $this->stringifier->stringify($shortUrl)));
|
||||||
return ExitCode::EXIT_SUCCESS;
|
return ExitCode::EXIT_SUCCESS;
|
||||||
} catch (ShortUrlNotFoundException) {
|
} catch (ShortUrlNotFoundException $e) {
|
||||||
// TODO Print error
|
$io->error(sprintf('Short URL not found for "%s"', $identifier->__toString()));
|
||||||
|
|
||||||
|
if ($io->isVerbose()) {
|
||||||
|
$this->getApplication()?->renderThrowable($e, $io);
|
||||||
|
}
|
||||||
|
|
||||||
return ExitCode::EXIT_FAILURE;
|
return ExitCode::EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Shlinkio\Shlink\CLI\Input;
|
namespace Shlinkio\Shlink\CLI\Input;
|
||||||
|
|
||||||
|
use Shlinkio\Shlink\Core\Options\UrlShortenerOptions;
|
||||||
|
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlCreation;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlEdition;
|
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlEdition;
|
||||||
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
@ -53,6 +55,11 @@ readonly final class ShortUrlDataInput
|
|||||||
InputOption::VALUE_REQUIRED,
|
InputOption::VALUE_REQUIRED,
|
||||||
'This will limit the number of visits for this short URL.',
|
'This will limit the number of visits for this short URL.',
|
||||||
)
|
)
|
||||||
|
->addOption(
|
||||||
|
'title',
|
||||||
|
mode: InputOption::VALUE_REQUIRED,
|
||||||
|
description: 'A descriptive title for the short URL.',
|
||||||
|
)
|
||||||
->addOption(
|
->addOption(
|
||||||
'crawlable',
|
'crawlable',
|
||||||
'r',
|
'r',
|
||||||
@ -67,59 +74,46 @@ readonly final class ShortUrlDataInput
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function longUrl(InputInterface $input): ?string
|
|
||||||
{
|
|
||||||
return $this->longUrlAsOption ? $input->getOption('long-url') : $input->getArgument('longUrl');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string[]
|
|
||||||
*/
|
|
||||||
public function tags(InputInterface $input): array
|
|
||||||
{
|
|
||||||
return array_unique(flatten(array_map(splitByComma(...), $input->getOption('tags'))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validSince(InputInterface $input): ?string
|
|
||||||
{
|
|
||||||
return $input->getOption('valid-since');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function validUntil(InputInterface $input): ?string
|
|
||||||
{
|
|
||||||
return $input->getOption('valid-until');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function maxVisits(InputInterface $input): ?int
|
|
||||||
{
|
|
||||||
$maxVisits = $input->getOption('max-visits');
|
|
||||||
return $maxVisits !== null ? (int) $maxVisits : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function crawlable(InputInterface $input): bool
|
|
||||||
{
|
|
||||||
return $input->getOption('crawlable');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function noForwardQuery(InputInterface $input): bool
|
|
||||||
{
|
|
||||||
return $input->getOption('no-forward-query');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function toShortUrlEdition(InputInterface $input): ShortUrlEdition
|
public function toShortUrlEdition(InputInterface $input): ShortUrlEdition
|
||||||
{
|
{
|
||||||
return ShortUrlEdition::fromRawData([
|
return ShortUrlEdition::fromRawData($this->getCommonData($input));
|
||||||
ShortUrlInputFilter::LONG_URL => $this->longUrl($input),
|
|
||||||
ShortUrlInputFilter::VALID_SINCE => $this->validSince($input),
|
|
||||||
ShortUrlInputFilter::VALID_UNTIL => $this->validUntil($input),
|
|
||||||
ShortUrlInputFilter::MAX_VISITS => $this->maxVisits($input),
|
|
||||||
ShortUrlInputFilter::TAGS => $this->tags($input),
|
|
||||||
ShortUrlInputFilter::CRAWLABLE => $this->crawlable($input),
|
|
||||||
ShortUrlInputFilter::FORWARD_QUERY => !$this->noForwardQuery($input),
|
|
||||||
// ShortUrlInputFilter::TITLE => TODO,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
public function toShortUrlCreation(
|
||||||
// public function toShortUrlCreation(InputInterface $input)
|
InputInterface $input,
|
||||||
|
UrlShortenerOptions $options,
|
||||||
|
string $customSlugField,
|
||||||
|
string $shortCodeLengthField,
|
||||||
|
string $pathPrefixField,
|
||||||
|
string $findIfExistsField,
|
||||||
|
string $domainField,
|
||||||
|
): ShortUrlCreation {
|
||||||
|
$shortCodeLength = $input->getOption($shortCodeLengthField) ?? $options->defaultShortCodesLength;
|
||||||
|
return ShortUrlCreation::fromRawData([
|
||||||
|
...$this->getCommonData($input),
|
||||||
|
ShortUrlInputFilter::CUSTOM_SLUG => $input->getOption($customSlugField),
|
||||||
|
ShortUrlInputFilter::SHORT_CODE_LENGTH => $shortCodeLength,
|
||||||
|
ShortUrlInputFilter::PATH_PREFIX => $input->getOption($pathPrefixField),
|
||||||
|
ShortUrlInputFilter::FIND_IF_EXISTS => $input->getOption($findIfExistsField),
|
||||||
|
ShortUrlInputFilter::DOMAIN => $input->getOption($domainField),
|
||||||
|
], $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getCommonData(InputInterface $input): array
|
||||||
|
{
|
||||||
|
$longUrl = $this->longUrlAsOption ? $input->getOption('long-url') : $input->getArgument('longUrl');
|
||||||
|
$tags = array_unique(flatten(array_map(splitByComma(...), $input->getOption('tags'))));
|
||||||
|
$maxVisits = $input->getOption('max-visits');
|
||||||
|
|
||||||
|
return [
|
||||||
|
ShortUrlInputFilter::LONG_URL => $longUrl,
|
||||||
|
ShortUrlInputFilter::VALID_SINCE => $input->getOption('valid-since'),
|
||||||
|
ShortUrlInputFilter::VALID_UNTIL => $input->getOption('valid-until'),
|
||||||
|
ShortUrlInputFilter::MAX_VISITS => $maxVisits !== null ? (int) $maxVisits : null,
|
||||||
|
ShortUrlInputFilter::TAGS => $tags,
|
||||||
|
ShortUrlInputFilter::TITLE => $input->getOption('title'),
|
||||||
|
ShortUrlInputFilter::CRAWLABLE => $input->getOption('crawlable'),
|
||||||
|
ShortUrlInputFilter::FORWARD_QUERY => !$input->getOption('no-forward-query'),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user