mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-26 02:40:41 -06:00
Applied API role specs to single short URL resolution
This commit is contained in:
parent
940383646b
commit
dc08286a72
@ -90,10 +90,10 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function createListQueryBuilder(
|
private function createListQueryBuilder(
|
||||||
?string $searchTerm = null,
|
?string $searchTerm,
|
||||||
array $tags = [],
|
array $tags,
|
||||||
?DateRange $dateRange = null,
|
?DateRange $dateRange,
|
||||||
?Specification $spec = null
|
?Specification $spec
|
||||||
): QueryBuilder {
|
): QueryBuilder {
|
||||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||||
$qb->from(ShortUrl::class, 's')
|
$qb->from(ShortUrl::class, 's')
|
||||||
@ -171,9 +171,9 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||||||
return $query->getOneOrNullResult();
|
return $query->getOneOrNullResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findOne(string $shortCode, ?string $domain = null): ?ShortUrl
|
public function findOne(string $shortCode, ?string $domain = null, ?Specification $spec = null): ?ShortUrl
|
||||||
{
|
{
|
||||||
$qb = $this->createFindOneQueryBuilder($shortCode, $domain);
|
$qb = $this->createFindOneQueryBuilder($shortCode, $domain, $spec);
|
||||||
$qb->select('s');
|
$qb->select('s');
|
||||||
|
|
||||||
return $qb->getQuery()->getOneOrNullResult();
|
return $qb->getQuery()->getOneOrNullResult();
|
||||||
@ -181,13 +181,13 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||||||
|
|
||||||
public function shortCodeIsInUse(string $slug, ?string $domain = null): bool
|
public function shortCodeIsInUse(string $slug, ?string $domain = null): bool
|
||||||
{
|
{
|
||||||
$qb = $this->createFindOneQueryBuilder($slug, $domain);
|
$qb = $this->createFindOneQueryBuilder($slug, $domain, null);
|
||||||
$qb->select('COUNT(DISTINCT s.id)');
|
$qb->select('COUNT(DISTINCT s.id)');
|
||||||
|
|
||||||
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
|
return ((int) $qb->getQuery()->getSingleScalarResult()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createFindOneQueryBuilder(string $slug, ?string $domain = null): QueryBuilder
|
private function createFindOneQueryBuilder(string $slug, ?string $domain, ?Specification $spec): QueryBuilder
|
||||||
{
|
{
|
||||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||||
$qb->from(ShortUrl::class, 's')
|
$qb->from(ShortUrl::class, 's')
|
||||||
@ -198,6 +198,10 @@ class ShortUrlRepository extends EntitySpecificationRepository implements ShortU
|
|||||||
|
|
||||||
$this->whereDomainIs($qb, $domain);
|
$this->whereDomainIs($qb, $domain);
|
||||||
|
|
||||||
|
if ($spec !== null) {
|
||||||
|
$this->applySpecification($qb, $spec, 's');
|
||||||
|
}
|
||||||
|
|
||||||
return $qb;
|
return $qb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ interface ShortUrlRepositoryInterface extends ObjectRepository, EntitySpecificat
|
|||||||
|
|
||||||
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
public function findOneWithDomainFallback(string $shortCode, ?string $domain = null): ?ShortUrl;
|
||||||
|
|
||||||
public function findOne(string $shortCode, ?string $domain = null): ?ShortUrl;
|
public function findOne(string $shortCode, ?string $domain = null, ?Specification $spec = null): ?ShortUrl;
|
||||||
|
|
||||||
public function shortCodeIsInUse(string $slug, ?string $domain): bool;
|
public function shortCodeIsInUse(string $slug, ?string $domain): bool;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
|||||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||||
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
|
use Shlinkio\Shlink\Core\Repository\ShortUrlRepository;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ShortUrlResolver implements ShortUrlResolverInterface
|
class ShortUrlResolver implements ShortUrlResolverInterface
|
||||||
{
|
{
|
||||||
@ -22,11 +23,15 @@ class ShortUrlResolver implements ShortUrlResolverInterface
|
|||||||
/**
|
/**
|
||||||
* @throws ShortUrlNotFoundException
|
* @throws ShortUrlNotFoundException
|
||||||
*/
|
*/
|
||||||
public function resolveShortUrl(ShortUrlIdentifier $identifier): ShortUrl
|
public function resolveShortUrl(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): ShortUrl
|
||||||
{
|
{
|
||||||
/** @var ShortUrlRepository $shortUrlRepo */
|
/** @var ShortUrlRepository $shortUrlRepo */
|
||||||
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);
|
$shortUrlRepo = $this->em->getRepository(ShortUrl::class);
|
||||||
$shortUrl = $shortUrlRepo->findOne($identifier->shortCode(), $identifier->domain());
|
$shortUrl = $shortUrlRepo->findOne(
|
||||||
|
$identifier->shortCode(),
|
||||||
|
$identifier->domain(),
|
||||||
|
$apiKey !== null ? $apiKey->spec() : null,
|
||||||
|
);
|
||||||
if ($shortUrl === null) {
|
if ($shortUrl === null) {
|
||||||
throw ShortUrlNotFoundException::fromNotFound($identifier);
|
throw ShortUrlNotFoundException::fromNotFound($identifier);
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,14 @@ namespace Shlinkio\Shlink\Core\Service\ShortUrl;
|
|||||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
use Shlinkio\Shlink\Core\Exception\ShortUrlNotFoundException;
|
||||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
interface ShortUrlResolverInterface
|
interface ShortUrlResolverInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @throws ShortUrlNotFoundException
|
* @throws ShortUrlNotFoundException
|
||||||
*/
|
*/
|
||||||
public function resolveShortUrl(ShortUrlIdentifier $identifier): ShortUrl;
|
public function resolveShortUrl(ShortUrlIdentifier $identifier, ?ApiKey $apiKey = null): ShortUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws ShortUrlNotFoundException
|
* @throws ShortUrlNotFoundException
|
||||||
|
@ -42,7 +42,7 @@ class ShortUrlResolverTest extends TestCase
|
|||||||
$shortCode = $shortUrl->getShortCode();
|
$shortCode = $shortUrl->getShortCode();
|
||||||
|
|
||||||
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||||
$findOne = $repo->findOne($shortCode, null)->willReturn($shortUrl);
|
$findOne = $repo->findOne($shortCode, null, null)->willReturn($shortUrl);
|
||||||
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
||||||
|
|
||||||
$result = $this->urlResolver->resolveShortUrl(new ShortUrlIdentifier($shortCode));
|
$result = $this->urlResolver->resolveShortUrl(new ShortUrlIdentifier($shortCode));
|
||||||
@ -58,7 +58,7 @@ class ShortUrlResolverTest extends TestCase
|
|||||||
$shortCode = 'abc123';
|
$shortCode = 'abc123';
|
||||||
|
|
||||||
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
$repo = $this->prophesize(ShortUrlRepositoryInterface::class);
|
||||||
$findOne = $repo->findOne($shortCode, null)->willReturn(null);
|
$findOne = $repo->findOne($shortCode, null, null)->willReturn(null);
|
||||||
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
$getRepo = $this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
|
||||||
|
|
||||||
$this->expectException(ShortUrlNotFoundException::class);
|
$this->expectException(ShortUrlNotFoundException::class);
|
||||||
|
@ -11,6 +11,7 @@ use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
|||||||
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
||||||
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 ResolveShortUrlAction extends AbstractRestAction
|
class ResolveShortUrlAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
@ -29,7 +30,10 @@ class ResolveShortUrlAction extends AbstractRestAction
|
|||||||
public function handle(Request $request): Response
|
public function handle(Request $request): Response
|
||||||
{
|
{
|
||||||
$transformer = new ShortUrlDataTransformer($this->domainConfig);
|
$transformer = new ShortUrlDataTransformer($this->domainConfig);
|
||||||
$url = $this->urlResolver->resolveShortUrl(ShortUrlIdentifier::fromApiRequest($request));
|
$url = $this->urlResolver->resolveShortUrl(
|
||||||
|
ShortUrlIdentifier::fromApiRequest($request),
|
||||||
|
AuthenticationMiddleware::apiKeyFromRequest($request),
|
||||||
|
);
|
||||||
|
|
||||||
return new JsonResponse($transformer->transform($url));
|
return new JsonResponse($transformer->transform($url));
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
|||||||
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
use Shlinkio\Shlink\Core\Model\ShortUrlIdentifier;
|
||||||
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
use Shlinkio\Shlink\Core\Service\ShortUrl\ShortUrlResolverInterface;
|
||||||
use Shlinkio\Shlink\Rest\Action\ShortUrl\ResolveShortUrlAction;
|
use Shlinkio\Shlink\Rest\Action\ShortUrl\ResolveShortUrlAction;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
use function strpos;
|
use function strpos;
|
||||||
|
|
||||||
@ -32,12 +33,14 @@ class ResolveShortUrlActionTest extends TestCase
|
|||||||
public function correctShortCodeReturnsSuccess(): void
|
public function correctShortCodeReturnsSuccess(): void
|
||||||
{
|
{
|
||||||
$shortCode = 'abc123';
|
$shortCode = 'abc123';
|
||||||
$this->urlResolver->resolveShortUrl(new ShortUrlIdentifier($shortCode))->willReturn(
|
$apiKey = new ApiKey();
|
||||||
|
$this->urlResolver->resolveShortUrl(new ShortUrlIdentifier($shortCode), $apiKey)->willReturn(
|
||||||
new ShortUrl('http://domain.com/foo/bar'),
|
new ShortUrl('http://domain.com/foo/bar'),
|
||||||
)->shouldBeCalledOnce();
|
)->shouldBeCalledOnce();
|
||||||
|
|
||||||
$request = (new ServerRequest())->withAttribute('shortCode', $shortCode);
|
$request = (new ServerRequest())->withAttribute('shortCode', $shortCode)->withAttribute(ApiKey::class, $apiKey);
|
||||||
$response = $this->action->handle($request);
|
$response = $this->action->handle($request);
|
||||||
|
|
||||||
self::assertEquals(200, $response->getStatusCode());
|
self::assertEquals(200, $response->getStatusCode());
|
||||||
self::assertTrue(strpos($response->getBody()->getContents(), 'http://domain.com/foo/bar') > 0);
|
self::assertTrue(strpos($response->getBody()->getContents(), 'http://domain.com/foo/bar') > 0);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user