mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-28 09:03:07 +03:00
Applied API role specs to short URLs list
This commit is contained in:
parent
6e1d6ab795
commit
940383646b
8 changed files with 57 additions and 22 deletions
|
@ -7,16 +7,19 @@ namespace Shlinkio\Shlink\Core\Paginator\Adapter;
|
||||||
use Laminas\Paginator\Adapter\AdapterInterface;
|
use Laminas\Paginator\Adapter\AdapterInterface;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ShortUrlRepositoryAdapter implements AdapterInterface
|
class ShortUrlRepositoryAdapter implements AdapterInterface
|
||||||
{
|
{
|
||||||
private ShortUrlRepositoryInterface $repository;
|
private ShortUrlRepositoryInterface $repository;
|
||||||
private ShortUrlsParams $params;
|
private ShortUrlsParams $params;
|
||||||
|
private ?ApiKey $apiKey;
|
||||||
|
|
||||||
public function __construct(ShortUrlRepositoryInterface $repository, ShortUrlsParams $params)
|
public function __construct(ShortUrlRepositoryInterface $repository, ShortUrlsParams $params, ?ApiKey $apiKey)
|
||||||
{
|
{
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
$this->params = $params;
|
$this->params = $params;
|
||||||
|
$this->apiKey = $apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getItems($offset, $itemCountPerPage): array // phpcs:ignore
|
public function getItems($offset, $itemCountPerPage): array // phpcs:ignore
|
||||||
|
@ -28,6 +31,7 @@ class ShortUrlRepositoryAdapter implements AdapterInterface
|
||||||
$this->params->tags(),
|
$this->params->tags(),
|
||||||
$this->params->orderBy(),
|
$this->params->orderBy(),
|
||||||
$this->params->dateRange(),
|
$this->params->dateRange(),
|
||||||
|
$this->apiKey !== null ? $this->apiKey->spec() : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +41,7 @@ class ShortUrlRepositoryAdapter implements AdapterInterface
|
||||||
$this->params->searchTerm(),
|
$this->params->searchTerm(),
|
||||||
$this->params->tags(),
|
$this->params->tags(),
|
||||||
$this->params->dateRange(),
|
$this->params->dateRange(),
|
||||||
|
$this->apiKey !== null ? $this->apiKey->spec() : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,10 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Core\Repository;
|
namespace Shlinkio\Shlink\Core\Repository;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
use Doctrine\ORM\Query\Expr\Join;
|
use Doctrine\ORM\Query\Expr\Join;
|
||||||
use Doctrine\ORM\QueryBuilder;
|
use Doctrine\ORM\QueryBuilder;
|
||||||
|
use Happyr\DoctrineSpecification\EntitySpecificationRepository;
|
||||||
|
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||||
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
|
use Shlinkio\Shlink\Common\Doctrine\Type\ChronosDateTimeType;
|
||||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
|
@ -19,7 +20,7 @@ use function array_key_exists;
|
||||||
use function count;
|
use function count;
|
||||||
use function Functional\contains;
|
use function Functional\contains;
|
||||||
|
|
||||||
class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryInterface
|
class ShortUrlRepository extends EntitySpecificationRepository implements ShortUrlRepositoryInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string[] $tags
|
* @param string[] $tags
|
||||||
|
@ -31,9 +32,10 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
?string $searchTerm = null,
|
?string $searchTerm = null,
|
||||||
array $tags = [],
|
array $tags = [],
|
||||||
?ShortUrlsOrdering $orderBy = null,
|
?ShortUrlsOrdering $orderBy = null,
|
||||||
?DateRange $dateRange = null
|
?DateRange $dateRange = null,
|
||||||
|
?Specification $spec = null
|
||||||
): array {
|
): array {
|
||||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange);
|
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange, $spec);
|
||||||
$qb->select('DISTINCT s')
|
$qb->select('DISTINCT s')
|
||||||
->setMaxResults($limit)
|
->setMaxResults($limit)
|
||||||
->setFirstResult($offset);
|
->setFirstResult($offset);
|
||||||
|
@ -75,9 +77,13 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
return $qb->getQuery()->getResult();
|
return $qb->getQuery()->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function countList(?string $searchTerm = null, array $tags = [], ?DateRange $dateRange = null): int
|
public function countList(
|
||||||
{
|
?string $searchTerm = null,
|
||||||
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange);
|
array $tags = [],
|
||||||
|
?DateRange $dateRange = null,
|
||||||
|
?Specification $spec = null
|
||||||
|
): int {
|
||||||
|
$qb = $this->createListQueryBuilder($searchTerm, $tags, $dateRange, $spec);
|
||||||
$qb->select('COUNT(DISTINCT s)');
|
$qb->select('COUNT(DISTINCT s)');
|
||||||
|
|
||||||
return (int) $qb->getQuery()->getSingleScalarResult();
|
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||||
|
@ -86,7 +92,8 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
private function createListQueryBuilder(
|
private function createListQueryBuilder(
|
||||||
?string $searchTerm = null,
|
?string $searchTerm = null,
|
||||||
array $tags = [],
|
array $tags = [],
|
||||||
?DateRange $dateRange = null
|
?DateRange $dateRange = null,
|
||||||
|
?Specification $spec = null
|
||||||
): QueryBuilder {
|
): QueryBuilder {
|
||||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||||
$qb->from(ShortUrl::class, 's')
|
$qb->from(ShortUrl::class, 's')
|
||||||
|
@ -125,6 +132,10 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI
|
||||||
->andWhere($qb->expr()->in('t.name', $tags));
|
->andWhere($qb->expr()->in('t.name', $tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($spec) {
|
||||||
|
$this->applySpecification($qb, $spec, 's');
|
||||||
|
}
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,15 @@ declare(strict_types=1);
|
||||||
namespace Shlinkio\Shlink\Core\Repository;
|
namespace Shlinkio\Shlink\Core\Repository;
|
||||||
|
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
use Happyr\DoctrineSpecification\EntitySpecificationRepositoryInterface;
|
||||||
|
use Happyr\DoctrineSpecification\Specification\Specification;
|
||||||
use Shlinkio\Shlink\Common\Util\DateRange;
|
use Shlinkio\Shlink\Common\Util\DateRange;
|
||||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
use Shlinkio\Shlink\Core\Model\ShortUrlMeta;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering;
|
use Shlinkio\Shlink\Core\Model\ShortUrlsOrdering;
|
||||||
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
|
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
|
||||||
|
|
||||||
interface ShortUrlRepositoryInterface extends ObjectRepository
|
interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
|
||||||
{
|
{
|
||||||
public function findList(
|
public function findList(
|
||||||
?int $limit = null,
|
?int $limit = null,
|
||||||
|
@ -19,10 +21,16 @@ interface ShortUrlRepositoryInterface extends ObjectRepository
|
||||||
?string $searchTerm = null,
|
?string $searchTerm = null,
|
||||||
array $tags = [],
|
array $tags = [],
|
||||||
?ShortUrlsOrdering $orderBy = null,
|
?ShortUrlsOrdering $orderBy = null,
|
||||||
?DateRange $dateRange = null
|
?DateRange $dateRange = null,
|
||||||
|
?Specification $spec = null
|
||||||
): array;
|
): array;
|
||||||
|
|
||||||
public function countList(?string $searchTerm = null, array $tags = [], ?DateRange $dateRange = null): int;
|
public function countList(
|
||||||
|
?string $searchTerm = null,
|
||||||
|
array $tags = [],
|
||||||
|
?DateRange $dateRange = null,
|
||||||
|
?Specification $spec = null
|
||||||
|
): int;
|
||||||
|
|
||||||
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
|
||||||
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
||||||
use Shlinkio\Shlink\Core\Util\TagManagerTrait;
|
use Shlinkio\Shlink\Core\Util\TagManagerTrait;
|
||||||
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
|
use Shlinkio\Shlink\Core\Util\UrlValidatorInterface;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ShortUrlService implements ShortUrlServiceInterface
|
class ShortUrlService implements ShortUrlServiceInterface
|
||||||
{
|
{
|
||||||
|
@ -39,11 +40,11 @@ class ShortUrlService implements ShortUrlServiceInterface
|
||||||
/**
|
/**
|
||||||
* @return ShortUrl[]|Paginator
|
* @return ShortUrl[]|Paginator
|
||||||
*/
|
*/
|
||||||
public function listShortUrls(ShortUrlsParams $params): Paginator
|
public function listShortUrls(ShortUrlsParams $params, ?ApiKey $apiKey = null): Paginator
|
||||||
{
|
{
|
||||||
/** @var ShortUrlRepository $repo */
|
/** @var ShortUrlRepository $repo */
|
||||||
$repo = $this->em->getRepository(ShortUrl::class);
|
$repo = $this->em->getRepository(ShortUrl::class);
|
||||||
$paginator = new Paginator(new ShortUrlRepositoryAdapter($repo, $params));
|
$paginator = new Paginator(new ShortUrlRepositoryAdapter($repo, $params, $apiKey));
|
||||||
$paginator->setItemCountPerPage($params->itemsPerPage())
|
$paginator->setItemCountPerPage($params->itemsPerPage())
|
||||||
->setCurrentPageNumber($params->page());
|
->setCurrentPageNumber($params->page());
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,14 @@ use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlEdit;
|
use Shlinkio\Shlink\Core\Model\ShortUrlEdit;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
interface ShortUrlServiceInterface
|
interface ShortUrlServiceInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return ShortUrl[]|Paginator
|
* @return ShortUrl[]|Paginator
|
||||||
*/
|
*/
|
||||||
public function listShortUrls(ShortUrlsParams $params): Paginator;
|
public function listShortUrls(ShortUrlsParams $params, ?ApiKey $apiKey = null): Paginator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string[] $tags
|
* @param string[] $tags
|
||||||
|
|
|
@ -11,6 +11,7 @@ use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||||
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
|
use Shlinkio\Shlink\Core\Paginator\Adapter\ShortUrlRepositoryAdapter;
|
||||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
use Shlinkio\Shlink\Core\Repository\ShortUrlRepositoryInterface;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ShortUrlRepositoryAdapterTest extends TestCase
|
class ShortUrlRepositoryAdapterTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -41,11 +42,11 @@ class ShortUrlRepositoryAdapterTest extends TestCase
|
||||||
'endDate' => $endDate,
|
'endDate' => $endDate,
|
||||||
'orderBy' => $orderBy,
|
'orderBy' => $orderBy,
|
||||||
]);
|
]);
|
||||||
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params);
|
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params, null);
|
||||||
$orderBy = $params->orderBy();
|
$orderBy = $params->orderBy();
|
||||||
$dateRange = $params->dateRange();
|
$dateRange = $params->dateRange();
|
||||||
|
|
||||||
$this->repo->findList(10, 5, $searchTerm, $tags, $orderBy, $dateRange)->shouldBeCalledOnce();
|
$this->repo->findList(10, 5, $searchTerm, $tags, $orderBy, $dateRange, null)->shouldBeCalledOnce();
|
||||||
$adapter->getItems(5, 10);
|
$adapter->getItems(5, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +66,11 @@ class ShortUrlRepositoryAdapterTest extends TestCase
|
||||||
'startDate' => $startDate,
|
'startDate' => $startDate,
|
||||||
'endDate' => $endDate,
|
'endDate' => $endDate,
|
||||||
]);
|
]);
|
||||||
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params);
|
$apiKey = new ApiKey();
|
||||||
|
$adapter = new ShortUrlRepositoryAdapter($this->repo->reveal(), $params, $apiKey);
|
||||||
$dateRange = $params->dateRange();
|
$dateRange = $params->dateRange();
|
||||||
|
|
||||||
$this->repo->countList($searchTerm, $tags, $dateRange)->shouldBeCalledOnce();
|
$this->repo->countList($searchTerm, $tags, $dateRange, $apiKey->spec())->shouldBeCalledOnce();
|
||||||
$adapter->count();
|
$adapter->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||||
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
use Shlinkio\Shlink\Core\Service\ShortUrlServiceInterface;
|
||||||
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
|
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
|
||||||
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||||
|
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
|
||||||
|
|
||||||
class ListShortUrlsAction extends AbstractRestAction
|
class ListShortUrlsAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
|
@ -31,7 +32,10 @@ class ListShortUrlsAction extends AbstractRestAction
|
||||||
|
|
||||||
public function handle(Request $request): Response
|
public function handle(Request $request): Response
|
||||||
{
|
{
|
||||||
$shortUrls = $this->shortUrlService->listShortUrls(ShortUrlsParams::fromRawData($request->getQueryParams()));
|
$shortUrls = $this->shortUrlService->listShortUrls(
|
||||||
|
ShortUrlsParams::fromRawData($request->getQueryParams()),
|
||||||
|
AuthenticationMiddleware::apiKeyFromRequest($request),
|
||||||
|
);
|
||||||
return new JsonResponse(['shortUrls' => $this->serializePaginator($shortUrls, new ShortUrlDataTransformer(
|
return new JsonResponse(['shortUrls' => $this->serializePaginator($shortUrls, new ShortUrlDataTransformer(
|
||||||
$this->domainConfig,
|
$this->domainConfig,
|
||||||
))]);
|
))]);
|
||||||
|
|
|
@ -15,6 +15,7 @@ use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
use Shlinkio\Shlink\Core\Model\ShortUrlsParams;
|
||||||
use Shlinkio\Shlink\Core\Service\ShortUrlService;
|
use Shlinkio\Shlink\Core\Service\ShortUrlService;
|
||||||
use Shlinkio\Shlink\Rest\Action\ShortUrl\ListShortUrlsAction;
|
use Shlinkio\Shlink\Rest\Action\ShortUrl\ListShortUrlsAction;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ListShortUrlsActionTest extends TestCase
|
class ListShortUrlsActionTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,8 @@ class ListShortUrlsActionTest extends TestCase
|
||||||
?string $startDate = null,
|
?string $startDate = null,
|
||||||
?string $endDate = null
|
?string $endDate = null
|
||||||
): void {
|
): void {
|
||||||
|
$apiKey = new ApiKey();
|
||||||
|
$request = (new ServerRequest())->withQueryParams($query)->withAttribute(ApiKey::class, $apiKey);
|
||||||
$listShortUrls = $this->service->listShortUrls(ShortUrlsParams::fromRawData([
|
$listShortUrls = $this->service->listShortUrls(ShortUrlsParams::fromRawData([
|
||||||
'page' => $expectedPage,
|
'page' => $expectedPage,
|
||||||
'searchTerm' => $expectedSearchTerm,
|
'searchTerm' => $expectedSearchTerm,
|
||||||
|
@ -53,10 +56,10 @@ class ListShortUrlsActionTest extends TestCase
|
||||||
'orderBy' => $expectedOrderBy,
|
'orderBy' => $expectedOrderBy,
|
||||||
'startDate' => $startDate,
|
'startDate' => $startDate,
|
||||||
'endDate' => $endDate,
|
'endDate' => $endDate,
|
||||||
]))->willReturn(new Paginator(new ArrayAdapter()));
|
]), $apiKey)->willReturn(new Paginator(new ArrayAdapter()));
|
||||||
|
|
||||||
/** @var JsonResponse $response */
|
/** @var JsonResponse $response */
|
||||||
$response = $this->action->handle((new ServerRequest())->withQueryParams($query));
|
$response = $this->action->handle($request);
|
||||||
$payload = $response->getPayload();
|
$payload = $response->getPayload();
|
||||||
|
|
||||||
self::assertArrayHasKey('shortUrls', $payload);
|
self::assertArrayHasKey('shortUrls', $payload);
|
||||||
|
|
Loading…
Reference in a new issue