Add list scopes endpoint for Console

This commit is contained in:
Matej Bačo
2026-04-29 10:08:31 +02:00
parent aca11ed073
commit e75fc5b859
12 changed files with 212 additions and 4 deletions
+4
View File
@@ -56,6 +56,8 @@ use Appwrite\Utopia\Response\Model\ColumnString;
use Appwrite\Utopia\Response\Model\ColumnText;
use Appwrite\Utopia\Response\Model\ColumnURL;
use Appwrite\Utopia\Response\Model\ColumnVarchar;
use Appwrite\Utopia\Response\Model\ConsoleKeyScope;
use Appwrite\Utopia\Response\Model\ConsoleKeyScopeList;
use Appwrite\Utopia\Response\Model\ConsoleOAuth2Provider;
use Appwrite\Utopia\Response\Model\ConsoleOAuth2ProviderList;
use Appwrite\Utopia\Response\Model\ConsoleOAuth2ProviderParameter;
@@ -488,6 +490,8 @@ Response::setModel(new ConsoleVariables());
Response::setModel(new ConsoleOAuth2ProviderParameter());
Response::setModel(new ConsoleOAuth2Provider());
Response::setModel(new ConsoleOAuth2ProviderList());
Response::setModel(new ConsoleKeyScope());
Response::setModel(new ConsoleKeyScopeList());
Response::setModel(new MFAChallenge());
Response::setModel(new MFARecoveryCodes());
Response::setModel(new MFAType());
@@ -1 +0,0 @@
List all OAuth2 providers supported by the Appwrite server, along with the parameters required to configure each provider. The response excludes mock providers but includes sandbox providers.
-1
View File
@@ -1 +0,0 @@
Get all Environment Variables that are relevant for the console.
@@ -34,7 +34,7 @@ class XList extends Action
namespace: 'console',
group: 'console',
name: 'listOAuth2Providers',
description: '/docs/references/console/list-oauth2-providers.md',
description: 'List all OAuth2 providers supported by the Appwrite server, along with the parameters required to configure each provider. The response excludes mock providers but includes sandbox providers.',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
@@ -0,0 +1,67 @@
<?php
namespace Appwrite\Platform\Modules\Console\Http\Scopes\Key;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Config\Config;
use Utopia\Database\Document;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
class XList extends Action
{
use HTTP;
public static function getName(): string
{
return 'listKeyScopes';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/console/scopes/key')
->desc('List key scopes')
->groups(['api'])
->label('scope', 'public')
->label('sdk', new Method(
namespace: 'console',
group: 'console',
name: 'listKeyScopes',
description: 'List all scopes available for project API keys, along with a description for each scope.',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_CONSOLE_KEY_SCOPE_LIST,
)
],
contentType: ContentType::JSON
))
->inject('response')
->callback($this->action(...));
}
public function action(Response $response): void
{
$scopesConfig = Config::getParam('projectScopes', []);
$scopes = [];
foreach ($scopesConfig as $scopeId => $scope) {
$scopes[] = new Document([
'$id' => $scopeId,
'description' => $scope['description'] ?? '',
]);
}
$response->dynamic(new Document([
'total' => \count($scopes),
'scopes' => $scopes,
]), Response::MODEL_CONSOLE_KEY_SCOPE_LIST);
}
}
@@ -36,7 +36,7 @@ class Get extends Action
namespace: 'console',
group: 'console',
name: 'variables',
description: '/docs/references/console/variables.md',
description: 'Get all Environment Variables that are relevant for the console.',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
@@ -15,6 +15,7 @@ use Appwrite\Platform\Modules\Console\Http\Redirects\Recover\Get as RedirectReco
use Appwrite\Platform\Modules\Console\Http\Redirects\Register\Get as RedirectRegister;
use Appwrite\Platform\Modules\Console\Http\Redirects\Root\Get as RedirectRoot;
use Appwrite\Platform\Modules\Console\Http\Resources\Get as GetResourceAvailability;
use Appwrite\Platform\Modules\Console\Http\Scopes\Key\XList as ListKeyScopes;
use Appwrite\Platform\Modules\Console\Http\Variables\Get as GetVariables;
use Utopia\Platform\Service;
@@ -30,6 +31,7 @@ class Http extends Service
$this->addAction(GetVariables::getName(), new GetVariables());
$this->addAction(ListOAuth2Providers::getName(), new ListOAuth2Providers());
$this->addAction(ListKeyScopes::getName(), new ListKeyScopes());
$this->addAction(CreateAssistantQuery::getName(), new CreateAssistantQuery());
$this->addAction(GetResourceAvailability::getName(), new GetResourceAvailability());
+2
View File
@@ -335,6 +335,8 @@ class Response extends SwooleResponse
public const MODEL_CONSOLE_OAUTH2_PROVIDER_PARAMETER = 'consoleOAuth2ProviderParameter';
public const MODEL_CONSOLE_OAUTH2_PROVIDER = 'consoleOAuth2Provider';
public const MODEL_CONSOLE_OAUTH2_PROVIDER_LIST = 'consoleOAuth2ProviderList';
public const MODEL_CONSOLE_KEY_SCOPE = 'consoleKeyScope';
public const MODEL_CONSOLE_KEY_SCOPE_LIST = 'consoleKeyScopeList';
// Deprecated
public const MODEL_PERMISSIONS = 'permissions';
@@ -0,0 +1,37 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class ConsoleKeyScope extends Model
{
public function __construct()
{
$this
->addRule('$id', [
'type' => self::TYPE_STRING,
'description' => 'Scope ID.',
'default' => '',
'example' => 'users.read',
])
->addRule('description', [
'type' => self::TYPE_STRING,
'description' => 'Scope description.',
'default' => '',
'example' => 'Access to read your project\'s users',
])
;
}
public function getName(): string
{
return 'Console Key Scope';
}
public function getType(): string
{
return Response::MODEL_CONSOLE_KEY_SCOPE;
}
}
@@ -0,0 +1,37 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class ConsoleKeyScopeList extends Model
{
public function __construct()
{
$this
->addRule('total', [
'type' => self::TYPE_INTEGER,
'description' => 'Total number of key scopes exposed by the server.',
'default' => 0,
'example' => 5,
])
->addRule('scopes', [
'type' => Response::MODEL_CONSOLE_KEY_SCOPE,
'description' => 'List of key scopes, each with its ID and description.',
'default' => [],
'array' => true,
])
;
}
public function getName(): string
{
return 'Console Key Scopes List';
}
public function getType(): string
{
return Response::MODEL_CONSOLE_KEY_SCOPE_LIST;
}
}
@@ -128,4 +128,47 @@ class ConsoleConsoleClientTest extends Scope
// Sandbox providers (e.g. paypalSandbox) are included
$this->assertContains('paypalSandbox', $providerIds);
}
public function testListKeyScopes(): void
{
$response = $this->client->call(Client::METHOD_GET, '/console/scopes/key', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['total']);
$this->assertIsArray($response['body']['scopes']);
$this->assertGreaterThan(0, $response['body']['total']);
$this->assertEquals($response['body']['total'], \count($response['body']['scopes']));
$scopeIds = \array_column($response['body']['scopes'], '$id');
// Well-known scopes must be present
$this->assertContains('users.read', $scopeIds);
$this->assertContains('users.write', $scopeIds);
$this->assertContains('functions.read', $scopeIds);
$this->assertContains('functions.write', $scopeIds);
// Every scope has the expected shape
foreach ($response['body']['scopes'] as $scope) {
$this->assertArrayHasKey('$id', $scope);
$this->assertIsString($scope['$id']);
$this->assertNotEmpty($scope['$id']);
$this->assertArrayHasKey('description', $scope);
$this->assertIsString($scope['description']);
$this->assertNotEmpty($scope['description']);
}
// A specific scope has the expected description
$usersRead = null;
foreach ($response['body']['scopes'] as $scope) {
if ($scope['$id'] === 'users.read') {
$usersRead = $scope;
break;
}
}
$this->assertNotNull($usersRead);
$this->assertEquals('Access to read your project\'s users', $usersRead['description']);
}
}
@@ -43,4 +43,22 @@ class ConsoleCustomServerTest extends Scope
$this->assertContains('github', $providerIds);
$this->assertNotContains('mock', $providerIds);
}
public function testListKeyScopes(): void
{
// Public endpoint: must succeed without admin authentication. Drop the
// headers from getHeaders() and only pass project + content-type.
$response = $this->client->call(Client::METHOD_GET, '/console/scopes/key', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertIsInt($response['body']['total']);
$this->assertIsArray($response['body']['scopes']);
$this->assertGreaterThan(0, $response['body']['total']);
$scopeIds = \array_column($response['body']['scopes'], '$id');
$this->assertContains('users.read', $scopeIds);
}
}