mirror of
https://github.com/shlinkio/shlink.git
synced 2025-03-29 04:52:54 +03:00
Applied API role specs to domains list
This commit is contained in:
parent
262a06f624
commit
19834f6715
9 changed files with 40 additions and 16 deletions
|
@ -8,6 +8,8 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
||||||
use Shlinkio\Shlink\Core\Domain\Repository\DomainRepositoryInterface;
|
use Shlinkio\Shlink\Core\Domain\Repository\DomainRepositoryInterface;
|
||||||
use Shlinkio\Shlink\Core\Entity\Domain;
|
use Shlinkio\Shlink\Core\Entity\Domain;
|
||||||
|
use Shlinkio\Shlink\Rest\ApiKey\Role;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
use function Functional\map;
|
use function Functional\map;
|
||||||
|
|
||||||
|
@ -25,15 +27,20 @@ class DomainService implements DomainServiceInterface
|
||||||
/**
|
/**
|
||||||
* @return DomainItem[]
|
* @return DomainItem[]
|
||||||
*/
|
*/
|
||||||
public function listDomains(): array
|
public function listDomains(?ApiKey $apiKey = null): array
|
||||||
{
|
{
|
||||||
/** @var DomainRepositoryInterface $repo */
|
/** @var DomainRepositoryInterface $repo */
|
||||||
$repo = $this->em->getRepository(Domain::class);
|
$repo = $this->em->getRepository(Domain::class);
|
||||||
$domains = $repo->findDomainsWithout($this->defaultDomain);
|
$domains = $repo->findDomainsWithout($this->defaultDomain, $apiKey);
|
||||||
|
$mappedDomains = map($domains, fn (Domain $domain) => new DomainItem($domain->getAuthority(), false));
|
||||||
|
|
||||||
|
if ($apiKey !== null && $apiKey->hasRole(Role::DOMAIN_SPECIFIC)) {
|
||||||
|
return $mappedDomains;
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
new DomainItem($this->defaultDomain, true),
|
new DomainItem($this->defaultDomain, true),
|
||||||
...map($domains, fn (Domain $domain) => new DomainItem($domain->getAuthority(), false)),
|
...$mappedDomains,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,12 @@ declare(strict_types=1);
|
||||||
namespace Shlinkio\Shlink\Core\Domain;
|
namespace Shlinkio\Shlink\Core\Domain;
|
||||||
|
|
||||||
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
interface DomainServiceInterface
|
interface DomainServiceInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return DomainItem[]
|
* @return DomainItem[]
|
||||||
*/
|
*/
|
||||||
public function listDomains(): array;
|
public function listDomains(?ApiKey $apiKey = null): array;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,17 +4,18 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Shlinkio\Shlink\Core\Domain\Repository;
|
namespace Shlinkio\Shlink\Core\Domain\Repository;
|
||||||
|
|
||||||
use Doctrine\ORM\EntityRepository;
|
|
||||||
use Doctrine\ORM\Query\Expr\Join;
|
use Doctrine\ORM\Query\Expr\Join;
|
||||||
|
use Happyr\DoctrineSpecification\EntitySpecificationRepository;
|
||||||
use Shlinkio\Shlink\Core\Entity\Domain;
|
use Shlinkio\Shlink\Core\Entity\Domain;
|
||||||
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
use Shlinkio\Shlink\Core\Entity\ShortUrl;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class DomainRepository extends EntityRepository implements DomainRepositoryInterface
|
class DomainRepository extends EntitySpecificationRepository implements DomainRepositoryInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Domain[]
|
* @return Domain[]
|
||||||
*/
|
*/
|
||||||
public function findDomainsWithout(?string $excludedAuthority = null): array
|
public function findDomainsWithout(?string $excludedAuthority, ?ApiKey $apiKey = null): array
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('d');
|
$qb = $this->createQueryBuilder('d');
|
||||||
$qb->join(ShortUrl::class, 's', Join::WITH, 's.domain = d')
|
$qb->join(ShortUrl::class, 's', Join::WITH, 's.domain = d')
|
||||||
|
@ -25,6 +26,10 @@ class DomainRepository extends EntityRepository implements DomainRepositoryInter
|
||||||
->setParameter('excludedAuthority', $excludedAuthority);
|
->setParameter('excludedAuthority', $excludedAuthority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($apiKey !== null) {
|
||||||
|
$this->applySpecification($qb, $apiKey->spec(), 's');
|
||||||
|
}
|
||||||
|
|
||||||
return $qb->getQuery()->getResult();
|
return $qb->getQuery()->getResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,14 @@ declare(strict_types=1);
|
||||||
namespace Shlinkio\Shlink\Core\Domain\Repository;
|
namespace Shlinkio\Shlink\Core\Domain\Repository;
|
||||||
|
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
use Happyr\DoctrineSpecification\EntitySpecificationRepositoryInterface;
|
||||||
use Shlinkio\Shlink\Core\Entity\Domain;
|
use Shlinkio\Shlink\Core\Entity\Domain;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
interface DomainRepositoryInterface extends ObjectRepository
|
interface DomainRepositoryInterface extends ObjectRepository, EntitySpecificationRepositoryInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Domain[]
|
* @return Domain[]
|
||||||
*/
|
*/
|
||||||
public function findDomainsWithout(?string $excludedAuthority = null): array;
|
public function findDomainsWithout(?string $excludedAuthority, ?ApiKey $apiKey = null): array;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ class DomainRepositoryTest extends DatabaseTestCase
|
||||||
|
|
||||||
$this->getEntityManager()->flush();
|
$this->getEntityManager()->flush();
|
||||||
|
|
||||||
self::assertEquals([$barDomain, $bazDomain, $fooDomain], $this->repo->findDomainsWithout());
|
self::assertEquals([$barDomain, $bazDomain, $fooDomain], $this->repo->findDomainsWithout(null));
|
||||||
self::assertEquals([$barDomain, $bazDomain], $this->repo->findDomainsWithout('foo.com'));
|
self::assertEquals([$barDomain, $bazDomain], $this->repo->findDomainsWithout('foo.com'));
|
||||||
self::assertEquals([$bazDomain, $fooDomain], $this->repo->findDomainsWithout('bar.com'));
|
self::assertEquals([$bazDomain, $fooDomain], $this->repo->findDomainsWithout('bar.com'));
|
||||||
self::assertEquals([$barDomain, $fooDomain], $this->repo->findDomainsWithout('baz.com'));
|
self::assertEquals([$barDomain, $fooDomain], $this->repo->findDomainsWithout('baz.com'));
|
||||||
|
|
|
@ -34,7 +34,7 @@ class DomainServiceTest extends TestCase
|
||||||
{
|
{
|
||||||
$repo = $this->prophesize(DomainRepositoryInterface::class);
|
$repo = $this->prophesize(DomainRepositoryInterface::class);
|
||||||
$getRepo = $this->em->getRepository(Domain::class)->willReturn($repo->reveal());
|
$getRepo = $this->em->getRepository(Domain::class)->willReturn($repo->reveal());
|
||||||
$findDomains = $repo->findDomainsWithout('default.com')->willReturn($domains);
|
$findDomains = $repo->findDomainsWithout('default.com', null)->willReturn($domains);
|
||||||
|
|
||||||
$result = $this->domainService->listDomains();
|
$result = $this->domainService->listDomains();
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
||||||
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
|
||||||
|
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
|
||||||
|
|
||||||
class ListDomainsAction extends AbstractRestAction
|
class ListDomainsAction extends AbstractRestAction
|
||||||
{
|
{
|
||||||
|
@ -24,7 +25,8 @@ class ListDomainsAction extends AbstractRestAction
|
||||||
|
|
||||||
public function handle(ServerRequestInterface $request): ResponseInterface
|
public function handle(ServerRequestInterface $request): ResponseInterface
|
||||||
{
|
{
|
||||||
$domainItems = $this->domainService->listDomains();
|
$apiKey = AuthenticationMiddleware::apiKeyFromRequest($request);
|
||||||
|
$domainItems = $this->domainService->listDomains($apiKey);
|
||||||
|
|
||||||
return new JsonResponse([
|
return new JsonResponse([
|
||||||
'domains' => [
|
'domains' => [
|
||||||
|
|
|
@ -76,6 +76,11 @@ class ApiKey extends AbstractEntity
|
||||||
|
|
||||||
public function isAdmin(): bool
|
public function isAdmin(): bool
|
||||||
{
|
{
|
||||||
return $this->roles->count() === 0;
|
return $this->roles->isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRole(string $roleName): bool
|
||||||
|
{
|
||||||
|
return $this->roles->exists(fn ($key, ApiKeyRole $role) => $role->name() === $roleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Prophecy\Prophecy\ObjectProphecy;
|
||||||
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
use Shlinkio\Shlink\Core\Domain\DomainServiceInterface;
|
||||||
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
||||||
use Shlinkio\Shlink\Rest\Action\Domain\ListDomainsAction;
|
use Shlinkio\Shlink\Rest\Action\Domain\ListDomainsAction;
|
||||||
|
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||||
|
|
||||||
class ListDomainsActionTest extends TestCase
|
class ListDomainsActionTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -23,20 +24,21 @@ class ListDomainsActionTest extends TestCase
|
||||||
public function setUp(): void
|
public function setUp(): void
|
||||||
{
|
{
|
||||||
$this->domainService = $this->prophesize(DomainServiceInterface::class);
|
$this->domainService = $this->prophesize(DomainServiceInterface::class);
|
||||||
$this->action = new ListDomainsAction($this->domainService->reveal(), 'foo.com');
|
$this->action = new ListDomainsAction($this->domainService->reveal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @test */
|
/** @test */
|
||||||
public function domainsAreProperlyListed(): void
|
public function domainsAreProperlyListed(): void
|
||||||
{
|
{
|
||||||
|
$apiKey = new ApiKey();
|
||||||
$domains = [
|
$domains = [
|
||||||
new DomainItem('bar.com', true),
|
new DomainItem('bar.com', true),
|
||||||
new DomainItem('baz.com', false),
|
new DomainItem('baz.com', false),
|
||||||
];
|
];
|
||||||
$listDomains = $this->domainService->listDomains()->willReturn($domains);
|
$listDomains = $this->domainService->listDomains($apiKey)->willReturn($domains);
|
||||||
|
|
||||||
/** @var JsonResponse $resp */
|
/** @var JsonResponse $resp */
|
||||||
$resp = $this->action->handle(ServerRequestFactory::fromGlobals());
|
$resp = $this->action->handle(ServerRequestFactory::fromGlobals()->withAttribute(ApiKey::class, $apiKey));
|
||||||
$payload = $resp->getPayload();
|
$payload = $resp->getPayload();
|
||||||
|
|
||||||
self::assertEquals([
|
self::assertEquals([
|
||||||
|
|
Loading…
Add table
Reference in a new issue