New CLI command to create the initial API key idempotently

This commit is contained in:
Alejandro Celaya
2023-09-21 09:29:59 +02:00
parent 6db46b50e9
commit 637d8334f4
14 changed files with 84 additions and 129 deletions

View File

@@ -11,10 +11,13 @@ use Shlinkio\Shlink\Rest\Entity\ApiKey;
class ApiKeyRepository extends EntitySpecificationRepository implements ApiKeyRepositoryInterface
{
public function createInitialApiKey(string $apiKey): void
/**
* Will create provided API key with admin permissions, only if there's no other API keys yet
*/
public function createInitialApiKey(string $apiKey): ?ApiKey
{
$em = $this->getEntityManager();
$em->wrapInTransaction(function () use ($apiKey, $em): void {
return $em->wrapInTransaction(function () use ($apiKey, $em): ?ApiKey {
// Ideally this would be a SELECT COUNT(...), but MsSQL and Postgres do not allow locking on aggregates
// Because of that we check if at least one result exists
$firstResult = $em->createQueryBuilder()->select('a.id')
@@ -24,10 +27,16 @@ class ApiKeyRepository extends EntitySpecificationRepository implements ApiKeyRe
->setLockMode(LockMode::PESSIMISTIC_WRITE)
->getOneOrNullResult();
if ($firstResult === null) {
$em->persist(ApiKey::fromMeta(ApiKeyMeta::fromParams(key: $apiKey)));
$em->flush();
// Do not create an initial API key if other keys already exist
if ($firstResult !== null) {
return null;
}
$new = ApiKey::fromMeta(ApiKeyMeta::fromParams(key: $apiKey));
$em->persist($new);
$em->flush();
return $new;
});
}
}