mirror of
https://github.com/shlinkio/shlink.git
synced 2024-12-26 17:01:21 -06:00
Added roles info to api key generation and api key list
This commit is contained in:
parent
c49a0ca040
commit
9e9d213f20
@ -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;
|
||||
|
@ -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() ? '---' : '+++';
|
||||
|
@ -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,
|
||||
];
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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(
|
||||
|
@ -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'];
|
||||
|
@ -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();
|
||||
|
@ -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' => [
|
||||
|
@ -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
|
||||
|
@ -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] ?? '';
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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(),
|
||||
]];
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user