diff --git a/app/config/collections.php b/app/config/collections.php index 5ce8667032..c1709ae618 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -97,6 +97,17 @@ $collections = [ '$id' => 'attributes', 'name' => 'Attributes', 'attributes' => [ + [ + '$id' => 'collectionInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'collectionId', 'type' => Database::VAR_STRING, @@ -229,7 +240,7 @@ $collections = [ [ '$id' => '_key_collection', 'type' => Database::INDEX_KEY, - 'attributes' => ['collectionId'], + 'attributes' => ['collectionInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -241,6 +252,17 @@ $collections = [ '$id' => 'indexes', 'name' => 'Indexes', 'attributes' => [ + [ + '$id' => 'collectionInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'collectionId', 'type' => Database::VAR_STRING, @@ -323,10 +345,10 @@ $collections = [ [ '$id' => '_key_collection', 'type' => Database::INDEX_KEY, - 'attributes' => ['collectionId'], + 'attributes' => ['collectionInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -335,6 +357,17 @@ $collections = [ '$id' => 'projects', 'name' => 'Projects', 'attributes' => [ + [ + '$id' => 'teamInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'teamId', 'type' => Database::VAR_STRING, @@ -572,6 +605,17 @@ $collections = [ '$id' => 'platforms', 'name' => 'platforms', 'attributes' => [ + [ + '$id' => 'projectInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'projectId', 'type' => Database::VAR_STRING, @@ -643,7 +687,7 @@ $collections = [ [ '$id' => '_key_project', 'type' => Database::INDEX_KEY, - 'attributes' => ['projectId'], + 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -655,6 +699,17 @@ $collections = [ '$id' => 'domains', 'name' => 'domains', 'attributes' => [ + [ + '$id' => 'projectInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'projectId', 'type' => Database::VAR_STRING, @@ -737,7 +792,7 @@ $collections = [ [ '$id' => '_key_project', 'type' => Database::INDEX_KEY, - 'attributes' => ['projectId'], + 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -749,6 +804,17 @@ $collections = [ '$id' => 'keys', 'name' => 'keys', 'attributes' => [ + [ + '$id' => 'projectInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'projectId', 'type' => Database::VAR_STRING, @@ -809,7 +875,7 @@ $collections = [ [ '$id' => '_key_project', 'type' => Database::INDEX_KEY, - 'attributes' => ['projectId'], + 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -821,6 +887,17 @@ $collections = [ '$id' => 'webhooks', 'name' => 'webhooks', 'attributes' => [ + [ + '$id' => 'projectInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'projectId', 'type' => Database::VAR_STRING, @@ -914,10 +991,10 @@ $collections = [ [ '$id' => '_key_project', 'type' => Database::INDEX_KEY, - 'attributes' => ['projectId'], + 'attributes' => ['projectInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], - ], + ] ], ], @@ -1093,6 +1170,17 @@ $collections = [ '$id' => 'tokens', 'name' => 'Tokens', 'attributes' => [ + [ + '$id' => 'userInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'userId', 'type' => Database::VAR_STRING, @@ -1164,7 +1252,7 @@ $collections = [ [ '$id' => '_key_user', 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], + 'attributes' => ['userInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -1176,6 +1264,17 @@ $collections = [ '$id' => 'sessions', 'name' => 'Sessions', 'attributes' => [ + [ + '$id' => 'userInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'userId', 'type' => Database::VAR_STRING, @@ -1441,7 +1540,7 @@ $collections = [ [ '$id' => '_key_user', 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], + 'attributes' => ['userInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -1504,7 +1603,7 @@ $collections = [ 'name' => 'Memberships', 'attributes' => [ [ - '$id' => 'teamId', + '$id' => 'userInternalId', 'type' => Database::VAR_STRING, 'format' => '', 'size' => Database::LENGTH_KEY, @@ -1525,6 +1624,28 @@ $collections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => 'teamInternalId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], + [ + '$id' => 'teamId', + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => Database::LENGTH_KEY, + 'signed' => true, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => [], + ], [ '$id' => 'roles', 'type' => Database::VAR_STRING, @@ -1596,21 +1717,21 @@ $collections = [ [ '$id' => '_key_unique', 'type' => Database::INDEX_UNIQUE, - 'attributes' => ['teamId', 'userId'], + 'attributes' => ['teamInternalId', 'userInternalId'], 'lengths' => [Database::LENGTH_KEY, Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC, Database::ORDER_ASC], ], [ - '$id' => '_key_team', + '$id' => '_key_internal', 'type' => Database::INDEX_KEY, - 'attributes' => ['teamId'], + 'attributes' => ['userInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], [ - '$id' => '_key_user', + '$id' => '_key_team', 'type' => Database::INDEX_KEY, - 'attributes' => ['userId'], + 'attributes' => ['teamInternalId'], 'lengths' => [Database::LENGTH_KEY], 'orders' => [Database::ORDER_ASC], ], @@ -1660,7 +1781,6 @@ $collections = [ 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, 'filters' => [], ], [ @@ -1821,7 +1941,6 @@ $collections = [ 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, 'filters' => [], ], [ @@ -2101,7 +2220,6 @@ $collections = [ 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, 'filters' => [], ], [ @@ -2529,7 +2647,6 @@ $collections = [ 'signed' => true, 'required' => false, 'default' => null, - 'array' => false, 'filters' => [], ], [ diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index cc6294df29..ea94d849d5 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -178,6 +178,7 @@ App::post('/v1/account/sessions') [ '$id' => $dbForProject->getId(), 'userId' => $profile->getId(), + 'userInternalId' => $profile->getInternalId(), 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $email, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak @@ -507,6 +508,7 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect') $session = new Document(array_merge([ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'provider' => $provider, 'providerUid' => $oauth2ID, 'providerAccessToken' => $accessToken, @@ -661,6 +663,7 @@ App::post('/v1/account/sessions/magic-url') $token = new Document([ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'type' => Auth::TOKEN_TYPE_MAGIC_URL, 'secret' => Auth::hash($loginSecret), // One way hash encryption to protect DB leak 'expire' => $expire, @@ -738,6 +741,8 @@ App::put('/v1/account/sessions/magic-url') ->inject('events') ->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Audit $audits, Event $events) { + /** @var Utopia\Database\Document $user */ + $user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId)); if ($user->isEmpty()) { @@ -758,6 +763,7 @@ App::put('/v1/account/sessions/magic-url') [ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'provider' => Auth::SESSION_PROVIDER_MAGIC_URL, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, @@ -901,6 +907,7 @@ App::post('/v1/account/sessions/anonymous') [ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'provider' => Auth::SESSION_PROVIDER_ANONYMOUS, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expiry, @@ -1679,6 +1686,7 @@ App::post('/v1/account/recovery') $recovery = new Document([ '$id' => $dbForProject->getId(), 'userId' => $profile->getId(), + 'userInternalId' => $profile->getInternalId(), 'type' => Auth::TOKEN_TYPE_RECOVERY, 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak 'expire' => $expire, @@ -1839,6 +1847,7 @@ App::post('/v1/account/verification') $verification = new Document([ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'type' => Auth::TOKEN_TYPE_VERIFICATION, 'secret' => Auth::hash($verificationSecret), // One way hash encryption to protect DB leak 'expire' => $expire, diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 5334ad1869..3c579f82e2 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -47,6 +47,7 @@ use MaxMind\Db\Reader; * * * @return Document Newly created attribute document + * @throws Exception */ function createAttribute(string $collectionId, Document $attribute, Response $response, Database $dbForProject, EventDatabase $database, EventAudit $audits, Event $events, Stats $usage): Document { @@ -84,8 +85,9 @@ function createAttribute(string $collectionId, Document $attribute, Response $re try { $attribute = new Document([ - '$id' => $collectionId . '_' . $key, + '$id' => $collection->getInternalId() . '_' . $key, 'key' => $key, + 'collectionInternalId' => $collection->getInternalId(), 'collectionId' => $collectionId, 'type' => $type, 'status' => 'processing', // processing, available, failed, deleting, stuck @@ -1117,7 +1119,7 @@ App::get('/v1/database/collections/:collectionId/attributes/:key') throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key); + $attribute = $dbForProject->getDocument('attributes', $collection->getInternalId() . '_' . $key); if ($attribute->isEmpty()) { throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND); @@ -1173,7 +1175,7 @@ App::delete('/v1/database/collections/:collectionId/attributes/:key') throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } - $attribute = $dbForProject->getDocument('attributes', $collectionId . '_' . $key); + $attribute = $dbForProject->getDocument('attributes', $collection->getInternalId() . '_' . $key); if ($attribute->isEmpty()) { throw new Exception('Attribute not found', 404, Exception::ATTRIBUTE_NOT_FOUND); @@ -1260,8 +1262,8 @@ App::post('/v1/database/collections/:collectionId/indexes') } $count = $dbForProject->count('indexes', [ - new Query('collectionId', Query::TYPE_EQUAL, [$collectionId]) - ], 61); + new Query('collectionInternalId', Query::TYPE_EQUAL, [$collection->getInternalId()]) + ]); $limit = 64 - MariaDB::getNumberOfDefaultIndexes(); @@ -1298,9 +1300,10 @@ App::post('/v1/database/collections/:collectionId/indexes') try { $index = $dbForProject->createDocument('indexes', new Document([ - '$id' => $collectionId . '_' . $key, + '$id' => $collection->getInternalId() . '_' . $key, 'key' => $key, 'status' => 'processing', // processing, available, failed, deleting, stuck + 'collectionInternalId' => $collection->getInternalId(), 'collectionId' => $collectionId, 'type' => $type, 'attributes' => $attributes, @@ -1438,7 +1441,7 @@ App::delete('/v1/database/collections/:collectionId/indexes/:key') throw new Exception('Collection not found', 404, Exception::COLLECTION_NOT_FOUND); } - $index = $dbForProject->getDocument('indexes', $collectionId . '_' . $key); + $index = $dbForProject->getDocument('indexes', $collection->getInternalId() . '_' . $key); if (empty($index->getId())) { throw new Exception('Index not found', 404, Exception::INDEX_NOT_FOUND); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 9613f821cf..e95481cc9a 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -78,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, @@ -109,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); @@ -268,7 +271,7 @@ App::get('/v1/projects/:projectId/usage') ], ]; - $dbForProject->setNamespace("_{$projectId}"); + $dbForProject->setNamespace("_{$project->getInternalId()}"); $metrics = [ 'requests', @@ -589,6 +592,7 @@ App::post('/v1/projects/:projectId/webhooks') '$id' => $dbForConsole->getId(), '$read' => ['role:all'], '$write' => ['role:all'], + 'projectInternalId' => $project->getInternalId(), 'projectId' => $project->getId(), 'name' => $name, 'events' => $events, @@ -629,7 +633,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([ @@ -662,7 +666,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,7 +709,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()) { @@ -754,7 +758,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,6 +802,7 @@ 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, @@ -835,7 +840,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([ @@ -868,7 +873,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,7 +910,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()) { @@ -948,7 +953,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()) { @@ -993,6 +998,7 @@ 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, @@ -1064,7 +1070,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()) { @@ -1101,7 +1107,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()) { @@ -1145,7 +1151,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()) { @@ -1185,7 +1191,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()) { @@ -1204,6 +1210,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(), @@ -1243,7 +1250,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([ @@ -1276,7 +1283,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()) { @@ -1310,7 +1317,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()) { @@ -1370,7 +1377,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/app/controllers/api/teams.php b/app/controllers/api/teams.php index a32dc87bcd..eb8d19c8db 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -73,7 +73,9 @@ App::post('/v1/teams') '$read' => ['user:' . $user->getId(), 'team:' . $team->getId()], '$write' => ['user:' . $user->getId(), 'team:' . $team->getId() . '/owner'], 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'teamId' => $team->getId(), + 'teamInternalId' => $team->getInternalId(), 'roles' => $roles, 'invited' => \time(), 'joined' => \time(), @@ -366,7 +368,9 @@ App::post('/v1/teams/:teamId/memberships') '$read' => ['role:all'], '$write' => ['user:' . $invitee->getId(), 'team:' . $team->getId() . '/owner'], 'userId' => $invitee->getId(), + 'userInternalId' => $invitee->getInternalId(), 'teamId' => $team->getId(), + 'teamInternalId' => $team->getInternalId(), 'roles' => $roles, 'invited' => \time(), 'joined' => ($isPrivilegedUser || $isAppUser) ? \time() : 0, @@ -701,6 +705,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status') $session = new Document(array_merge([ '$id' => $dbForProject->getId(), 'userId' => $user->getId(), + 'userInternalId' => $user->getInternalId(), 'provider' => Auth::SESSION_PROVIDER_EMAIL, 'providerUid' => $user->getAttribute('email'), 'secret' => Auth::hash($secret), // One way hash encryption to protect DB leak diff --git a/app/init.php b/app/init.php index 5b3965e41c..5eba16f74a 100644 --- a/app/init.php +++ b/app/init.php @@ -257,7 +257,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('attributes', [ - new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], $database->getAttributeLimit()); } ); @@ -270,7 +270,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('indexes', [ - new Query('collectionId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('collectionInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], 64); } ); @@ -283,7 +283,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('platforms', [ - new Query('projectId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY); } ); @@ -296,7 +296,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('domains', [ - new Query('projectId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY); } ); @@ -309,7 +309,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('keys', [ - new Query('projectId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY); } ); @@ -322,7 +322,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return $database ->find('webhooks', [ - new Query('projectId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('projectInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY); } ); @@ -334,7 +334,7 @@ Database::addFilter( }, function (mixed $value, Document $document, Database $database) { return Authorization::skip(fn () => $database->find('sessions', [ - new Query('userId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY)); } ); @@ -347,7 +347,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return Authorization::skip(fn() => $database ->find('tokens', [ - new Query('userId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY)); } ); @@ -360,7 +360,7 @@ Database::addFilter( function (mixed $value, Document $document, Database $database) { return Authorization::skip(fn() => $database ->find('memberships', [ - new Query('userId', Query::TYPE_EQUAL, [$document->getId()]) + new Query('userInternalId', Query::TYPE_EQUAL, [$document->getInternalId()]) ], APP_LIMIT_SUBQUERY)); } ); @@ -842,6 +842,7 @@ App::setResource('project', function ($dbForConsole, $request, $console) { App::setResource('console', function () { return new Document([ '$id' => 'console', + '$internalId' => 'console', 'name' => 'Appwrite', '$collection' => 'projects', 'description' => 'Appwrite core engine', @@ -871,12 +872,12 @@ App::setResource('console', function () { ]); }, []); -App::setResource('dbForProject', function ($db, $cache, $project) { +App::setResource('dbForProject', function ($db, $cache, Document $project) { $cache = new Cache(new RedisCache($cache)); $database = new Database(new MariaDB($db), $cache); $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $database->setNamespace("_{$project->getId()}"); + $database->setNamespace("_{$project->getInternalId()}"); return $database; }, ['db', 'cache', 'project']); diff --git a/app/realtime.php b/app/realtime.php index 7f3264f315..c14629c697 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -150,6 +150,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume 'timestamp' => time(), 'value' => '{}' ]); + $statsDocument = Authorization::skip(fn () => $database->createDocument('realtime', $document)); } catch (\Throwable $th) { call_user_func($logError, $th, "createWorkerDocument"); @@ -297,7 +298,9 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); - [$database, $returnDatabase] = getDatabase($register, "_{$projectId}"); + [$consoleDatabase, $returnConsoleDatabase] = getDatabase($register, '_console'); + $project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId)); + [$database, $returnDatabase] = getDatabase($register, "_{$project->getInternalId()}"); $user = $database->getDocument('users', $userId); @@ -306,6 +309,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']); call_user_func($returnDatabase); + call_user_func($returnConsoleDatabase); } } @@ -373,7 +377,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $cache = new Cache(new RedisCache($redis)); $database = new Database(new MariaDB($db), $cache); $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $database->setNamespace("_{$project->getId()}"); + $database->setNamespace("_{$project->getInternalId()}"); /* * Project Check @@ -480,7 +484,9 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $cache = new Cache(new RedisCache($redis)); $database = new Database(new MariaDB($db), $cache); $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $database->setNamespace("_{$realtime->connections[$connection]['projectId']}"); + $database->setNamespace("_console"); + $project = Authorization::skip(fn() => $database->getDocument('projects', $realtime->connections[$connection]['projectId'])); + $database->setNamespace("_{$project->getInternalId()}"); /* * Abuse Check diff --git a/app/tasks/usage.php b/app/tasks/usage.php index 106ace9107..26e47adfea 100644 --- a/app/tasks/usage.php +++ b/app/tasks/usage.php @@ -15,6 +15,9 @@ use Utopia\Database\Validator\Authorization; use Utopia\Registry\Registry; use Utopia\Logger\Log; +Authorization::disable(); +Authorization::setDefaultStatus(false); + function getDatabase(Registry &$register, string $namespace): Database { $attempts = 0; @@ -120,11 +123,8 @@ $cli $influxDB = getInfluxDB($register); $usage = new Usage($database, $influxDB, $logError); - $usageDB = new UsageDB($database, $logError); - Authorization::disable(); - $iterations = 0; Console::loop(function () use ($interval, $usage, $usageDB, &$iterations) { $now = date('d-m-Y H:i:s', time()); diff --git a/app/workers/builds.php b/app/workers/builds.php index 14986c5354..2d2f66bb72 100644 --- a/app/workers/builds.php +++ b/app/workers/builds.php @@ -15,9 +15,6 @@ use Utopia\Config\Config; require_once __DIR__ . '/../init.php'; -// Disable Auth since we already validate it in the API -Authorization::disable(); - Console::title('Builds V1 Worker'); Console::success(APP_NAME . ' build worker v1 has started'); diff --git a/app/workers/certificates.php b/app/workers/certificates.php index c32b44f49f..b31f4ed91f 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -36,8 +36,6 @@ class CertificatesV1 extends Worker public function run(): void { - Authorization::disable(); - Authorization::setDefaultStatus(false); /** * 1. Read arguments and validate domain * 2. Get main domain diff --git a/app/workers/database.php b/app/workers/database.php index 7b3d08a5f2..606d7ea4c8 100644 --- a/app/workers/database.php +++ b/app/workers/database.php @@ -5,7 +5,6 @@ use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Resque\Worker; use Utopia\CLI\Console; use Utopia\Database\Document; -use Utopia\Database\Validator\Authorization; require_once __DIR__ . '/../init.php'; @@ -20,8 +19,6 @@ class DatabaseV1 extends Worker public function run(): void { - Authorization::disable(); - $type = $this->args['type']; $project = new Document($this->args['project']); $collection = new Document($this->args['collection'] ?? []); @@ -53,8 +50,6 @@ class DatabaseV1 extends Worker Console::error('No database operation for type: ' . $type); break; } - - Authorization::reset(); } public function shutdown(): void diff --git a/app/workers/deletes.php b/app/workers/deletes.php index ffe93d6d09..c1ce85ec90 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -15,9 +15,6 @@ use Utopia\Audit\Audit; require_once __DIR__ . '/../init.php'; -Authorization::disable(); -Authorization::setDefaultStatus(false); - Console::title('Deletes V1 Worker'); Console::success(APP_NAME . ' deletes worker v1 has started' . "\n"); diff --git a/app/workers/functions.php b/app/workers/functions.php index 004d28e2ac..55d71ef368 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -44,6 +44,10 @@ class FunctionsV1 extends Worker $user = new Document($this->args['user'] ?? []); $payload = json_encode($this->args['payload'] ?? []); + if ($project->getId() === 'console') { + return; + } + $database = $this->getProjectDB($project->getId()); /** @@ -57,7 +61,7 @@ class FunctionsV1 extends Worker /** @var Document[] $functions */ while ($sum >= $limit) { - $functions = Authorization::skip(fn () => $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC])); + $functions = $database->find('functions', [], $limit, $offset, ['name'], [Database::ORDER_ASC]); $sum = \count($functions); $offset = $offset + $limit; @@ -101,7 +105,7 @@ class FunctionsV1 extends Worker $jwt = $this->args['jwt'] ?? ''; $data = $this->args['data'] ?? ''; - $function = Authorization::skip(fn () => $database->getDocument('functions', $execution->getAttribute('functionId'))); + $function = $database->getDocument('functions', $execution->getAttribute('functionId')); $this->execute( project: $project, @@ -132,7 +136,7 @@ class FunctionsV1 extends Worker */ // Reschedule - $function = Authorization::skip(fn () => $database->getDocument('functions', $function->getId())); + $function = $database->getDocument('functions', $function->getId()); if (empty($function->getId())) { throw new Exception('Function not found (' . $function->getId() . ')'); @@ -149,11 +153,11 @@ class FunctionsV1 extends Worker ->setAttribute('scheduleNext', $next) ->setAttribute('schedulePrevious', \time()); - $function = Authorization::skip(fn () => $database->updateDocument( + $function = $database->updateDocument( 'functions', $function->getId(), $function->setAttribute('scheduleNext', (int) $next) - )); + ); if ($function === false) { throw new Exception('Function update failed.'); @@ -198,7 +202,7 @@ class FunctionsV1 extends Worker $deploymentId = $function->getAttribute('deployment', ''); /** Check if deployment exists */ - $deployment = Authorization::skip(fn () => $dbForProject->getDocument('deployments', $deploymentId)); + $deployment = $dbForProject->getDocument('deployments', $deploymentId); if ($deployment->getAttribute('resourceId') !== $functionId) { throw new Exception('Deployment not found. Create deployment before trying to execute a function', 404); @@ -209,7 +213,7 @@ class FunctionsV1 extends Worker } /** Check if build has exists */ - $build = Authorization::skip(fn () => $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', ''))); + $build = $dbForProject->getDocument('builds', $deployment->getAttribute('buildId', '')); if ($build->isEmpty()) { throw new Exception('Build not found', 404); } @@ -227,38 +231,31 @@ class FunctionsV1 extends Worker $runtime = $runtimes[$function->getAttribute('runtime')]; - /** - * Create execution or update execution status - * @var Document $execution - */ - $execution = Authorization::skip(function () use ($dbForProject, &$executionId, $functionId, $deploymentId, $trigger, $user) { - $execution = $dbForProject->getDocument('executions', $executionId ?? ''); + /** Create execution or update execution status */ + $execution = $dbForProject->getDocument('executions', $executionId ?? ''); + if ($execution->isEmpty()) { + $executionId = $dbForProject->getId(); + $execution = $dbForProject->createDocument('executions', new Document([ + '$id' => $executionId, + '$read' => $user->isEmpty() ? [] : ['user:' . $user->getId()], + '$write' => [], + 'functionId' => $functionId, + 'deploymentId' => $deploymentId, + 'trigger' => $trigger, + 'status' => 'waiting', + 'statusCode' => 0, + 'response' => '', + 'stderr' => '', + 'time' => 0.0, + 'search' => implode(' ', [$functionId, $executionId]), + ])); + if ($execution->isEmpty()) { - $executionId = $dbForProject->getId(); - $execution = $dbForProject->createDocument('executions', new Document([ - '$id' => $executionId, - '$read' => $user->isEmpty() ? [] : ['user:' . $user->getId()], - '$write' => [], - 'functionId' => $functionId, - 'deploymentId' => $deploymentId, - 'trigger' => $trigger, - 'status' => 'waiting', - 'statusCode' => 0, - 'response' => '', - 'stderr' => '', - 'time' => 0.0, - 'search' => implode(' ', [$functionId, $executionId]), - ])); - - if ($execution->isEmpty()) { - throw new Exception('Failed to create or read execution'); - } + throw new Exception('Failed to create or read execution'); } - $execution->setAttribute('status', 'processing'); - $execution = $dbForProject->updateDocument('executions', $executionId, $execution); - - return $execution; - }); + } + $execution->setAttribute('status', 'processing'); + $execution = $dbForProject->updateDocument('executions', $executionId, $execution); /** Collect environment variables */ $vars = [ @@ -309,8 +306,7 @@ class FunctionsV1 extends Worker Console::error($th->getMessage()); } - $execution = Authorization::skip(fn () => $dbForProject->updateDocument('executions', $executionId, $execution)); - /** @var Document $execution */ + $execution = $dbForProject->updateDocument('executions', $executionId, $execution); /** Trigger Webhook */ $executionModel = new Execution(); diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 84feb0f961..40adc3e52e 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -17,6 +17,7 @@ use Utopia\Storage\Device\Wasabi; use Utopia\Storage\Device\Backblaze; use Utopia\Storage\Device\S3; use Exception; +use Utopia\Database\Validator\Authorization; abstract class Worker { @@ -112,6 +113,11 @@ abstract class Worker public function perform(): void { try { + /** + * Disabling global authorization in workers. + */ + Authorization::disable(); + Authorization::setDefaultStatus(false); $this->run(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { @@ -159,7 +165,16 @@ abstract class Worker */ protected function getProjectDB(string $projectId): Database { - return $this->getDB(self::DATABASE_PROJECT, $projectId); + $consoleDB = $this->getConsoleDB(); + + if ($projectId === 'console') { + return $consoleDB; + } + + /** @var Document $project */ + $project = Authorization::skip(fn() => $consoleDB->getDocument('projects', $projectId)); + + return $this->getDB(self::DATABASE_PROJECT, $projectId, $project->getInternalId()); } /** @@ -177,7 +192,7 @@ abstract class Worker * @param string $projectId of internal or external DB * @return Database */ - private function getDB($type, $projectId = ''): Database + private function getDB(string $type, string $projectId = '', string $projectInternalId = ''): Database { global $register; @@ -189,7 +204,7 @@ abstract class Worker if (!$projectId) { throw new \Exception('ProjectID not provided - cannot get database'); } - $namespace = "_{$projectId}"; + $namespace = "_{$projectInternalId}"; break; case self::DATABASE_CONSOLE: $namespace = "_console"; diff --git a/src/Appwrite/Stats/Usage.php b/src/Appwrite/Stats/Usage.php index 9a885c011f..4d3b09f847 100644 --- a/src/Appwrite/Stats/Usage.php +++ b/src/Appwrite/Stats/Usage.php @@ -180,7 +180,10 @@ class Usage private function createOrUpdateMetric(string $projectId, int $time, string $period, string $metric, int $value, int $type): void { $id = \md5("{$time}_{$period}_{$metric}"); - $this->database->setNamespace('_' . $projectId); + $this->database->setNamespace('_console'); + $project = $this->database->getDocument('projects', $projectId); + $this->database->setNamespace('_' . $project->getInternalId()); + try { $document = $this->database->getDocument('stats', $id); if ($document->isEmpty()) { diff --git a/src/Appwrite/Stats/UsageDB.php b/src/Appwrite/Stats/UsageDB.php index cc312b69ac..0295b860cd 100644 --- a/src/Appwrite/Stats/UsageDB.php +++ b/src/Appwrite/Stats/UsageDB.php @@ -28,7 +28,10 @@ class UsageDB extends Usage $period = $options['key']; $time = (int) (floor(time() / $options['multiplier']) * $options['multiplier']); $id = \md5("{$time}_{$period}_{$metric}"); - $this->database->setNamespace('_' . $projectId); + $this->database->setNamespace('_console'); + $project = $this->database->getDocument('projects', $projectId); + $this->database->setNamespace('_' . $project->getInternalId()); + try { $document = $this->database->getDocument('stats', $id); if ($document->isEmpty()) { @@ -70,15 +73,21 @@ class UsageDB extends Usage */ private function foreachDocument(string $projectId, string $collection, array $queries, callable $callback): void { + if ($projectId === 'console') { + return; + } + $limit = 50; $results = []; $sum = $limit; $latestDocument = null; - $this->database->setNamespace('_' . $projectId); + $this->database->setNamespace('_console'); + $project = $this->database->getDocument('projects', $projectId); + $this->database->setNamespace('_' . $project->getInternalId()); while ($sum === $limit) { try { - $results = $this->database->find($collection, $queries, $limit, cursor:$latestDocument); + $results = $this->database->find($collection, $queries, $limit, cursor: $latestDocument); } catch (\Exception $e) { if (is_callable($this->errorHandler)) { call_user_func($this->errorHandler, $e, "fetch_documents_project_{$projectId}_collection_{$collection}"); @@ -115,7 +124,10 @@ class UsageDB extends Usage */ private function sum(string $projectId, string $collection, string $attribute, string $metric): int { - $this->database->setNamespace('_' . $projectId); + $this->database->setNamespace('_console'); + $project = $this->database->getDocument('projects', $projectId); + $this->database->setNamespace('_' . $project->getInternalId()); + try { $sum = (int) $this->database->sum($collection, $attribute); $this->createOrUpdateMetric($projectId, $metric, $sum); @@ -141,7 +153,10 @@ class UsageDB extends Usage */ private function count(string $projectId, string $collection, string $metric): int { - $this->database->setNamespace("_{$projectId}"); + $this->database->setNamespace('_console'); + $project = $this->database->getDocument('projects', $projectId); + $this->database->setNamespace('_' . $project->getInternalId()); + try { $count = $this->database->count($collection); $this->createOrUpdateMetric($projectId, $metric, $count); @@ -252,11 +267,12 @@ class UsageDB extends Usage */ public function collect(): void { - $this->foreachDocument('console', 'projects', [], function ($project) { - $projectId = $project->getId(); - $this->usersStats($projectId); - $this->databaseStats($projectId); - $this->storageStats($projectId); + $this->foreachDocument('console', 'projects', [], function (Document $project) { + $projectId = $project->getId(); + + $this->usersStats($projectId); + $this->databaseStats($projectId); + $this->storageStats($projectId); }); } } diff --git a/tests/e2e/Services/Database/DatabaseCustomServerTest.php b/tests/e2e/Services/Database/DatabaseCustomServerTest.php index c423eb9094..b2f2b4267c 100644 --- a/tests/e2e/Services/Database/DatabaseCustomServerTest.php +++ b/tests/e2e/Services/Database/DatabaseCustomServerTest.php @@ -789,7 +789,7 @@ class DatabaseCustomServerTest extends Scope $this->assertEquals('available', $attribute['status'], 'attribute: ' . $attribute['key']); } - // testing for indexLimit = 64 + // Test indexLimit = 64 // MariaDB, MySQL, and MongoDB create 5 indexes per new collection // Add up to the limit, then check if the next index throws IndexLimitException for ($i = 0; $i < 59; $i++) { diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 9553b540fe..444611e07a 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -587,6 +587,7 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ + $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $data['functionId'] . '/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php index 9d75bc159e..bed1033d05 100644 --- a/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php +++ b/tests/e2e/Services/Realtime/RealtimeConsoleClientTest.php @@ -75,14 +75,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*.create", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.create", $response['data']['events']); $this->assertContains("collections.*.attributes.*.create", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.*.attributes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); @@ -97,14 +93,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*.update", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.update", $response['data']['events']); $this->assertContains("collections.*.attributes.*.update", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.*.attributes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); @@ -165,14 +157,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*.create", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.create", $response['data']['events']); $this->assertContains("collections.*.indexes.*.create", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.*.indexes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); @@ -187,14 +175,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*.update", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.update", $response['data']['events']); $this->assertContains("collections.*.indexes.*.update", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.*.indexes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); @@ -247,14 +231,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*.delete", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.indexes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $response['data']['events']); $this->assertContains("collections.*.indexes.*.delete", $response['data']['events']); - $this->assertContains("collections.*.indexes.{$actorsId}_{$indexKey}", $response['data']['events']); $this->assertContains("collections.*.indexes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); @@ -306,14 +286,10 @@ class RealtimeConsoleClientTest extends Scope $this->assertArrayHasKey('timestamp', $response['data']); $this->assertCount(1, $response['data']['channels']); $this->assertContains('console', $response['data']['channels']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*.delete", $response['data']['events']); - $this->assertContains("collections.{$actorsId}.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.{$actorsId}.attributes.*", $response['data']['events']); $this->assertContains("collections.{$actorsId}", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}.delete", $response['data']['events']); $this->assertContains("collections.*.attributes.*.delete", $response['data']['events']); - $this->assertContains("collections.*.attributes.{$actorsId}_{$attributeKey}", $response['data']['events']); $this->assertContains("collections.*.attributes.*", $response['data']['events']); $this->assertContains("collections.*", $response['data']['events']); $this->assertNotEmpty($response['data']['payload']); diff --git a/tests/e2e/Services/Webhooks/WebhooksBase.php b/tests/e2e/Services/Webhooks/WebhooksBase.php index 2818890a35..b3adec1bf4 100644 --- a/tests/e2e/Services/Webhooks/WebhooksBase.php +++ b/tests/e2e/Services/Webhooks/WebhooksBase.php @@ -119,13 +119,9 @@ trait WebhooksBase $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.attributes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.attributes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); @@ -149,13 +145,9 @@ trait WebhooksBase $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.attributes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.attributes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.attributes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.attributes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.attributes.{$actorsId}_{$attributeId}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); diff --git a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php index 541e81633a..7d9fbaaee4 100644 --- a/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php +++ b/tests/e2e/Services/Webhooks/WebhooksCustomServerTest.php @@ -95,13 +95,9 @@ class WebhooksCustomServerTest extends Scope $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.indexes.*.create', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.indexes.*.create", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.create", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']); @@ -124,13 +120,9 @@ class WebhooksCustomServerTest extends Scope $this->assertStringContainsString('collections.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.indexes.*', $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString('collections.*.indexes.*.delete', $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.*.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.indexes.*", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertStringContainsString("collections.{$actorsId}.indexes.*.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}", $webhook['headers']['X-Appwrite-Webhook-Events']); - $this->assertStringContainsString("collections.{$actorsId}.indexes.{$actorsId}_{$indexKey}.delete", $webhook['headers']['X-Appwrite-Webhook-Events']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Signature'], $signatureExpected); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Id'] ?? '', $this->getProject()['webhookId']); $this->assertEquals($webhook['headers']['X-Appwrite-Webhook-Project-Id'] ?? '', $this->getProject()['$id']);