Move logic to determine if a new key has a duplicated name to the APiKeyService

This commit is contained in:
Alejandro Celaya
2024-11-08 09:03:50 +01:00
parent b08c498b13
commit 6f837b3b91
6 changed files with 38 additions and 50 deletions

View File

@@ -21,7 +21,13 @@ readonly class ApiKeyService implements ApiKeyServiceInterface
public function create(ApiKeyMeta $apiKeyMeta): ApiKey
{
// TODO If name is auto-generated, do not throw. Instead, re-generate a new key
$apiKey = ApiKey::fromMeta($apiKeyMeta);
if ($this->existsWithName($apiKey->name)) {
throw new InvalidArgumentException(
sprintf('Another API key with name "%s" already exists', $apiKeyMeta->name),
);
}
$this->em->persist($apiKey);
$this->em->flush();
@@ -77,14 +83,6 @@ readonly class ApiKeyService implements ApiKeyServiceInterface
return $this->repo->findBy($conditions);
}
/**
* @inheritDoc
*/
public function existsWithName(string $apiKeyName): bool
{
return $this->repo->count(['name' => $apiKeyName]) > 0;
}
/**
* @inheritDoc
* @todo This method should be transactional and to a SELECT ... FROM UPDATE when checking if the new name exists,
@@ -120,4 +118,9 @@ readonly class ApiKeyService implements ApiKeyServiceInterface
{
return $this->repo->findOneBy(['key' => ApiKey::hashKey($key)]);
}
private function existsWithName(string $apiKeyName): bool
{
return $this->repo->count(['name' => $apiKeyName]) > 0;
}
}

View File

@@ -33,11 +33,6 @@ interface ApiKeyServiceInterface
*/
public function listKeys(bool $enabledOnly = false): array;
/**
* Check if an API key exists for provided name
*/
public function existsWithName(string $apiKeyName): bool;
/**
* @throws InvalidArgumentException If an API key with oldName does not exist, or newName is in use by another one
*/

View File

@@ -8,7 +8,6 @@ use Cake\Chronos\Chronos;
use Doctrine\ORM\EntityManager;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestWith;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
@@ -41,6 +40,9 @@ class ApiKeyServiceTest extends TestCase
#[Test, DataProvider('provideCreationDate')]
public function apiKeyIsProperlyCreated(Chronos|null $date, string|null $name, array $roles): void
{
$this->repo->expects($this->once())->method('count')->with(
! empty($name) ? ['name' => $name] : $this->isType('array'),
)->willReturn(0);
$this->em->expects($this->once())->method('flush');
$this->em->expects($this->once())->method('persist')->with($this->isInstanceOf(ApiKey::class));
@@ -73,6 +75,19 @@ class ApiKeyServiceTest extends TestCase
yield 'empty name' => [null, '', []];
}
#[Test]
public function exceptionIsThrownWhileCreatingIfNameIsInUse(): void
{
$this->repo->expects($this->once())->method('count')->with(['name' => 'the_name'])->willReturn(1);
$this->em->expects($this->never())->method('flush');
$this->em->expects($this->never())->method('persist');
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Another API key with name "the_name" already exists');
$this->service->create(ApiKeyMeta::fromParams(name: 'the_name'));
}
#[Test, DataProvider('provideInvalidApiKeys')]
public function checkReturnsFalseForInvalidApiKeys(ApiKey|null $invalidKey): void
{
@@ -179,17 +194,6 @@ class ApiKeyServiceTest extends TestCase
yield 'existing api keys' => [null];
}
#[Test]
#[TestWith([0, false])]
#[TestWith([1, true])]
#[TestWith([27, true])]
public function existsWithNameCountsEntriesInRepository(int $count, bool $expected): void
{
$name = 'the_key';
$this->repo->expects($this->once())->method('count')->with(['name' => $name])->willReturn($count);
self::assertEquals($this->service->existsWithName($name), $expected);
}
#[Test]
public function renameApiKeyThrowsExceptionIfApiKeyIsNotFound(): void
{