From a3aeecfd0db1ee8b2efdd719aebda7b828044c00 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 21 Jun 2020 15:12:13 +0300 Subject: [PATCH 1/3] Removed first and last params --- CHANGES.md | 3 +++ app/controllers/api/database.php | 46 +++++++++++++------------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 233301df9e..9833893b5d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -32,6 +32,9 @@ - Fixed missing custom scopes param for OAuth2 session create API route - Fixed wrong JSON validation when creating and updating database documnets +## Breaking Changes +- **Deprecated** `first` and `last` query params for documents list route in the database API + ## Security - Access to Health API now requires authentication with an API Key with access to `health.read` scope allowed diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index d8ecedab84..957d90d7b5 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -477,10 +477,8 @@ $utopia->get('/v1/database/collections/:collectionId/documents') ->param('orderType', 'ASC', function () { return new WhiteList(array('DESC', 'ASC')); }, 'Order direction. Possible values are DESC for descending order, or ASC for ascending order.', true) ->param('orderCast', 'string', function () { return new WhiteList(array('int', 'string', 'date', 'time', 'datetime')); }, 'Order field type casting. Possible values are int, string, date, time or datetime. The database will attempt to cast the order field to the value you pass here. The default value is a string.', true) ->param('search', '', function () { return new Text(256); }, 'Search query. Enter any free text search. The database will try to find a match against all document attributes and children.', true) - ->param('first', 0, function () { return new Range(0, 1); }, 'Return only the first document. Pass 1 for true or 0 for false. The default value is 0.', true) - ->param('last', 0, function () { return new Range(0, 1); }, 'Return only the last document. Pass 1 for true or 0 for false. The default value is 0.', true) ->action( - function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search, $first, $last) use ($response, $projectDB, $isDev) { + function ($collectionId, $filters, $offset, $limit, $orderField, $orderType, $orderCast, $search) use ($response, $projectDB, $isDev) { $collection = $projectDB->getDocument($collectionId, $isDev); if (\is_null($collection->getId()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) { @@ -494,38 +492,32 @@ $utopia->get('/v1/database/collections/:collectionId/documents') 'orderType' => $orderType, 'orderCast' => $orderCast, 'search' => $search, - 'first' => (bool) $first, - 'last' => (bool) $last, 'filters' => \array_merge($filters, [ '$collection='.$collectionId, ]), ]); - if ($first || $last) { - $response->json((!empty($list) ? $list->getArrayCopy() : [])); - } else { - if ($isDev) { - $collection - ->setAttribute('debug', $projectDB->getDebug()) - ->setAttribute('limit', $limit) - ->setAttribute('offset', $offset) - ->setAttribute('orderField', $orderField) - ->setAttribute('orderType', $orderType) - ->setAttribute('orderCast', $orderCast) - ->setAttribute('filters', $filters) - ; - } - + if ($isDev) { $collection - ->setAttribute('sum', $projectDB->getSum()) - ->setAttribute('documents', $list) + ->setAttribute('debug', $projectDB->getDebug()) + ->setAttribute('limit', $limit) + ->setAttribute('offset', $offset) + ->setAttribute('orderField', $orderField) + ->setAttribute('orderType', $orderType) + ->setAttribute('orderCast', $orderCast) + ->setAttribute('filters', $filters) ; - - /* - * View - */ - $response->json($collection->getArrayCopy(/*['$id', '$collection', 'name', 'documents']*/[], ['rules'])); } + + $collection + ->setAttribute('sum', $projectDB->getSum()) + ->setAttribute('documents', $list) + ; + + /* + * View + */ + $response->json($collection->getArrayCopy(/*['$id', '$collection', 'name', 'documents']*/[], ['rules'])); } ); From bd073da05e816a18adfaece67f2f7566a3bf14c0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 21 Jun 2020 15:23:50 +0300 Subject: [PATCH 2/3] Fixed tests --- tests/e2e/Services/Database/DatabaseBase.php | 35 -------------------- 1 file changed, 35 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 60dc1f81cc..7e68940104 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -317,41 +317,6 @@ trait DatabaseBase return []; } - /** - * @depends testCreateDocument - */ - public function testListDocumentsFirstAndLast(array $data):array - { - $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'limit' => 1, - 'orderField' => 'releaseYear', - 'orderType' => 'ASC', - 'orderCast' => 'int', - 'first' => true, - ]); - - $this->assertEquals(1944, $documents['body']['releaseYear']); - - $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'limit' => 2, - 'offset' => 1, - 'orderField' => 'releaseYear', - 'orderType' => 'ASC', - 'orderCast' => 'int', - 'last' => true, - ]); - - $this->assertEquals(2019, $documents['body']['releaseYear']); - - return []; - } - /** * @depends testCreateDocument */ From 7c2969b967c6f107a3970e56baf7d33eed0236d2 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 26 Jun 2020 17:41:13 +0300 Subject: [PATCH 3/3] Removed first and last from internal functions --- app/controllers/api/account.php | 24 ++++++++-------------- app/controllers/api/teams.php | 6 ++---- app/controllers/api/users.php | 3 +-- app/workers/certificates.php | 3 +-- src/Appwrite/Database/Database.php | 32 ++++++++++++++++++++---------- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index a7c1c2c534..10665bf740 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -80,9 +80,8 @@ $utopia->post('/v1/account') } } - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -163,9 +162,8 @@ $utopia->post('/v1/account/sessions') ->action( function ($email, $password) use ($response, $request, $projectDB, $audit, $webhook) { $protocol = Config::getParam('protocol'); - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -414,9 +412,8 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') $projectDB->deleteDocument($current); //throw new Exception('User already logged in', 401); } - $user = (empty($user->getId())) ? $projectDB->getCollection([ // Get user by provider id + $user = (empty($user->getId())) ? $projectDB->getCollectionFirst([ // Get user by provider id 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'oauth2'.\ucfirst($provider).'='.$oauth2ID, @@ -427,9 +424,8 @@ $utopia->get('/v1/account/sessions/oauth2/:provider/redirect') $name = $oauth2->getUserName($accessToken); $email = $oauth2->getUserEmail($accessToken); - $user = $projectDB->getCollection([ // Get user by provider email address + $user = $projectDB->getCollectionFirst([ // Get user by provider email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -797,9 +793,8 @@ $utopia->patch('/v1/account/email') throw new Exception('Invalid credentials', 401); } - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -1056,9 +1051,8 @@ $utopia->post('/v1/account/recovery') ->param('url', '', function () use ($clients) { return new Host($clients); }, 'URL to redirect the user back to your app from the recovery email. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.') ->action( function ($email, $url) use ($request, $response, $projectDB, $mail, $audit, $project) { - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -1161,9 +1155,8 @@ $utopia->put('/v1/account/recovery') throw new Exception('Passwords must match', 400); } - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, '$id='.$userId, @@ -1311,9 +1304,8 @@ $utopia->put('/v1/account/verification') ->param('secret', '', function () { return new Text(256); }, 'Valid verification token.') ->action( function ($userId, $secret) use ($response, $user, $projectDB, $audit) { - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, '$id='.$userId, diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b8e0bf1194..95dad48562 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -232,9 +232,8 @@ $utopia->post('/v1/teams/:teamId/memberships') ], ]); - $invitee = $projectDB->getCollection([ // Get user by email address + $invitee = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, @@ -480,9 +479,8 @@ $utopia->patch('/v1/teams/:teamId/memberships/:inviteId/status') } if (empty($user->getId())) { - $user = $projectDB->getCollection([ // Get user + $user = $projectDB->getCollectionFirst([ // Get user 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, '$id='.$userId, diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index d032cef947..1324c559ac 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -35,9 +35,8 @@ $utopia->post('/v1/users') ->param('name', '', function () { return new Text(100); }, 'User name.', true) ->action( function ($email, $password, $name) use ($response, $projectDB) { - $profile = $projectDB->getCollection([ // Get user by email address + $profile = $projectDB->getCollectionFirst([ // Get user by email address 'limit' => 1, - 'first' => true, 'filters' => [ '$collection='.Database::SYSTEM_COLLECTION_USERS, 'email='.$email, diff --git a/app/workers/certificates.php b/app/workers/certificates.php index b04c7409c0..22c3a14e63 100644 --- a/app/workers/certificates.php +++ b/app/workers/certificates.php @@ -77,7 +77,7 @@ class CertificatesV1 } } - $certificate = $consoleDB->getCollection([ + $certificate = $consoleDB->getCollectionFirst([ 'limit' => 1, 'offset' => 0, 'orderField' => 'id', @@ -87,7 +87,6 @@ class CertificatesV1 '$collection='.Database::SYSTEM_COLLECTION_CERTIFICATES, 'domain='.$domain->get(), ], - 'first' => true, ]); // $condition = ($certificate diff --git a/src/Appwrite/Database/Database.php b/src/Appwrite/Database/Database.php index e75eb01b51..45b61cd089 100644 --- a/src/Appwrite/Database/Database.php +++ b/src/Appwrite/Database/Database.php @@ -130,8 +130,6 @@ class Database 'orderField' => '$id', 'orderType' => 'ASC', 'orderCast' => 'int', - 'first' => false, - 'last' => false, 'filters' => [], ], $options); @@ -141,17 +139,31 @@ class Database $node = new Document($node); } - if ($options['first']) { - $results = \reset($results); - } - - if ($options['last']) { - $results = \end($results); - } - return $results; } + /** + * @param array $options + * + * @return Document + */ + public function getCollectionFirst(array $options) + { + $results = $this->getCollection($options); + return \reset($results); + } + + /** + * @param array $options + * + * @return Document + */ + public function getCollectionLast(array $options) + { + $results = $this->getCollection($options); + return \end($results); + } + /** * @param int $id * @param bool $mock is mocked data allowed?