diff --git a/docs/swagger/paths/v1_short-urls.json b/docs/swagger/paths/v1_short-urls.json index c3db1f05..b034dcf3 100644 --- a/docs/swagger/paths/v1_short-urls.json +++ b/docs/swagger/paths/v1_short-urls.json @@ -64,7 +64,9 @@ "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", - "visits-DESC" + "visits-DESC", + "title-ASC", + "title-DESC" ] } }, diff --git a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php index c0a99f02..24689bcb 100644 --- a/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php +++ b/module/CLI/src/Command/ShortUrl/ListShortUrlsCommand.php @@ -19,11 +19,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use function array_flip; -use function array_intersect_key; use function array_pad; -use function array_values; use function explode; +use function Functional\map; use function implode; use function sprintf; @@ -32,12 +30,16 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand use PagerfantaUtilsTrait; public const NAME = 'short-url:list'; - private const COLUMNS_WHITELIST = [ + private const COLUMNS_TO_SHOW = [ 'shortCode', + 'title', 'shortUrl', 'longUrl', 'dateCreated', 'visitsCount', + ]; + private const COLUMNS_TO_SHOW_WITH_TAGS = [ + ...self::COLUMNS_TO_SHOW, 'tags', ]; @@ -154,21 +156,20 @@ class ListShortUrlsCommand extends AbstractWithDateRangeCommand { $result = $this->shortUrlService->listShortUrls($params); - $headers = ['Short code', 'Short URL', 'Long URL', 'Date created', 'Visits count']; + $headers = ['Short code', 'Title', 'Short URL', 'Long URL', 'Date created', 'Visits count']; if ($showTags) { $headers[] = 'Tags'; } $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']); - } else { - unset($shortUrl['tags']); } - $rows[] = array_values(array_intersect_key($shortUrl, array_flip(self::COLUMNS_WHITELIST))); + $rows[] = map($columnsToShow, fn (string $prop) => $shortUrl[$prop]); } ShlinkTable::fromOutput($output)->render($headers, $rows, $all ? null : $this->formatCurrentPageMessage( diff --git a/module/Core/src/Repository/ShortUrlRepository.php b/module/Core/src/Repository/ShortUrlRepository.php index 3830cdaf..f7a089b7 100644 --- a/module/Core/src/Repository/ShortUrlRepository.php +++ b/module/Core/src/Repository/ShortUrlRepository.php @@ -55,6 +55,7 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU $fieldName = $orderBy->orderField(); $order = $orderBy->orderDirection(); + // visitsCount and visitCount are deprecated. Only visits should work if (contains(['visits', 'visitsCount', 'visitCount'], $fieldName)) { $qb->addSelect('COUNT(DISTINCT v) AS totalVisits') ->leftJoin('s.visits', 'v') @@ -66,10 +67,11 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU // Map public field names to column names $fieldNameMap = [ - 'originalUrl' => 'longUrl', + 'originalUrl' => 'longUrl', // Deprecated 'longUrl' => 'longUrl', 'shortCode' => 'shortCode', 'dateCreated' => 'dateCreated', + 'title' => 'title', ]; if (array_key_exists($fieldName, $fieldNameMap)) { $qb->orderBy('s.' . $fieldNameMap[$fieldName], $order); diff --git a/module/Rest/test-api/Action/ListShortUrlsTest.php b/module/Rest/test-api/Action/ListShortUrlsTest.php index f7182fe5..f81524ae 100644 --- a/module/Rest/test-api/Action/ListShortUrlsTest.php +++ b/module/Rest/test-api/Action/ListShortUrlsTest.php @@ -159,6 +159,14 @@ class ListShortUrlsTest extends ApiTestCase self::SHORT_URL_CUSTOM_SLUG, self::SHORT_URL_SHLINK_WITH_TITLE, ], 'valid_api_key']; + yield [['orderBy' => 'title-DESC'], [ + self::SHORT_URL_META, + self::SHORT_URL_CUSTOM_SLUG, + self::SHORT_URL_DOCS, + self::SHORT_URL_CUSTOM_DOMAIN, + self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN, + self::SHORT_URL_SHLINK_WITH_TITLE, + ], 'valid_api_key']; yield [['startDate' => Chronos::parse('2018-12-01')->toAtomString()], [ self::SHORT_URL_META, self::SHORT_URL_CUSTOM_SLUG,