From dc38b631606c477d376bca94235f39eaf3e5085d Mon Sep 17 00:00:00 2001 From: shimon Date: Tue, 5 Jul 2022 14:02:23 +0300 Subject: [PATCH] small fix --- app/controllers/api/projects.php | 116 +++++++++++++++++++---------- tests/e2e/Scopes/ProjectCustom.php | 1 + 2 files changed, 79 insertions(+), 38 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 793c2d19dd..24c0e783ef 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -26,6 +26,7 @@ use Appwrite\Extend\Exception; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Hostname; +use Utopia\Validator\Integer; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -77,14 +78,17 @@ App::post('/v1/projects') } $projectId = ($projectId == 'unique()') ? $dbForConsole->getId() : $projectId; + if ($projectId === 'console') { throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT); } + $project = $dbForConsole->createDocument('projects', new Document([ - '$id' => $projectId == 'unique()' ? $dbForConsole->getId() : $projectId, + '$id' => $projectId, '$read' => ['team:' . $teamId], '$write' => ['team:' . $teamId . '/owner', 'team:' . $teamId . '/developer'], 'name' => $name, + 'teamInternalId' => $team->getInternalId(), 'teamId' => $team->getId(), 'description' => $description, 'logo' => $logo, @@ -108,7 +112,7 @@ App::post('/v1/projects') /** @var array $collections */ $collections = Config::getParam('collections', []); - $dbForProject->setNamespace("_{$project->getId()}"); + $dbForProject->setNamespace("_{$project->getInternalId()}"); $dbForProject->create('appwrite'); $audit = new Audit($dbForProject); @@ -121,8 +125,6 @@ App::post('/v1/projects') if (($collection['$collection'] ?? '') !== Database::METADATA) { continue; } - - $attributes = []; $indexes = []; @@ -149,6 +151,7 @@ App::post('/v1/projects') 'orders' => $index['orders'], ]); } + $dbForProject->createCollection($key, $attributes, $indexes); } @@ -185,7 +188,7 @@ App::get('/v1/projects') ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, APP_LIMIT_COUNT), 'Results offset. The default value is 0. Use this param to manage pagination. [learn more about pagination](https://appwrite.io/docs/pagination)', true) ->param('cursor', '', new UID(), 'ID of the project used as the starting point for the query, excluding the project itself. Should be used for efficient pagination when working with large sets of data. [learn more about pagination](https://appwrite.io/docs/pagination)', true) - ->param('cursorDirection', Database::CURSOR_AFTER, new WhiteList([Database::CURSOR_AFTER, Database::CURSOR_BEFORE]), 'Direction of the cursor.', true) + ->param('cursorDirection', Database::CURSOR_AFTER, new WhiteList([Database::CURSOR_AFTER, Database::CURSOR_BEFORE]), 'Direction of the cursor, can be either \'before\' or \'after\'.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForConsole') @@ -283,15 +286,15 @@ App::get('/v1/projects/:projectId/usage') ], ]; - $dbForProject->setNamespace("_{$projectId}"); + $dbForProject->setNamespace("_{$project->getInternalId()}"); $metrics = [ 'requests', 'network', 'executions', 'users.count', - 'database.documents.count', - 'database.collections.count', + 'databases.documents.count', + 'databases.collections.count', 'storage.total' ]; @@ -338,8 +341,8 @@ App::get('/v1/projects/:projectId/usage') 'requests' => $stats['requests'], 'network' => $stats['network'], 'functions' => $stats['executions'], - 'documents' => $stats['database.documents.count'], - 'collections' => $stats['database.collections.count'], + 'documents' => $stats['databases.documents.count'], + 'collections' => $stats['databases.collections.count'], 'users' => $stats['users.count'], 'storage' => $stats['storage.total'] ]); @@ -598,12 +601,11 @@ App::post('/v1/projects/:projectId/webhooks') $security = (bool) filter_var($security, FILTER_VALIDATE_BOOLEAN); - - $webhook = new Document([ '$id' => $dbForConsole->getId(), '$read' => ['role:all'], '$write' => ['role:all'], + 'projectInternalId' => $project->getInternalId(), 'projectId' => $project->getId(), 'name' => $name, 'events' => $events, @@ -644,7 +646,7 @@ App::get('/v1/projects/:projectId/webhooks') } $webhooks = $dbForConsole->find('webhooks', [ - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ], 5000); $response->dynamic(new Document([ @@ -677,7 +679,7 @@ App::get('/v1/projects/:projectId/webhooks/:webhookId') $webhook = $dbForConsole->findOne('webhooks', [ new Query('_uid', Query::TYPE_EQUAL, [$webhookId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($webhook === false || $webhook->isEmpty()) { @@ -705,10 +707,9 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->param('security', false, new Boolean(true), 'Certificate verification, false for disabled or true for enabled.') ->param('httpUser', '', new Text(256), 'Webhook HTTP user. Max length: 256 chars.', true) ->param('httpPass', '', new Text(256), 'Webhook HTTP password. Max length: 256 chars.', true) - ->param('signatureKey', null, new Text(256), 'Webhook signature key. Max length: 256 chars.', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, string $signatureKey, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $webhookId, string $name, array $events, string $url, bool $security, string $httpUser, string $httpPass, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -720,7 +721,7 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') $webhook = $dbForConsole->findOne('webhooks', [ new Query('_uid', Query::TYPE_EQUAL, [$webhookId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($webhook === false || $webhook->isEmpty()) { @@ -736,10 +737,45 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId') ->setAttribute('httpPass', $httpPass) ; - if (!empty($signatureKey)) { - $webhook->setAttribute('signatureKey', $signatureKey); + $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); + $dbForConsole->deleteCachedDocument('projects', $project->getId()); + + $response->dynamic($webhook, Response::MODEL_WEBHOOK); + }); + +App::patch('/v1/projects/:projectId/webhooks/:webhookId/signature') + ->desc('Update Webhook Signature Key') + ->groups(['api', 'projects']) + ->label('scope', 'projects.write') + ->label('sdk.auth', [APP_AUTH_TYPE_ADMIN]) + ->label('sdk.namespace', 'projects') + ->label('sdk.method', 'updateWebhookSignature') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_WEBHOOK) + ->param('projectId', null, new UID(), 'Project unique ID.') + ->param('webhookId', null, new UID(), 'Webhook unique ID.') + ->inject('response') + ->inject('dbForConsole') + ->action(function (string $projectId, string $webhookId, Response $response, Database $dbForConsole) { + + $project = $dbForConsole->getDocument('projects', $projectId); + + if ($project->isEmpty()) { + throw new Exception('Project not found', 404, Exception::PROJECT_NOT_FOUND); } + $webhook = $dbForConsole->findOne('webhooks', [ + new Query('_uid', Query::TYPE_EQUAL, [$webhookId]), + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) + ]); + + if ($webhook === false || $webhook->isEmpty()) { + throw new Exception('Webhook not found', 404, Exception::WEBHOOK_NOT_FOUND); + } + + $webhook->setAttribute('signatureKey', \bin2hex(\random_bytes(64))); + $dbForConsole->updateDocument('webhooks', $webhook->getId(), $webhook); $dbForConsole->deleteCachedDocument('projects', $project->getId()); @@ -769,7 +805,7 @@ App::delete('/v1/projects/:projectId/webhooks/:webhookId') $webhook = $dbForConsole->findOne('webhooks', [ new Query('_uid', Query::TYPE_EQUAL, [$webhookId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($webhook === false || $webhook->isEmpty()) { @@ -798,9 +834,10 @@ App::post('/v1/projects/:projectId/keys') ->param('projectId', null, new UID(), 'Project unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' scopes are allowed.') + ->param('expire', 0, new Integer(), 'Key expiration time in Unix timestamp. Use 0 for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $name, array $scopes, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $name, array $scopes, int $expire, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -812,9 +849,11 @@ App::post('/v1/projects/:projectId/keys') '$id' => $dbForConsole->getId(), '$read' => ['role:all'], '$write' => ['role:all'], + 'projectInternalId' => $project->getInternalId(), 'projectId' => $project->getId(), 'name' => $name, 'scopes' => $scopes, + 'expire' => $expire, 'secret' => \bin2hex(\random_bytes(128)), ]); @@ -848,7 +887,7 @@ App::get('/v1/projects/:projectId/keys') } $keys = $dbForConsole->find('keys', [ - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]), + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]), ], 5000); $response->dynamic(new Document([ @@ -881,7 +920,7 @@ App::get('/v1/projects/:projectId/keys/:keyId') $key = $dbForConsole->findOne('keys', [ new Query('_uid', Query::TYPE_EQUAL, [$keyId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($key === false || $key->isEmpty()) { @@ -905,9 +944,10 @@ App::put('/v1/projects/:projectId/keys/:keyId') ->param('keyId', null, new UID(), 'Key unique ID.') ->param('name', null, new Text(128), 'Key name. Max length: 128 chars.') ->param('scopes', null, new ArrayList(new WhiteList(array_keys(Config::getParam('scopes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Key scopes list. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' events are allowed.') + ->param('expire', 0, new Integer(), 'Key expiration time in Unix timestamp. Use 0 for unlimited expiration.', true) ->inject('response') ->inject('dbForConsole') - ->action(function (string $projectId, string $keyId, string $name, array $scopes, Response $response, Database $dbForConsole) { + ->action(function (string $projectId, string $keyId, string $name, array $scopes, int $expire, Response $response, Database $dbForConsole) { $project = $dbForConsole->getDocument('projects', $projectId); @@ -917,7 +957,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') $key = $dbForConsole->findOne('keys', [ new Query('_uid', Query::TYPE_EQUAL, [$keyId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($key === false || $key->isEmpty()) { @@ -927,6 +967,7 @@ App::put('/v1/projects/:projectId/keys/:keyId') $key ->setAttribute('name', $name) ->setAttribute('scopes', $scopes) + ->setAttribute('expire', $expire) ; $dbForConsole->updateDocument('keys', $key->getId(), $key); @@ -959,7 +1000,7 @@ App::delete('/v1/projects/:projectId/keys/:keyId') $key = $dbForConsole->findOne('keys', [ new Query('_uid', Query::TYPE_EQUAL, [$keyId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($key === false || $key->isEmpty()) { @@ -1004,14 +1045,13 @@ App::post('/v1/projects/:projectId/platforms') '$id' => $dbForConsole->getId(), '$read' => ['role:all'], '$write' => ['role:all'], + 'projectInternalId' => $project->getInternalId(), 'projectId' => $project->getId(), 'type' => $type, 'name' => $name, 'key' => $key, 'store' => $store, - 'hostname' => $hostname, - 'dateCreated' => \time(), - 'dateUpdated' => \time(), + 'hostname' => $hostname ]); $platform = $dbForConsole->createDocument('platforms', $platform); @@ -1077,7 +1117,7 @@ App::get('/v1/projects/:projectId/platforms/:platformId') $platform = $dbForConsole->findOne('platforms', [ new Query('_uid', Query::TYPE_EQUAL, [$platformId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($platform === false || $platform->isEmpty()) { @@ -1114,7 +1154,7 @@ App::put('/v1/projects/:projectId/platforms/:platformId') $platform = $dbForConsole->findOne('platforms', [ new Query('_uid', Query::TYPE_EQUAL, [$platformId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($platform === false || $platform->isEmpty()) { @@ -1123,7 +1163,6 @@ App::put('/v1/projects/:projectId/platforms/:platformId') $platform ->setAttribute('name', $name) - ->setAttribute('dateUpdated', \time()) ->setAttribute('key', $key) ->setAttribute('store', $store) ->setAttribute('hostname', $hostname) @@ -1159,7 +1198,7 @@ App::delete('/v1/projects/:projectId/platforms/:platformId') $platform = $dbForConsole->findOne('platforms', [ new Query('_uid', Query::TYPE_EQUAL, [$platformId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($platform === false || $platform->isEmpty()) { @@ -1199,7 +1238,7 @@ App::post('/v1/projects/:projectId/domains') $document = $dbForConsole->findOne('domains', [ new Query('domain', Query::TYPE_EQUAL, [$domain]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]), + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]), ]); if ($document && !$document->isEmpty()) { @@ -1218,6 +1257,7 @@ App::post('/v1/projects/:projectId/domains') '$id' => $dbForConsole->getId(), '$read' => ['role:all'], '$write' => ['role:all'], + 'projectInternalId' => $project->getInternalId(), 'projectId' => $project->getId(), 'updated' => \time(), 'domain' => $domain->get(), @@ -1257,7 +1297,7 @@ App::get('/v1/projects/:projectId/domains') } $domains = $dbForConsole->find('domains', [ - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ], 5000); $response->dynamic(new Document([ @@ -1290,7 +1330,7 @@ App::get('/v1/projects/:projectId/domains/:domainId') $domain = $dbForConsole->findOne('domains', [ new Query('_uid', Query::TYPE_EQUAL, [$domainId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($domain === false || $domain->isEmpty()) { @@ -1324,7 +1364,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification') $domain = $dbForConsole->findOne('domains', [ new Query('_uid', Query::TYPE_EQUAL, [$domainId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($domain === false || $domain->isEmpty()) { @@ -1384,7 +1424,7 @@ App::delete('/v1/projects/:projectId/domains/:domainId') $domain = $dbForConsole->findOne('domains', [ new Query('_uid', Query::TYPE_EQUAL, [$domainId]), - new Query('projectId', Query::TYPE_EQUAL, [$project->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$project->getInternalId()]) ]); if ($domain === false || $domain->isEmpty()) { diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index 0d05e5fd6b..5b019320e8 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -31,6 +31,7 @@ trait ProjectCustom ]); + $this->assertEquals(201, $team['headers']['status-code']); $this->assertEquals('Demo Project Team', $team['body']['name']); $this->assertNotEmpty($team['body']['$id']);