mirror of
https://github.com/shlinkio/shlink.git
synced 2024-11-26 23:18:37 +03:00
Updated services required to initialize API keys with roles
This commit is contained in:
parent
95e51665b1
commit
c9ff2b3834
7 changed files with 70 additions and 9 deletions
|
@ -30,7 +30,7 @@
|
|||
"laminas/laminas-diactoros": "^2.1.3",
|
||||
"laminas/laminas-inputfilter": "^2.10",
|
||||
"laminas/laminas-paginator": "^2.8",
|
||||
"laminas/laminas-servicemanager": "^3.4",
|
||||
"laminas/laminas-servicemanager": "^3.6",
|
||||
"laminas/laminas-stdlib": "^3.2",
|
||||
"lcobucci/jwt": "^4.0",
|
||||
"league/uri": "^6.2",
|
||||
|
|
|
@ -45,6 +45,9 @@ class DomainService implements DomainServiceInterface
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DomainNotFoundException
|
||||
*/
|
||||
public function getDomain(string $domainId): Domain
|
||||
{
|
||||
/** @var Domain|null $domain */
|
||||
|
@ -55,4 +58,16 @@ class DomainService implements DomainServiceInterface
|
|||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
public function getOrCreate(string $authority): Domain
|
||||
{
|
||||
$repo = $this->em->getRepository(Domain::class);
|
||||
/** @var Domain|null $domain */
|
||||
$domain = $repo->findOneBy(['authority' => $authority]) ?? new Domain($authority);
|
||||
|
||||
$this->em->persist($domain);
|
||||
$this->em->flush();
|
||||
|
||||
return $domain;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\Core\Domain;
|
|||
|
||||
use Shlinkio\Shlink\Core\Domain\Model\DomainItem;
|
||||
use Shlinkio\Shlink\Core\Entity\Domain;
|
||||
use Shlinkio\Shlink\Core\Exception\DomainNotFoundException;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
interface DomainServiceInterface
|
||||
|
@ -15,5 +16,10 @@ interface DomainServiceInterface
|
|||
*/
|
||||
public function listDomains(?ApiKey $apiKey = null): array;
|
||||
|
||||
/**
|
||||
* @throws DomainNotFoundException
|
||||
*/
|
||||
public function getDomain(string $domainId): Domain;
|
||||
|
||||
public function getOrCreate(string $authority): Domain;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace ShlinkioTest\Shlink\Core\Domain;
|
|||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Shlinkio\Shlink\Core\Domain\DomainService;
|
||||
|
@ -111,4 +112,33 @@ class DomainServiceTest extends TestCase
|
|||
self::assertSame($domain, $result);
|
||||
$find->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @dataProvider provideFoundDomains
|
||||
*/
|
||||
public function getOrCreateAlwaysPersistsDomain(?Domain $foundDomain): void
|
||||
{
|
||||
$authority = 'example.com';
|
||||
$repo = $this->prophesize(DomainRepositoryInterface::class);
|
||||
$repo->findOneBy(['authority' => $authority])->willReturn($foundDomain);
|
||||
$getRepo = $this->em->getRepository(Domain::class)->willReturn($repo->reveal());
|
||||
$persist = $this->em->persist($foundDomain !== null ? $foundDomain : Argument::type(Domain::class));
|
||||
$flush = $this->em->flush();
|
||||
|
||||
$result = $this->domainService->getOrCreate($authority);
|
||||
|
||||
if ($foundDomain !== null) {
|
||||
self::assertSame($result, $foundDomain);
|
||||
}
|
||||
$getRepo->shouldHaveBeenCalledOnce();
|
||||
$persist->shouldHaveBeenCalledOnce();
|
||||
$flush->shouldHaveBeenCalledOnce();
|
||||
}
|
||||
|
||||
public function provideFoundDomains(): iterable
|
||||
{
|
||||
yield 'domain not found' => [null];
|
||||
yield 'domain found' => [new Domain('')];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Shlinkio\Shlink\Rest\Service;
|
|||
use Cake\Chronos\Chronos;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
||||
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
use function sprintf;
|
||||
|
@ -20,9 +21,13 @@ class ApiKeyService implements ApiKeyServiceInterface
|
|||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function create(?Chronos $expirationDate = null): ApiKey
|
||||
public function create(?Chronos $expirationDate = null, RoleDefinition ...$roleDefinitions): ApiKey
|
||||
{
|
||||
$key = new ApiKey($expirationDate);
|
||||
foreach ($roleDefinitions as $definition) {
|
||||
$key->registerRole($definition);
|
||||
}
|
||||
|
||||
$this->em->persist($key);
|
||||
$this->em->flush();
|
||||
|
||||
|
@ -31,7 +36,6 @@ class ApiKeyService implements ApiKeyServiceInterface
|
|||
|
||||
public function check(string $key): ApiKeyCheckResult
|
||||
{
|
||||
/** @var ApiKey|null $apiKey */
|
||||
$apiKey = $this->getByKey($key);
|
||||
return new ApiKeyCheckResult($apiKey);
|
||||
}
|
||||
|
@ -41,7 +45,6 @@ class ApiKeyService implements ApiKeyServiceInterface
|
|||
*/
|
||||
public function disable(string $key): ApiKey
|
||||
{
|
||||
/** @var ApiKey|null $apiKey */
|
||||
$apiKey = $this->getByKey($key);
|
||||
if ($apiKey === null) {
|
||||
throw new InvalidArgumentException(sprintf('API key "%s" does not exist and can\'t be disabled', $key));
|
||||
|
|
|
@ -6,11 +6,12 @@ namespace Shlinkio\Shlink\Rest\Service;
|
|||
|
||||
use Cake\Chronos\Chronos;
|
||||
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
||||
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
|
||||
interface ApiKeyServiceInterface
|
||||
{
|
||||
public function create(?Chronos $expirationDate = null): ApiKey;
|
||||
public function create(?Chronos $expirationDate = null, RoleDefinition ...$roleDefinitions): ApiKey;
|
||||
|
||||
public function check(string $key): ApiKeyCheckResult;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ use Prophecy\Argument;
|
|||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Prophecy\Prophecy\ObjectProphecy;
|
||||
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
||||
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
|
||||
use Shlinkio\Shlink\Rest\Entity\ApiKey;
|
||||
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
|
||||
|
||||
|
@ -31,21 +32,26 @@ class ApiKeyServiceTest extends TestCase
|
|||
/**
|
||||
* @test
|
||||
* @dataProvider provideCreationDate
|
||||
* @param RoleDefinition[] $roles
|
||||
*/
|
||||
public function apiKeyIsProperlyCreated(?Chronos $date): void
|
||||
public function apiKeyIsProperlyCreated(?Chronos $date, array $roles): void
|
||||
{
|
||||
$this->em->flush()->shouldBeCalledOnce();
|
||||
$this->em->persist(Argument::type(ApiKey::class))->shouldBeCalledOnce();
|
||||
|
||||
$key = $this->service->create($date);
|
||||
$key = $this->service->create($date, ...$roles);
|
||||
|
||||
self::assertEquals($date, $key->getExpirationDate());
|
||||
foreach ($roles as $roleDefinition) {
|
||||
self::assertTrue($key->hasRole($roleDefinition->roleName()));
|
||||
}
|
||||
}
|
||||
|
||||
public function provideCreationDate(): iterable
|
||||
{
|
||||
yield 'no expiration date' => [null];
|
||||
yield 'expiration date' => [Chronos::parse('2030-01-01')];
|
||||
yield 'no expiration date' => [null, []];
|
||||
yield 'expiration date' => [Chronos::parse('2030-01-01'), []];
|
||||
yield 'roles' => [null, [RoleDefinition::forDomain('123'), RoleDefinition::forAuthoredShortUrls()]];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue