diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 502bfc589..8018cd088 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -444,12 +444,13 @@ App::patch('/v1/projects/:projectId/oauth2') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_PROJECT) ->param('projectId', '', new UID(), 'Project unique ID.') - ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name', false) - ->param('appId', '', new Text(256), 'Provider app ID. Max length: 256 chars.', true) - ->param('secret', '', new text(512), 'Provider secret key. Max length: 512 chars.', true) + ->param('provider', '', new WhiteList(\array_keys(Config::getParam('providers')), true), 'Provider Name') + ->param('appId', null, new Text(256), 'Provider app ID. Max length: 256 chars.', true) + ->param('secret', null, new text(512), 'Provider secret key. Max length: 512 chars.', true) + ->param('enabled', null, new Boolean(), 'Provider status. Set to \'false\' to disable new session creation.', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $provider, string $appId, string $secret, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $provider, ?string $appId, ?string $secret, ?bool $enabled, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -458,8 +459,18 @@ App::patch('/v1/projects/:projectId/oauth2') } $providers = $project->getAttribute('authProviders', []); - $providers[$provider . 'Appid'] = $appId; - $providers[$provider . 'Secret'] = $secret; + + if ($appId !== null) { + $providers[$provider . 'Appid'] = $appId; + } + + if ($secret !== null) { + $providers[$provider . 'Secret'] = $secret; + } + + if ($enabled !== null) { + $providers[$provider . 'Enabled'] = $enabled; + } $project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('authProviders', $providers)); diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index e23335365..029cc95d4 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -70,6 +70,7 @@ use Appwrite\Utopia\Response\Model\HealthStatus; use Appwrite\Utopia\Response\Model\HealthTime; use Appwrite\Utopia\Response\Model\HealthVersion; use Appwrite\Utopia\Response\Model\Mock; // Keep last +use Appwrite\Utopia\Response\Model\Provider; use Appwrite\Utopia\Response\Model\Runtime; use Appwrite\Utopia\Response\Model\UsageBuckets; use Appwrite\Utopia\Response\Model\UsageCollection; @@ -194,6 +195,8 @@ class Response extends SwooleResponse public const MODEL_WEBHOOK_LIST = 'webhookList'; public const MODEL_KEY = 'key'; public const MODEL_KEY_LIST = 'keyList'; + public const MODEL_PROVIDER = 'provider'; + public const MODEL_PROVIDER_LIST = 'providerList'; public const MODEL_PLATFORM = 'platform'; public const MODEL_PLATFORM_LIST = 'platformList'; public const MODEL_DOMAIN = 'domain'; @@ -259,6 +262,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false)) ->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false)) ->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false)) + ->setModel(new BaseList('Providers List', self::MODEL_PROVIDER_LIST, 'platforms', self::MODEL_PROVIDER, true, false)) ->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false)) ->setModel(new BaseList('Domains List', self::MODEL_DOMAIN_LIST, 'domains', self::MODEL_DOMAIN, true, false)) ->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY)) @@ -312,6 +316,7 @@ class Response extends SwooleResponse ->setModel(new Webhook()) ->setModel(new Key()) ->setModel(new Domain()) + ->setModel(new Provider()) ->setModel(new Platform()) ->setModel(new Variable()) ->setModel(new Country()) diff --git a/src/Appwrite/Utopia/Response/Model/Project.php b/src/Appwrite/Utopia/Response/Model/Project.php index 1638adeca..d5731cb2a 100644 --- a/src/Appwrite/Utopia/Response/Model/Project.php +++ b/src/Appwrite/Utopia/Response/Model/Project.php @@ -107,6 +107,13 @@ class Project extends Model 'default' => 0, 'example' => 100, ]) + ->addRule('providers', [ + 'type' => Response::MODEL_PROVIDER, + 'description' => 'List of Providers.', + 'default' => [], + 'example' => new \stdClass(), + 'array' => true, + ]) ->addRule('platforms', [ 'type' => Response::MODEL_PLATFORM, 'description' => 'List of Platforms.', @@ -138,32 +145,8 @@ class Project extends Model ; $services = Config::getParam('services', []); - $providers = Config::getParam('providers', []); $auth = Config::getParam('auth', []); - foreach ($providers as $index => $provider) { - if (!$provider['enabled']) { - continue; - } - - $name = (isset($provider['name'])) ? $provider['name'] : 'Unknown'; - - $this - ->addRule('provider' . \ucfirst($index) . 'Appid', [ - 'type' => self::TYPE_STRING, - 'description' => $name . ' OAuth app ID.', - 'example' => '123247283472834787438', - 'default' => '', - ]) - ->addRule('provider' . \ucfirst($index) . 'Secret', [ - 'type' => self::TYPE_STRING, - 'description' => $name . ' OAuth secret ID.', - 'example' => 'djsgudsdsewe43434343dd34...', - 'default' => '', - ]) - ; - } - foreach ($auth as $index => $method) { $name = $method['name'] ?? ''; $key = $method['key'] ?? ''; @@ -224,6 +207,7 @@ class Project extends Model */ public function filter(Document $document): Document { + // Services $values = $document->getAttribute('services', []); $services = Config::getParam('services', []); @@ -236,6 +220,7 @@ class Project extends Model $document->setAttribute('serviceStatusFor' . ucfirst($key), $value); } + // Auth $authValues = $document->getAttribute('auths', []); $auth = Config::getParam('auth', []); @@ -247,17 +232,27 @@ class Project extends Model $document->setAttribute('auth' . ucfirst($key), $value); } + // Providers $providers = Config::getParam('providers', []); $providerValues = $document->getAttribute('authProviders', []); + $projectProviders = []; foreach ($providers as $key => $provider) { if (!$provider['enabled']) { + // Disabled by Appwrite configuration, exclude from response continue; } - $appId = $providerValues[$key . 'Appid'] ?? ''; - $secret = $providerValues[$key . 'Secret'] ?? ''; - $document->setAttribute('provider' . ucfirst($key) . 'Appid', $appId)->setAttribute('provider' . ucfirst($key) . 'Secret', $secret); + + $projectProviders[] = new Document([ + 'name' => ucfirst($key), + 'appId' => $providerValues[$key . 'Appid'] ?? '', + 'secret' => $providerValues[$key . 'Secret'] ?? '', + 'enabled' => $providerValues[$key . 'Enabled'] ?? false, + ]); } + + $document->setAttribute("providers", $projectProviders); + return $document; } } diff --git a/src/Appwrite/Utopia/Response/Model/Provider.php b/src/Appwrite/Utopia/Response/Model/Provider.php new file mode 100644 index 000000000..6bd533d9b --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Provider.php @@ -0,0 +1,63 @@ +addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Provider name.', + 'default' => '', + 'example' => 'GitHub', + ]) + ->addRule('appId', [ + 'type' => self::TYPE_STRING, + 'description' => 'OAuth 2.0 application ID.', + 'default' => '', + 'example' => '259125845563242502', + ]) + ->addRule('secret', [ + 'type' => self::TYPE_STRING, + 'description' => 'OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration.', + 'default' => '', + 'example' => 'Bpw_g9c2TGXxfgLshDbSaL8tsCcqgczQ', + ]) + ->addRule('enabled', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Provider is active and can be used to create session.', + 'example' => '', + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Provider'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_PROVIDER; + } +} diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 0c6dfab18..29789a322 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -447,8 +447,61 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals($id, $response['body']['$id']); foreach ($providers as $key => $provider) { - $this->assertEquals('AppId-' . ucfirst($key), $response['body']['provider' . ucfirst($key) . 'Appid']); - $this->assertEquals('Secret-' . ucfirst($key), $response['body']['provider' . ucfirst($key) . 'Secret']); + $asserted = false; + foreach ($response['body']['providers'] as $responseProvider) { + if ($responseProvider['name'] === ucfirst($key)) { + $this->assertEquals('AppId-' . ucfirst($key), $responseProvider['appId']); + $this->assertEquals('Secret-' . ucfirst($key), $responseProvider['secret']); + $this->assertFalse($responseProvider['enabled']); + $asserted = true; + break; + } + } + + $this->assertTrue($asserted); + } + + // Enable providers + $i = 0; + foreach ($providers as $key => $provider) { + $response = $this->client->call(Client::METHOD_PATCH, '/projects/' . $id . '/oauth2', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'provider' => $key, + 'enabled' => $i === 0 ? false : true // On first provider, test enabled=false + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + + $i++; + } + + $response = $this->client->call(Client::METHOD_GET, '/projects/' . $id, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']); + $this->assertEquals($id, $response['body']['$id']); + + $i = 0; + foreach ($providers as $key => $provider) { + $asserted = false; + foreach ($response['body']['providers'] as $responseProvider) { + if ($responseProvider['name'] === ucfirst($key)) { + // On first provider, test enabled=false + $this->assertEquals($i !== 0, $responseProvider['enabled']); + $asserted = true; + break; + } + } + + $this->assertTrue($asserted); + + $i++; } /**