From 5d0f306bccffcbeab3d4d9da8015539eaab21620 Mon Sep 17 00:00:00 2001 From: KetchupBomb <king.me.brad@gmail.com> Date: Sat, 10 Apr 2021 06:50:34 +0000 Subject: [PATCH 1/5] Feature/show API key info in short-url CLI --- .../Command/ShortUrl/ListShortUrlsCommand.php | 105 +++++++++++------- module/Core/src/Entity/ShortUrl.php | 5 + 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php index 24689bcb..aa975a40 100644 --- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php @@ -4,12 +4,15 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\ShortUrl; +use closure; use Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand; use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ShlinkTable; use Shlinkio\Shlink\Common\Paginator\Paginator; use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtilsTrait; use Shlinkio\Shlink\Common\Rest\DataTransformerInterface; +use Shlinkio\Shlink\Core\Entity\ShortUrl; +use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering; use Shlinkio\Shlink\Core\Model\ShortUrlsParams; use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface; @@ -19,10 +22,13 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use function array_keys; use function array_pad; +use function count; use function explode; use function Functional\map; -use function implode; +use function is_null; +use function join; use function sprintf; class ListShortUrlsCommand extends AbstractWithDateRangeCommand @@ -30,18 +36,6 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand use PagerfantaUtilsTrait; public const NAME = 'short-url:list'; - private const COLUMNS_TO_SHOW = [ - 'shortCode', - 'title', - 'shortUrl', - 'longUrl', - 'dateCreated', - 'visitsCount', - ]; - private const COLUMNS_TO_SHOW_WITH_TAGS = [ - ...self::COLUMNS_TO_SHOW, - 'tags', - ]; private ShortUrlServiceInterface $shortUrlService; private DataTransformerInterface $transformer; @@ -90,6 +84,18 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand InputOption::VALUE_NONE, 'Whether to display the tags or not.', ) + ->addOption( + 'show-api-key', + 'k', + InputOption::VALUE_NONE, + 'Whether to display the API key from which the URL was generated or not.', + ) + ->addOption( + 'show-api-key-name', + 'm', + InputOption::VALUE_NONE, + 'Whether to display the API key name from which the URL was generated or not.', + ) ->addOption( 'all', 'a', @@ -117,12 +123,38 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand $searchTerm = $this->getOptionWithDeprecatedFallback($input, 'search-term'); $tags = $input->getOption('tags'); $tags = ! empty($tags) ? explode(',', $tags) : []; - $showTags = $this->getOptionWithDeprecatedFallback($input, 'show-tags'); $all = $input->getOption('all'); $startDate = $this->getStartDateOption($input, $output); $endDate = $this->getEndDateOption($input, $output); $orderBy = $this->processOrderBy($input); + + $transformerLookup = fn (string $key): closure + => fn (ShortUrl $shortUrl) + => $this->transformer->transform($shortUrl)[$key]; + + $columnMap = [ + 'Short Code' => $transformerLookup('shortCode'), + 'Title' => $transformerLookup('title'), + 'Short URL' => $transformerLookup('shortUrl'), + 'Long URL' => $transformerLookup('longUrl'), + 'Date created' => $transformerLookup('dateCreated'), + 'Visits count' => $transformerLookup('visitsCount'), + ]; + if ($this->getOptionWithDeprecatedFallback($input, 'show-tags')) { + $columnMap['Tags'] = fn (ShortUrl $shortUrl): string + => join(', ', map($shortUrl->getTags(), fn (Tag $tag): string => (string) $tag)); + } + if ($input->getOption('show-api-key')) { + $columnMap['API Key'] = fn (ShortUrl $shortUrl): string => (string) $shortUrl->authorApiKey(); + } + if ($input->getOption('show-api-key-name')) { + $columnMap['API Key Name'] = fn (ShortUrl $shortUrl): ?string => ! is_null($shortUrl->authorApiKey()) + ? $shortUrl->authorApiKey()->name() + : null; + } + + $data = [ ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm, ShortUrlsParamsInputFilter::TAGS => $tags, @@ -137,7 +169,7 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand do { $data[ShortUrlsParamsInputFilter::PAGE] = $page; - $result = $this->renderPage($output, $showTags, ShortUrlsParams::fromRawData($data), $all); + $result = $this->renderPage($output, $columnMap, ShortUrlsParams::fromRawData($data), $all); $page++; $continue = $result->hasNextPage() && $io->confirm( @@ -152,32 +184,29 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand return ExitCodes::EXIT_SUCCESS; } - private function renderPage(OutputInterface $output, bool $showTags, ShortUrlsParams $params, bool $all): Paginator - { - $result = $this->shortUrlService->listShortUrls($params); + private function renderPage( + OutputInterface $output, + array $columnMap, + ShortUrlsParams $params, + bool $all + ): Paginator { + $shortUrls = $this->shortUrlService->listShortUrls($params); - $headers = ['Short code', 'Title', 'Short URL', 'Long URL', 'Date created', 'Visits count']; - if ($showTags) { - $headers[] = 'Tags'; - } + $rows = map($shortUrls, fn (ShortUrl $shortUrl) + => map($columnMap, fn (callable $call) + => $call($shortUrl))); - $rows = []; - foreach ($result as $row) { - $columnsToShow = $showTags ? self::COLUMNS_TO_SHOW_WITH_TAGS : self::COLUMNS_TO_SHOW; - $shortUrl = $this->transformer->transform($row); - if ($showTags) { - $shortUrl['tags'] = implode(', ', $shortUrl['tags']); - } + ShlinkTable::fromOutput($output) + ->render( + array_keys($columnMap), + $rows, + $all ? null : $this->formatCurrentPageMessage( + $shortUrls, + 'Page %s of %s', + ), + ); - $rows[] = map($columnsToShow, fn (string $prop) => $shortUrl[$prop]); - } - - ShlinkTable::fromOutput($output)->render($headers, $rows, $all ? null : $this->formatCurrentPageMessage( - $result, - 'Page %s of %s', - )); - - return $result; + return $shortUrls; } private function processOrderBy(InputInterface $input): ?string diff --git a/module/Core/src/Entity/ShortUrl.php b/module/Core/src/Entity/ShortUrl.php index 810281fa..84f215de 100644 --- a/module/Core/src/Entity/ShortUrl.php +++ b/module/Core/src/Entity/ShortUrl.php @@ -132,6 +132,11 @@ class ShortUrl extends AbstractEntity return $this->tags; } + public function authorApiKey(): ?ApiKey + { + return $this->authorApiKey; + } + public function getValidSince(): ?Chronos { return $this->validSince; From a896fbbb9081b1ffa89f1568698f476eed306d3c Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandro@alejandrocelaya.com> Date: Sun, 11 Apr 2021 10:50:35 +0200 Subject: [PATCH 2/5] Fixed coding styles --- .../Command/ShortUrl/ListShortUrlsCommand.php | 58 ++++++++----------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php index aa975a40..69fc2556 100644 --- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\ShortUrl; -use closure; use Shlinkio\Shlink\CLI\Command\Util\AbstractWithDateRangeCommand; use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ShlinkTable; @@ -24,11 +23,9 @@ use Symfony\Component\Console\Style\SymfonyStyle; use function array_keys; use function array_pad; -use function count; use function explode; use function Functional\map; -use function is_null; -use function join; +use function implode; use function sprintf; class ListShortUrlsCommand extends AbstractWithDateRangeCommand @@ -128,32 +125,33 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand $endDate = $this->getEndDateOption($input, $output); $orderBy = $this->processOrderBy($input); - - $transformerLookup = fn (string $key): closure - => fn (ShortUrl $shortUrl) - => $this->transformer->transform($shortUrl)[$key]; + $transformerLookup = fn (string $key): callable => + fn (ShortUrl $shortUrl) => $this->transformer->transform($shortUrl)[$key]; $columnMap = [ - 'Short Code' => $transformerLookup('shortCode'), - 'Title' => $transformerLookup('title'), - 'Short URL' => $transformerLookup('shortUrl'), - 'Long URL' => $transformerLookup('longUrl'), - 'Date created' => $transformerLookup('dateCreated'), - 'Visits count' => $transformerLookup('visitsCount'), + 'Short Code' => $transformerLookup('shortCode'), + 'Title' => $transformerLookup('title'), + 'Short URL' => $transformerLookup('shortUrl'), + 'Long URL' => $transformerLookup('longUrl'), + 'Date created' => $transformerLookup('dateCreated'), + 'Visits count' => $transformerLookup('visitsCount'), ]; if ($this->getOptionWithDeprecatedFallback($input, 'show-tags')) { - $columnMap['Tags'] = fn (ShortUrl $shortUrl): string - => join(', ', map($shortUrl->getTags(), fn (Tag $tag): string => (string) $tag)); + $columnMap['Tags'] = static fn (ShortUrl $shortUrl): string => implode( + ', ', + map($shortUrl->getTags(), fn (Tag $tag): string => (string) $tag), + ); } if ($input->getOption('show-api-key')) { - $columnMap['API Key'] = fn (ShortUrl $shortUrl): string => (string) $shortUrl->authorApiKey(); + $columnMap['API Key'] = static fn (ShortUrl $shortUrl): string => (string) $shortUrl->authorApiKey(); } if ($input->getOption('show-api-key-name')) { - $columnMap['API Key Name'] = fn (ShortUrl $shortUrl): ?string => ! is_null($shortUrl->authorApiKey()) - ? $shortUrl->authorApiKey()->name() - : null; - } + $columnMap['API Key Name'] = static function (ShortUrl $shortUrl): ?string { + $apiKey = $shortUrl->authorApiKey(); + return $apiKey !== null ? $apiKey->name() : null; + }; + } $data = [ ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm, @@ -192,19 +190,13 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand ): Paginator { $shortUrls = $this->shortUrlService->listShortUrls($params); - $rows = map($shortUrls, fn (ShortUrl $shortUrl) - => map($columnMap, fn (callable $call) - => $call($shortUrl))); + $rows = map($shortUrls, fn (ShortUrl $shortUrl) => map($columnMap, fn (callable $call) => $call($shortUrl))); - ShlinkTable::fromOutput($output) - ->render( - array_keys($columnMap), - $rows, - $all ? null : $this->formatCurrentPageMessage( - $shortUrls, - 'Page %s of %s', - ), - ); + ShlinkTable::fromOutput($output)->render( + array_keys($columnMap), + $rows, + $all ? null : $this->formatCurrentPageMessage($shortUrls, 'Page %s of %s'), + ); return $shortUrls; } From 5ddac7866b4ce1e673e1b142a59833fd55aa10e7 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandro@alejandrocelaya.com> Date: Sun, 11 Apr 2021 11:06:29 +0200 Subject: [PATCH 3/5] Ensured short URL transformation happens only once per short URL when listing from CLI --- .../Command/ShortUrl/ListShortUrlsCommand.php | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php index 69fc2556..8aa6bb1d 100644 --- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php @@ -11,7 +11,6 @@ use Shlinkio\Shlink\Common\Paginator\Paginator; use Shlinkio\Shlink\Common\Paginator\Util\PagerfantaUtilsTrait; use Shlinkio\Shlink\Common\Rest\DataTransformerInterface; use Shlinkio\Shlink\Core\Entity\ShortUrl; -use Shlinkio\Shlink\Core\Entity\Tag; use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering; use Shlinkio\Shlink\Core\Model\ShortUrlsParams; use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface; @@ -125,28 +124,24 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand $endDate = $this->getEndDateOption($input, $output); $orderBy = $this->processOrderBy($input); - $transformerLookup = fn (string $key): callable => - fn (ShortUrl $shortUrl) => $this->transformer->transform($shortUrl)[$key]; - + $pickProp = static fn (string $prop): callable => static fn (array $shortUrl) => $shortUrl[$prop]; $columnMap = [ - 'Short Code' => $transformerLookup('shortCode'), - 'Title' => $transformerLookup('title'), - 'Short URL' => $transformerLookup('shortUrl'), - 'Long URL' => $transformerLookup('longUrl'), - 'Date created' => $transformerLookup('dateCreated'), - 'Visits count' => $transformerLookup('visitsCount'), + 'Short Code' => $pickProp('shortCode'), + 'Title' => $pickProp('title'), + 'Short URL' => $pickProp('shortUrl'), + 'Long URL' => $pickProp('longUrl'), + 'Date created' => $pickProp('dateCreated'), + 'Visits count' => $pickProp('visitsCount'), ]; if ($this->getOptionWithDeprecatedFallback($input, 'show-tags')) { - $columnMap['Tags'] = static fn (ShortUrl $shortUrl): string => implode( - ', ', - map($shortUrl->getTags(), fn (Tag $tag): string => (string) $tag), - ); + $columnMap['Tags'] = static fn (array $shortUrl): string => implode(', ', $shortUrl['tags']); } if ($input->getOption('show-api-key')) { - $columnMap['API Key'] = static fn (ShortUrl $shortUrl): string => (string) $shortUrl->authorApiKey(); + $columnMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string => + (string) $shortUrl->authorApiKey(); } if ($input->getOption('show-api-key-name')) { - $columnMap['API Key Name'] = static function (ShortUrl $shortUrl): ?string { + $columnMap['API Key Name'] = static function (array $_, ShortUrl $shortUrl): ?string { $apiKey = $shortUrl->authorApiKey(); return $apiKey !== null ? $apiKey->name() : null; @@ -190,7 +185,10 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand ): Paginator { $shortUrls = $this->shortUrlService->listShortUrls($params); - $rows = map($shortUrls, fn (ShortUrl $shortUrl) => map($columnMap, fn (callable $call) => $call($shortUrl))); + $rows = map($shortUrls, function (ShortUrl $shortUrl) use ($columnMap) { + $rawShortUrl = $this->transformer->transform($shortUrl); + return map($columnMap, fn (callable $call) => $call($rawShortUrl, $shortUrl)); + }); ShlinkTable::fromOutput($output)->render( array_keys($columnMap), From 334d95c843de9c70e84512e12234e5312acd93ef Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandro@alejandrocelaya.com> Date: Sun, 11 Apr 2021 11:29:42 +0200 Subject: [PATCH 4/5] Improved test covering ListSHortUrlsCommand with optional tags --- .../Command/ShortUrl/ListShortUrlsCommand.php | 64 +++++++++------- .../ShortUrl/ListShortUrlsCommandTest.php | 76 +++++++++++++++++-- 2 files changed, 105 insertions(+), 35 deletions(-) diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php index 8aa6bb1d..0d637f5f 100644 --- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php @@ -123,30 +123,7 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand $startDate = $this->getStartDateOption($input, $output); $endDate = $this->getEndDateOption($input, $output); $orderBy = $this->processOrderBy($input); - - $pickProp = static fn (string $prop): callable => static fn (array $shortUrl) => $shortUrl[$prop]; - $columnMap = [ - 'Short Code' => $pickProp('shortCode'), - 'Title' => $pickProp('title'), - 'Short URL' => $pickProp('shortUrl'), - 'Long URL' => $pickProp('longUrl'), - 'Date created' => $pickProp('dateCreated'), - 'Visits count' => $pickProp('visitsCount'), - ]; - if ($this->getOptionWithDeprecatedFallback($input, 'show-tags')) { - $columnMap['Tags'] = static fn (array $shortUrl): string => implode(', ', $shortUrl['tags']); - } - if ($input->getOption('show-api-key')) { - $columnMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string => - (string) $shortUrl->authorApiKey(); - } - if ($input->getOption('show-api-key-name')) { - $columnMap['API Key Name'] = static function (array $_, ShortUrl $shortUrl): ?string { - $apiKey = $shortUrl->authorApiKey(); - - return $apiKey !== null ? $apiKey->name() : null; - }; - } + $columnsMap = $this->resolveColumnsMap($input); $data = [ ShortUrlsParamsInputFilter::SEARCH_TERM => $searchTerm, @@ -162,7 +139,7 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand do { $data[ShortUrlsParamsInputFilter::PAGE] = $page; - $result = $this->renderPage($output, $columnMap, ShortUrlsParams::fromRawData($data), $all); + $result = $this->renderPage($output, $columnsMap, ShortUrlsParams::fromRawData($data), $all); $page++; $continue = $result->hasNextPage() && $io->confirm( @@ -179,19 +156,19 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand private function renderPage( OutputInterface $output, - array $columnMap, + array $columnsMap, ShortUrlsParams $params, bool $all ): Paginator { $shortUrls = $this->shortUrlService->listShortUrls($params); - $rows = map($shortUrls, function (ShortUrl $shortUrl) use ($columnMap) { + $rows = map($shortUrls, function (ShortUrl $shortUrl) use ($columnsMap) { $rawShortUrl = $this->transformer->transform($shortUrl); - return map($columnMap, fn (callable $call) => $call($rawShortUrl, $shortUrl)); + return map($columnsMap, fn (callable $call) => $call($rawShortUrl, $shortUrl)); }); ShlinkTable::fromOutput($output)->render( - array_keys($columnMap), + array_keys($columnsMap), $rows, $all ? null : $this->formatCurrentPageMessage($shortUrls, 'Page %s of %s'), ); @@ -209,4 +186,33 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand [$field, $dir] = array_pad(explode(',', $orderBy), 2, null); return $dir === null ? $field : sprintf('%s-%s', $field, $dir); } + + private function resolveColumnsMap(InputInterface $input): array + { + $pickProp = static fn (string $prop): callable => static fn (array $shortUrl) => $shortUrl[$prop]; + $columnsMap = [ + 'Short Code' => $pickProp('shortCode'), + 'Title' => $pickProp('title'), + 'Short URL' => $pickProp('shortUrl'), + 'Long URL' => $pickProp('longUrl'), + 'Date created' => $pickProp('dateCreated'), + 'Visits count' => $pickProp('visitsCount'), + ]; + if ($this->getOptionWithDeprecatedFallback($input, 'show-tags')) { + $columnsMap['Tags'] = static fn (array $shortUrl): string => implode(', ', $shortUrl['tags']); + } + if ($input->getOption('show-api-key')) { + $columnsMap['API Key'] = static fn (array $_, ShortUrl $shortUrl): string => + (string) $shortUrl->authorApiKey(); + } + if ($input->getOption('show-api-key-name')) { + $columnsMap['API Key Name'] = static function (array $_, ShortUrl $shortUrl): ?string { + $apiKey = $shortUrl->authorApiKey(); + + return $apiKey !== null ? $apiKey->name() : null; + }; + } + + return $columnsMap; + } } diff --git a/module/CLI/test/Command/ShortUrl/ListShortUrlsCommandTest.php b/module/CLI/test/Command/ShortUrl/ListShortUrlsCommandTest.php index 08519b62..6f7b11a6 100644 --- a/module/CLI/test/Command/ShortUrl/ListShortUrlsCommandTest.php +++ b/module/CLI/test/Command/ShortUrl/ListShortUrlsCommandTest.php @@ -12,13 +12,17 @@ use Prophecy\Prophecy\ObjectProphecy; use Shlinkio\Shlink\CLI\Command\ShortUrl\ListShortUrlsCommand; use Shlinkio\Shlink\Common\Paginator\Paginator; use Shlinkio\Shlink\Core\Entity\ShortUrl; +use Shlinkio\Shlink\Core\Model\ShortUrlMeta; use Shlinkio\Shlink\Core\Model\ShortUrlsParams; use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifier; use Shlinkio\Shlink\Core\ShortUrl\Transformer\ShortUrlDataTransformer; +use Shlinkio\Shlink\Rest\ApiKey\Model\ApiKeyMeta; +use Shlinkio\Shlink\Rest\Entity\ApiKey; use ShlinkioTest\Shlink\CLI\CliTestUtilsTrait; use Symfony\Component\Console\Tester\CommandTester; +use function count; use function explode; class ListShortUrlsCommandTest extends TestCase @@ -98,17 +102,77 @@ class ListShortUrlsCommandTest extends TestCase $this->commandTester->execute(['--page' => $page]); } - /** @test */ - public function ifTagsFlagIsProvidedTagsColumnIsIncluded(): void - { + /** + * @test + * @dataProvider provideOptionalFlags + */ + public function provideOptionalFlagsMakesNewColumnsToBeIncluded( + array $input, + array $expectedContents, + array $notExpectedContents, + ApiKey $apiKey + ): void { $this->shortUrlService->listShortUrls(ShortUrlsParams::emptyInstance()) - ->willReturn(new Paginator(new ArrayAdapter([]))) + ->willReturn(new Paginator(new ArrayAdapter([ + ShortUrl::fromMeta(ShortUrlMeta::fromRawData([ + 'longUrl' => 'foo.com', + 'tags' => ['foo', 'bar', 'baz'], + 'apiKey' => $apiKey, + ])), + ]))) ->shouldBeCalledOnce(); $this->commandTester->setInputs(['y']); - $this->commandTester->execute(['--show-tags' => true]); + $this->commandTester->execute($input); $output = $this->commandTester->getDisplay(); - self::assertStringContainsString('Tags', $output); + + if (count($expectedContents) === 0 && count($notExpectedContents) === 0) { + self::fail('No expectations were run'); + } + + foreach ($expectedContents as $column) { + self::assertStringContainsString($column, $output); + } + foreach ($notExpectedContents as $column) { + self::assertStringNotContainsString($column, $output); + } + } + + public function provideOptionalFlags(): iterable + { + $apiKey = ApiKey::fromMeta(ApiKeyMeta::withName('my api key')); + $key = $apiKey->toString(); + + yield 'tags only' => [ + ['--show-tags' => true], + ['| Tags ', '| foo, bar, baz'], + ['| API Key ', '| API Key Name |', $key, '| my api key'], + $apiKey, + ]; + yield 'api key only' => [ + ['--show-api-key' => true], + ['| API Key ', $key], + ['| Tags ', '| foo, bar, baz', '| API Key Name |', '| my api key'], + $apiKey, + ]; + yield 'api key name only' => [ + ['--show-api-key-name' => true], + ['| API Key Name |', '| my api key'], + ['| Tags ', '| foo, bar, baz', '| API Key ', $key], + $apiKey, + ]; + yield 'tags and api key' => [ + ['--show-tags' => true, '--show-api-key' => true], + ['| API Key ', '| Tags ', '| foo, bar, baz', $key], + ['| API Key Name |', '| my api key'], + $apiKey, + ]; + yield 'all' => [ + ['--show-tags' => true, '--show-api-key' => true, '--show-api-key-name' => true], + ['| API Key ', '| Tags ', '| API Key Name |', '| foo, bar, baz', $key, '| my api key'], + [], + $apiKey, + ]; } /** From d751df70fdca8230c71ccac35e3be0a8f2e09c33 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya <alejandro@alejandrocelaya.com> Date: Sun, 11 Apr 2021 11:30:43 +0200 Subject: [PATCH 5/5] Updated changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c88f036..5c0b0075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com), and this Also, when using swoole, the file is now updated **after** tracking a visit, which means it will not apply until the next one. +* [#1059](https://github.com/shlinkio/shlink/issues/1059) Added ability to optionally display author API key and its name when listing short URLs from the command line. + ### Changed * [#1036](https://github.com/shlinkio/shlink/issues/1036) Updated to `happyr/doctrine-specification` 2.0. * [#1039](https://github.com/shlinkio/shlink/issues/1039) Updated to `endroid/qr-code` 4.0.