Added roles info to api key generation and api key list

This commit is contained in:
Alejandro Celaya 2021-01-11 16:32:59 +01:00
parent c49a0ca040
commit 9e9d213f20
12 changed files with 51 additions and 20 deletions

View File

@ -28,7 +28,7 @@ class RoleResolver implements RoleResolverInterface
}
if ($domainAuthority !== null) {
$domain = $this->domainService->getOrCreate($domainAuthority);
$roleDefinitions[] = RoleDefinition::forDomain($domain->getId());
$roleDefinitions[] = RoleDefinition::forDomain($domain);
}
return $roleDefinitions;

View File

@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\CLI\Command\Api;
use Shlinkio\Shlink\CLI\Util\ExitCodes;
use Shlinkio\Shlink\CLI\Util\ShlinkTable;
use Shlinkio\Shlink\Rest\ApiKey\Role;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface;
use Symfony\Component\Console\Command\Command;
@ -14,7 +15,8 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use function array_filter;
use function array_map;
use function Functional\map;
use function implode;
use function sprintf;
class ListKeysCommand extends Command
@ -50,7 +52,7 @@ class ListKeysCommand extends Command
{
$enabledOnly = $input->getOption('enabledOnly');
$rows = array_map(function (ApiKey $apiKey) use ($enabledOnly) {
$rows = map($this->apiKeyService->listKeys($enabledOnly), function (ApiKey $apiKey) use ($enabledOnly) {
$expiration = $apiKey->getExpirationDate();
$messagePattern = $this->determineMessagePattern($apiKey);
@ -60,13 +62,21 @@ class ListKeysCommand extends Command
$rowData[] = sprintf($messagePattern, $this->getEnabledSymbol($apiKey));
}
$rowData[] = $expiration !== null ? $expiration->toAtomString() : '-';
$rowData[] = $apiKey->isAdmin() ? '-' : implode("\n", $apiKey->mapRoles(
fn (string $roleName, array $meta) =>
empty($meta)
? Role::toFriendlyName($roleName)
: sprintf('%s: %s', Role::toFriendlyName($roleName), Role::domainAuthorityFromMeta($meta)),
));
return $rowData;
}, $this->apiKeyService->listKeys($enabledOnly));
});
ShlinkTable::fromOutput($output)->render(array_filter([
'Key',
! $enabledOnly ? 'Is enabled' : null,
'Expiration date',
'Roles',
]), $rows);
return ExitCodes::EXIT_SUCCESS;
}
@ -80,8 +90,6 @@ class ListKeysCommand extends Command
return $apiKey->isExpired() ? self::WARNING_STRING_PATTERN : self::SUCCESS_STRING_PATTERN;
}
/**
*/
private function getEnabledSymbol(ApiKey $apiKey): string
{
return ! $apiKey->isEnabled() || $apiKey->isExpired() ? '---' : '+++';

View File

@ -47,6 +47,7 @@ class RoleResolverTest extends TestCase
public function provideRoles(): iterable
{
$domain = (new Domain('example.com'))->setId('1');
$buildInput = function (array $definition): InputInterface {
$input = $this->prophesize(InputInterface::class);
@ -64,7 +65,7 @@ class RoleResolverTest extends TestCase
];
yield 'domain role only' => [
$buildInput([RoleResolver::DOMAIN_ONLY_PARAM => 'example.com', RoleResolver::AUTHOR_ONLY_PARAM => false]),
[RoleDefinition::forDomain('1')],
[RoleDefinition::forDomain($domain)],
1,
];
yield 'author role only' => [
@ -74,7 +75,7 @@ class RoleResolverTest extends TestCase
];
yield 'both roles' => [
$buildInput([RoleResolver::DOMAIN_ONLY_PARAM => 'example.com', RoleResolver::AUTHOR_ONLY_PARAM => true]),
[RoleDefinition::forAuthoredShortUrls(), RoleDefinition::forDomain('1')],
[RoleDefinition::forAuthoredShortUrls(), RoleDefinition::forDomain($domain)],
1,
];
}

View File

@ -72,12 +72,12 @@ class DomainRepositoryTest extends DatabaseTestCase
$this->getEntityManager()->flush();
$authorAndDomainApiKey->registerRole(RoleDefinition::forDomain($fooDomain->getId()));
$authorAndDomainApiKey->registerRole(RoleDefinition::forDomain($fooDomain));
$fooDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($fooDomain->getId()));
$fooDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($fooDomain));
$this->getEntityManager()->persist($fooDomainApiKey);
$barDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($barDomain->getId()));
$barDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($barDomain));
$this->getEntityManager()->persist($fooDomainApiKey);
$this->getEntityManager()->flush();

View File

@ -335,9 +335,9 @@ class ShortUrlRepositoryTest extends DatabaseTestCase
$this->getEntityManager()->persist($apiKey);
$otherApiKey = ApiKey::withRoles(RoleDefinition::forAuthoredShortUrls());
$this->getEntityManager()->persist($otherApiKey);
$wrongDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($wrongDomain->getId()));
$wrongDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($wrongDomain));
$this->getEntityManager()->persist($wrongDomainApiKey);
$rightDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($rightDomain->getId()));
$rightDomainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($rightDomain));
$this->getEntityManager()->persist($rightDomainApiKey);
$shortUrl = new ShortUrl('foo', ShortUrlMeta::fromRawData(

View File

@ -114,7 +114,7 @@ class TagRepositoryTest extends DatabaseTestCase
$authorApiKey = ApiKey::withRoles(RoleDefinition::forAuthoredShortUrls());
$this->getEntityManager()->persist($authorApiKey);
$domainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($domain->getId()));
$domainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($domain));
$this->getEntityManager()->persist($domainApiKey);
$names = ['foo', 'bar', 'baz', 'another'];

View File

@ -221,7 +221,7 @@ class VisitRepositoryTest extends DatabaseTestCase
$this->getEntityManager()->persist($shortUrl3);
$this->createVisitsForShortUrl($shortUrl3, 7);
$domainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($domain->getId()));
$domainApiKey = ApiKey::withRoles(RoleDefinition::forDomain($domain));
$this->getEntityManager()->persist($domainApiKey);
$this->getEntityManager()->flush();

View File

@ -51,7 +51,7 @@ class DomainServiceTest extends TestCase
{
$default = new DomainItem('default.com', true);
$adminApiKey = new ApiKey();
$domainSpecificApiKey = ApiKey::withRoles(RoleDefinition::forDomain('123'));
$domainSpecificApiKey = ApiKey::withRoles(RoleDefinition::forDomain((new Domain(''))->setId('123')));
yield 'empty list without API key' => [[], [$default], null];
yield 'one item without API key' => [

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest\ApiKey\Model;
use Shlinkio\Shlink\Core\Entity\Domain;
use Shlinkio\Shlink\Rest\ApiKey\Role;
final class RoleDefinition
@ -22,9 +23,12 @@ final class RoleDefinition
return new self(Role::AUTHORED_SHORT_URLS, []);
}
public static function forDomain(string $domainId): self
public static function forDomain(Domain $domain): self
{
return new self(Role::DOMAIN_SPECIFIC, ['domain_id' => $domainId]);
return new self(
Role::DOMAIN_SPECIFIC,
['domain_id' => $domain->getId(), 'authority' => $domain->getAuthority()],
);
}
public function roleName(): string

View File

@ -16,6 +16,10 @@ class Role
{
public const AUTHORED_SHORT_URLS = 'AUTHORED_SHORT_URLS';
public const DOMAIN_SPECIFIC = 'DOMAIN_SPECIFIC';
private const ROLE_FRIENDLY_NAMES = [
self::AUTHORED_SHORT_URLS => 'Author only',
self::DOMAIN_SPECIFIC => 'Domain only',
];
public static function toSpec(ApiKeyRole $role, bool $inlined): Specification
{
@ -35,4 +39,14 @@ class Role
{
return $meta['domain_id'] ?? '-1';
}
public static function domainAuthorityFromMeta(array $meta): string
{
return $meta['authority'] ?? '';
}
public static function toFriendlyName(string $roleName): string
{
return self::ROLE_FRIENDLY_NAMES[$roleName] ?? '';
}
}

View File

@ -33,7 +33,7 @@ class ApiKeyFixture extends AbstractFixture implements DependentFixtureInterface
/** @var Domain $exampleDomain */
$exampleDomain = $this->getReference('example_domain');
$domainApiKey = $this->buildApiKey('domain_api_key', true);
$domainApiKey->registerRole(RoleDefinition::forDomain($exampleDomain->getId()));
$domainApiKey->registerRole(RoleDefinition::forDomain($exampleDomain));
$manager->persist($domainApiKey);
$manager->flush();

View File

@ -12,6 +12,7 @@ use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
use Shlinkio\Shlink\Core\Entity\Domain;
use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
use Shlinkio\Shlink\Rest\Entity\ApiKey;
use Shlinkio\Shlink\Rest\Service\ApiKeyService;
@ -51,7 +52,10 @@ class ApiKeyServiceTest extends TestCase
{
yield 'no expiration date' => [null, []];
yield 'expiration date' => [Chronos::parse('2030-01-01'), []];
yield 'roles' => [null, [RoleDefinition::forDomain('123'), RoleDefinition::forAuthoredShortUrls()]];
yield 'roles' => [null, [
RoleDefinition::forDomain((new Domain(''))->setId('123')),
RoleDefinition::forAuthoredShortUrls(),
]];
}
/**