From bb2b48193f33b5ff076759a957609b108597acf8 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 12 Apr 2023 12:06:48 -0700 Subject: [PATCH 01/25] Ensure empty team prefs returns as JSON object rather array --- src/Appwrite/Utopia/Response/Model/Team.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/Team.php b/src/Appwrite/Utopia/Response/Model/Team.php index 62df089438..d080a82bb1 100644 --- a/src/Appwrite/Utopia/Response/Model/Team.php +++ b/src/Appwrite/Utopia/Response/Model/Team.php @@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use Utopia\Database\Document; class Team extends Model { @@ -49,6 +50,24 @@ class Team extends Model ; } + /** + * Process Document before returning it to the client + * + * @return Document + */ + public function filter(Document $document): Document + { + $prefs = $document->getAttribute('prefs'); + if ($prefs instanceof Document) { + $prefs = $prefs->getArrayCopy(); + } + + if (is_array($prefs) && empty($prefs)) { + $document->setAttribute('prefs', new \stdClass()); + } + return $document; + } + /** * Get Name * From c7317b04683df8c3583514415f989755c2a3f35d Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 13 Apr 2023 15:59:57 +1200 Subject: [PATCH 02/25] Fix auto-setting custom ID on nested documents --- app/controllers/api/databases.php | 48 ++++++++++++++++--- .../e2e/Services/Databases/DatabasesBase.php | 22 ++++++++- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index b309b74894..4e3661e9ac 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2743,8 +2743,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') if (empty($related)) { continue; } - if (!\is_array($related)) { - $related = [$related]; + + if (\is_array($related) && \array_values($related) === $related) { + $relations = $related; + } else { + $relations = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); @@ -2752,7 +2755,15 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($related as $relation) { + foreach ($relations as &$relation) { + if ( + \is_array($related) + && \array_values($related) !== $related + && !isset($relation['$id']) + ) { + $relation['$id'] = ID::unique(); + $relation = new Document($relation); + } if ($relation instanceof Document) { $current = Authorization::skip( fn() => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), $relation->getId()) @@ -2761,7 +2772,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') if ($current->isEmpty()) { $type = Database::PERMISSION_CREATE; - if (!isset($relation['$id']) || $relation['$id'] === 'unique()') { + if (isset($relation['$id']) && $relation['$id'] === 'unique()') { $relation['$id'] = ID::unique(); } } else { @@ -2774,6 +2785,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') $checkPermissions($relatedCollection, $relation, $type); } } + + if (\is_array($related) && \array_values($related) === $related) { + $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); + } else { + $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); + } } }; @@ -3321,8 +3338,11 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if (empty($related)) { continue; } - if (!\is_array($related)) { - $related = [$related]; + + if (\is_array($related) && \array_values($related) === $related) { + $relations = $related; + } else { + $relations = [$related]; } $relatedCollectionId = $relationship->getAttribute('relatedCollection'); @@ -3331,6 +3351,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum ); foreach ($related as $relation) { + if ( + \is_array($relation) + && \array_values($relation) !== $relation + && !isset($relation['$id']) + ) { + $relation['$id'] = ID::unique(); + $relation = new Document($relation); + } if ($relation instanceof Document) { $oldDocument = Authorization::skip(fn() => $dbForProject->getDocument( 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(), @@ -3340,7 +3368,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum if ($oldDocument->isEmpty()) { $type = Database::PERMISSION_CREATE; - if (!isset($relation['$id']) || $relation['$id'] === 'unique()') { + if (isset($relation['$id']) && $relation['$id'] === 'unique()') { $relation['$id'] = ID::unique(); } } else { @@ -3353,6 +3381,12 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($relatedCollection, $relation, $oldDocument, $type); } } + + if (\is_array($related) && \array_values($related) === $related) { + $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); + } else { + $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); + } } }; diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 42f83ea046..a2cb48cf93 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -3339,6 +3339,26 @@ trait DatabasesBase $this->assertEquals('Library 1', $person1['body']['library']['libraryName']); + // Create without nested ID + $person2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $person['body']['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documentId' => ID::unique(), + 'data' => [ + 'library' => [ + 'libraryName' => 'Library 2', + ], + ], + 'permissions' => [ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ] + ]); + + $this->assertEquals('Library 2', $person2['body']['library']['libraryName']); + // Ensure IDs were set and internal IDs removed $this->assertEquals($databaseId, $person1['body']['$databaseId']); $this->assertEquals($databaseId, $person1['body']['library']['$databaseId']); @@ -3901,7 +3921,7 @@ trait DatabasesBase ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, count($response['body']['documents'])); + $this->assertEquals(2, count($response['body']['documents'])); $this->assertEquals(null, $response['body']['documents'][0]['fullName']); $this->assertArrayNotHasKey("libraries", $response['body']['documents'][0]); } From 975b044de08ff5653f89b63f140d29cf7c94e092 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 13 Apr 2023 16:08:53 +1200 Subject: [PATCH 03/25] Iterate relation by reference on update --- app/controllers/api/databases.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 4e3661e9ac..0fbb74f564 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -3350,7 +3350,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($related as $relation) { + foreach ($related as &$relation) { if ( \is_array($relation) && \array_values($relation) !== $relation From 08be9c4c890635d60561c9ec8dd99e200edda670 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 13 Apr 2023 16:35:42 +1200 Subject: [PATCH 04/25] Update changelog --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 21501b1bd5..5ab6e586cf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +# Version 1.3.2 + +## Bugs +- Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363) + # Version 1.3.1 ## Bugs From 0dea80c9dac6982f4dd22390d0a42dc356e1a91c Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 14 Apr 2023 22:03:16 +1200 Subject: [PATCH 05/25] Cache whether relation is a list --- app/controllers/api/databases.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 0fbb74f564..5146c945ea 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2744,7 +2744,9 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') continue; } - if (\is_array($related) && \array_values($related) === $related) { + $isList = \is_array($related) && \array_values($related) === $related; + + if ($isList) { $relations = $related; } else { $relations = [$related]; @@ -2786,7 +2788,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') } } - if (\is_array($related) && \array_values($related) === $related) { + if ($isList) { $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); } else { $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); @@ -3339,7 +3341,9 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum continue; } - if (\is_array($related) && \array_values($related) === $related) { + $isList = \is_array($related) && \array_values($related) === $related; + + if ($isList) { $relations = $related; } else { $relations = [$related]; @@ -3382,7 +3386,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum } } - if (\is_array($related) && \array_values($related) === $related) { + if ($isList) { $document->setAttribute($relationship->getAttribute('key'), \array_values($relations)); } else { $document->setAttribute($relationship->getAttribute('key'), \reset($relations)); From d41df04b6afa647d1c5434d3b700f7519432fdc9 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Fri, 14 Apr 2023 16:18:31 -0700 Subject: [PATCH 06/25] Ensure vars are not lost during upgrade Using a reference on an array element while iterating over it caused some unexpected behavior. Instead of using a reference, this change uses a key to allow us to edit the array element. For reference on the problem, see https://stackoverflow.com/questions/70691375/foreach-with-reference-causing-arrays-last-element-to-repeat. --- app/tasks/install.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/tasks/install.php b/app/tasks/install.php index 3519b58d0b..0f15af2eda 100644 --- a/app/tasks/install.php +++ b/app/tasks/install.php @@ -95,9 +95,9 @@ $cli if (is_null($value)) { continue; } - foreach ($vars as &$var) { + foreach ($vars as $i => $var) { if ($var['name'] === $key) { - $var['default'] = $value; + $vars[$i]['default'] = $value; } } } @@ -114,9 +114,9 @@ $cli if (is_null($value)) { continue; } - foreach ($vars as &$var) { + foreach ($vars as $i => $var) { if ($var['name'] === $key) { - $var['default'] = $value; + $vars[$i]['default'] = $value; } } } @@ -146,7 +146,7 @@ $cli $input = []; - foreach ($vars as $key => $var) { + foreach ($vars as $var) { if (!empty($var['filter']) && ($interactive !== 'Y' || !Console::isInteractive())) { if ($data && $var['default'] !== null) { $input[$var['name']] = $var['default']; From 471c832a4f710f5ce2406369e9becc6f008b066a Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 17 Apr 2023 17:42:10 -0700 Subject: [PATCH 07/25] Bump utopia-php/database version --- composer.json | 2 +- composer.lock | 110 ++++++++++++++++++++++++++------------------------ 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/composer.json b/composer.json index fdd5df4535..112a07e64c 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "utopia-php/cache": "0.8.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.35.*", + "utopia-php/database": "dev-feat-collection-level-permissions as 0.35.9", "utopia-php/domains": "1.1.*", "utopia-php/framework": "0.28.*", "utopia-php/image": "0.5.*", diff --git a/composer.lock b/composer.lock index 2d402ddb31..c81095cb32 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "87de4ea3130e576470a63b21628e30fb", + "content-hash": "4e4bc742147d14591f8e54b63a9dd008", "packages": [ { "name": "adhocore/jwt", @@ -300,16 +300,16 @@ }, { "name": "colinmollenhour/credis", - "version": "v1.14.0", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/colinmollenhour/credis.git", - "reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc" + "reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/dccc8a46586475075fbb012d8bd523b8a938c2dc", - "reference": "dccc8a46586475075fbb012d8bd523b8a938c2dc", + "url": "https://api.github.com/repos/colinmollenhour/credis/zipball/28810439de1d9597b7ba11794ed9479fb6f3de7c", + "reference": "28810439de1d9597b7ba11794ed9479fb6f3de7c", "shasum": "" }, "require": { @@ -341,9 +341,9 @@ "homepage": "https://github.com/colinmollenhour/credis", "support": { "issues": "https://github.com/colinmollenhour/credis/issues", - "source": "https://github.com/colinmollenhour/credis/tree/v1.14.0" + "source": "https://github.com/colinmollenhour/credis/tree/v1.15.0" }, - "time": "2022-11-09T01:18:39+00:00" + "time": "2023-04-18T15:34:23+00:00" }, { "name": "composer/package-versions-deprecated", @@ -481,22 +481,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.5.0", + "version": "7.5.1", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba" + "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b50a2a1251152e43f6a37f0fa053e730a67d25ba", - "reference": "b50a2a1251152e43f6a37f0fa053e730a67d25ba", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b964ca597e86b752cd994f27293e9fa6b6a95ed9", + "reference": "b964ca597e86b752cd994f27293e9fa6b6a95ed9", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/promises": "^1.5", - "guzzlehttp/psr7": "^1.9 || ^2.4", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -589,7 +589,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.5.0" + "source": "https://github.com/guzzle/guzzle/tree/7.5.1" }, "funding": [ { @@ -605,7 +605,7 @@ "type": "tidelift" } ], - "time": "2022-08-28T15:39:27+00:00" + "time": "2023-04-17T16:30:08+00:00" }, { "name": "guzzlehttp/promises", @@ -693,22 +693,22 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.4.4", + "version": "2.5.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf" + "reference": "b635f279edd83fc275f822a1188157ffea568ff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", - "reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/b635f279edd83fc275f822a1188157ffea568ff6", + "reference": "b635f279edd83fc275f822a1188157ffea568ff6", "shasum": "" }, "require": { "php": "^7.2.5 || ^8.0", "psr/http-factory": "^1.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.1 || ^2.0", "ralouphie/getallheaders": "^3.0" }, "provide": { @@ -728,9 +728,6 @@ "bamarni-bin": { "bin-links": true, "forward-command": false - }, - "branch-alias": { - "dev-master": "2.4-dev" } }, "autoload": { @@ -792,7 +789,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.4.4" + "source": "https://github.com/guzzle/psr7/tree/2.5.0" }, "funding": [ { @@ -808,7 +805,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T13:19:02+00:00" + "time": "2023-04-17T16:11:26+00:00" }, { "name": "influxdb/influxdb-php", @@ -1372,16 +1369,16 @@ }, { "name": "psr/http-message", - "version": "1.1", + "version": "2.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", - "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { @@ -1390,7 +1387,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -1405,7 +1402,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for HTTP messages", @@ -1419,9 +1416,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/1.1" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2023-04-04T09:50:52+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { "name": "psr/log", @@ -2112,16 +2109,16 @@ }, { "name": "utopia-php/database", - "version": "0.35.0", + "version": "dev-feat-collection-level-permissions", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2" + "reference": "58e42261d793e806bdfb4a1f7a85a52735a97fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f162c142fd61753c4b413b15c3c4041f3cd00bb2", - "reference": "f162c142fd61753c4b413b15c3c4041f3cd00bb2", + "url": "https://api.github.com/repos/utopia-php/database/zipball/58e42261d793e806bdfb4a1f7a85a52735a97fc4", + "reference": "58e42261d793e806bdfb4a1f7a85a52735a97fc4", "shasum": "" }, "require": { @@ -2164,9 +2161,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.35.0" + "source": "https://github.com/utopia-php/database/tree/feat-collection-level-permissions" }, - "time": "2023-04-11T04:02:22+00:00" + "time": "2023-04-19T23:40:57+00:00" }, { "name": "utopia-php/domains", @@ -3037,16 +3034,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.32.1", + "version": "0.32.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df" + "reference": "cdec289bcf38c99d0074414d2438e9967d0c9699" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/ba1d7afd57e3baef06c04ce6abc26f79310146df", - "reference": "ba1d7afd57e3baef06c04ce6abc26f79310146df", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cdec289bcf38c99d0074414d2438e9967d0c9699", + "reference": "cdec289bcf38c99d0074414d2438e9967d0c9699", "shasum": "" }, "require": { @@ -3082,9 +3079,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/0.32.1" + "source": "https://github.com/appwrite/sdk-generator/tree/0.32.2" }, - "time": "2023-04-12T04:43:07+00:00" + "time": "2023-04-12T21:06:57+00:00" }, { "name": "doctrine/deprecations", @@ -3787,16 +3784,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.18.1", + "version": "1.19.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f" + "reference": "f545fc30978190a056832aa7ed995e36a66267f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f", - "reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/f545fc30978190a056832aa7ed995e36a66267f3", + "reference": "f545fc30978190a056832aa7ed995e36a66267f3", "shasum": "" }, "require": { @@ -3826,9 +3823,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.19.1" }, - "time": "2023-04-07T11:51:11+00:00" + "time": "2023-04-18T11:30:56+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5655,9 +5652,18 @@ "time": "2023-02-08T07:49:20+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-feat-collection-level-permissions", + "alias": "0.35.9", + "alias_normalized": "0.35.9.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 50bb69290f7623dc730df417cd9e962aa85071c2 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 17 Apr 2023 17:40:36 -0700 Subject: [PATCH 08/25] Ensure collections are created with permissions and documentSecurity --- app/controllers/api/databases.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 5146c945ea..4af75839e0 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -743,7 +743,7 @@ App::post('/v1/databases/:databaseId/collections') ])); $collection = $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId); - $dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); + $dbForProject->createCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), permissions: $permissions ?? [], documentSecurity: $documentSecurity); } catch (DuplicateException) { throw new Exception(Exception::COLLECTION_ALREADY_EXISTS); } catch (LimitException) { @@ -1001,6 +1001,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId') ->setAttribute('documentSecurity', $documentSecurity) ->setAttribute('enabled', $enabled) ->setAttribute('search', implode(' ', [$collectionId, $name]))); + $dbForProject->updateCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $permissions, $documentSecurity); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (StructureException $exception) { From 611dd9b86c13c87f6c5f73f990d7c09830dcbeef Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 18 Apr 2023 17:34:39 -0700 Subject: [PATCH 09/25] Return 404 if a user doesn't have access to a collection It is better to return 404 so that an end user doesn't know if the collection actually exists but they don't have access or they really don't have access. --- app/controllers/api/databases.php | 13 ++++++++++--- tests/e2e/Services/Databases/DatabasesBase.php | 4 +--- .../Databases/DatabasesPermissionsTeamTest.php | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 4af75839e0..ba3f0fc378 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2886,12 +2886,19 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $collection = Authorization::skip(fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId)); - if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { - if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { - throw new Exception(Exception::COLLECTION_NOT_FOUND); + if (!($mode === APP_MODE_ADMIN && Auth::isPrivilegedUser(Authorization::getRoles()))) { + if (!$collection->getAttribute('documentSecurity', false)) { + $validator = new Authorization(Database::PERMISSION_READ); + if (!$validator->isValid($collection->getRead())) { + $collection = new Document(); + } } } + if ($collection->isEmpty() || !$collection->getAttribute('enabled')) { + throw new Exception(Exception::COLLECTION_NOT_FOUND); + } + // Validate queries $queriesValidator = new Documents($collection->getAttribute('attributes'), $collection->getAttribute('indexes')); $validQueries = $queriesValidator->isValid($queries); diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index a2cb48cf93..abff3437b8 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -2853,9 +2853,7 @@ trait DatabasesBase ]); // Current user has no collection permissions and document permissions are disabled - $this->assertEquals(200, $documentsUser2['headers']['status-code']); - $this->assertEquals(0, $documentsUser2['body']['total']); - $this->assertEquals(true, empty($documentsUser2['body']['documents'])); + $this->assertEquals(404, $documentsUser2['headers']['status-code']); // Enable document permissions $collection = $this->client->call(CLient::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId, [ diff --git a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php index 1bb42d8cb6..dcbf3e4bff 100644 --- a/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php +++ b/tests/e2e/Services/Databases/DatabasesPermissionsTeamTest.php @@ -176,7 +176,7 @@ class DatabasesPermissionsTeamTest extends Scope if ($success) { $this->assertCount(1, $documents['body']['documents']); } else { - $this->assertCount(0, $documents['body']['documents']); + $this->assertEquals(404, $documents['headers']['status-code']); } } From 37afb82d1c6619434f1ce7a31018c05c36670c64 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 18 Apr 2023 17:37:41 -0700 Subject: [PATCH 10/25] Delegate permissions check to database layer --- app/controllers/api/databases.php | 59 +++++++------------------------ 1 file changed, 12 insertions(+), 47 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index ba3f0fc378..8530e2f27b 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2925,34 +2925,16 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') $filterQueries = Query::groupByType($queries)['filters']; - $documents = Authorization::skip(fn () => $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries)); - - $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - $valid = $validator->isValid($collection->getRead()); - if (!$valid) { - $total = $documentSecurity - ? $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT) - : 0; - } else { - $total = Authorization::skip(fn() => $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT)); - } + $documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries); + $total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT); // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database): bool { - $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - - $valid = $validator->isValid($collection->getRead()); - if (!$documentSecurity && !$valid) { - return false; - } - - $valid = $valid || $validator->isValid($document->getRead()); - if ($documentSecurity && !$valid) { + if ($document->isEmpty()) { return false; } + $document->removeAttribute('$collection'); $document->setAttribute('$databaseId', $database->getId()); $document->setAttribute('$collectionId', $collection->getId()); @@ -2996,18 +2978,10 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents') }; // The linter is forcing this indentation - foreach ($documents as $index => $document) { - if (!$processDocument($collection, $document)) { - unset($documents[$index]); - - if ($valid) { - $total--; - } - } + foreach ($documents as $document) { + $processDocument($collection, $document); } - $documents = \array_values($documents); - $response->dynamic(new Document([ 'total' => $total, 'documents' => $documents, @@ -3062,7 +3036,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen $queries = Query::parseQueries($queries); - $document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries)); + $document = $dbForProject->getDocument('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $documentId, $queries); if ($document->isEmpty()) { throw new Exception(Exception::DOCUMENT_NOT_FOUND); @@ -3070,17 +3044,8 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents/:documen // Add $collectionId and $databaseId for all documents $processDocument = function (Document $collection, Document $document) use (&$processDocument, $dbForProject, $database) { - $documentSecurity = $collection->getAttribute('documentSecurity', false); - $validator = new Authorization(Database::PERMISSION_READ); - - $valid = $validator->isValid($collection->getRead()); - if (!$documentSecurity && !$valid) { - throw new Exception(Exception::DOCUMENT_NOT_FOUND); - } - - $valid = $valid || $validator->isValid($document->getRead()); - if ($documentSecurity && !$valid) { - throw new Exception(Exception::DOCUMENT_NOT_FOUND); + if ($document->isEmpty()) { + return; } $document->setAttribute('$databaseId', $database->getId()); @@ -3362,7 +3327,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum fn() => $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedCollectionId) ); - foreach ($related as &$relation) { + foreach ($relations as &$relation) { if ( \is_array($relation) && \array_values($relation) !== $relation @@ -3405,14 +3370,14 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE); try { - $document = Authorization::skip(fn() => $dbForProject->withRequestTimestamp( + $document = $dbForProject->withRequestTimestamp( $requestTimestamp, fn () => $dbForProject->updateDocument( 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $document->getId(), $newDocument ) - )); + ); } catch (AuthorizationException) { throw new Exception(Exception::USER_UNAUTHORIZED); } catch (DuplicateException) { From 4113ae7ca5bad189e683f18fcabadc92ce65d2e3 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Wed, 19 Apr 2023 17:16:49 -0700 Subject: [PATCH 11/25] Allow updating document with read-only relationship A user should be able to update a document without touching the relationship. Relates: https://github.com/appwrite/appwrite/issues/5404 --- app/controllers/api/databases.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 8530e2f27b..bb41bfb26d 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -3279,7 +3279,6 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $permissions = $document->getPermissions() ?? []; } - $data = \array_merge($document->getArrayCopy(), $data); $data['$collection'] = $collection->getId(); // Make sure user doesn't switch collectionID $data['$createdAt'] = $document->getCreatedAt(); // Make sure user doesn't switch createdAt $data['$id'] = $document->getId(); // Make sure user doesn't switch document unique ID @@ -3369,6 +3368,8 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE); + $data = \array_merge($document->getArrayCopy(), $data); + try { $document = $dbForProject->withRequestTimestamp( $requestTimestamp, From e8dee9296cfb18ff203ca966122b9e4021f73ad6 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 20 Apr 2023 10:10:51 -0700 Subject: [PATCH 12/25] Fix update document not merging existing data --- app/controllers/api/databases.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index bb41bfb26d..b1759ef8b4 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -3368,7 +3368,7 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE); - $data = \array_merge($document->getArrayCopy(), $data); + $newDocument = new Document(\array_merge($document->getArrayCopy(), $data)); try { $document = $dbForProject->withRequestTimestamp( From 023067171721b33f256c50a48d9cd2d70a0f653d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 20 Apr 2023 21:10:48 +0200 Subject: [PATCH 13/25] chore: upgrade utopia-php/database --- composer.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.lock b/composer.lock index c81095cb32..2cef516424 100644 --- a/composer.lock +++ b/composer.lock @@ -2113,12 +2113,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "58e42261d793e806bdfb4a1f7a85a52735a97fc4" + "reference": "9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/58e42261d793e806bdfb4a1f7a85a52735a97fc4", - "reference": "58e42261d793e806bdfb4a1f7a85a52735a97fc4", + "url": "https://api.github.com/repos/utopia-php/database/zipball/9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2", + "reference": "9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2", "shasum": "" }, "require": { @@ -2163,7 +2163,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-collection-level-permissions" }, - "time": "2023-04-19T23:40:57+00:00" + "time": "2023-04-20T18:37:34+00:00" }, { "name": "utopia-php/domains", @@ -3784,16 +3784,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.19.1", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "f545fc30978190a056832aa7ed995e36a66267f3" + "reference": "10553ab3f0337ff1a71433c3417d7eb2a3eec1fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/f545fc30978190a056832aa7ed995e36a66267f3", - "reference": "f545fc30978190a056832aa7ed995e36a66267f3", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/10553ab3f0337ff1a71433c3417d7eb2a3eec1fd", + "reference": "10553ab3f0337ff1a71433c3417d7eb2a3eec1fd", "shasum": "" }, "require": { @@ -3823,9 +3823,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.19.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.0" }, - "time": "2023-04-18T11:30:56+00:00" + "time": "2023-04-20T11:18:07+00:00" }, { "name": "phpunit/php-code-coverage", From 3f72b738fa849602fb02b2494cfd26c054bb21ea Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 20 Apr 2023 18:44:53 -0700 Subject: [PATCH 14/25] Fix related creates --- app/controllers/api/databases.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index b1759ef8b4..8419d0d437 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2760,8 +2760,8 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') foreach ($relations as &$relation) { if ( - \is_array($related) - && \array_values($related) !== $related + \is_array($relation) + && \array_values($relation) !== $relation && !isset($relation['$id']) ) { $relation['$id'] = ID::unique(); From 5925d61a9cad411b660fced3d46a69a444ecf086 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 21 Apr 2023 13:04:37 +0200 Subject: [PATCH 15/25] chore: update composer --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 2cef516424..254c2a4186 100644 --- a/composer.lock +++ b/composer.lock @@ -2113,12 +2113,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2" + "reference": "6ce621ac9d97e3ff18e1595c328526b3050ab68b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2", - "reference": "9cfa9679f4fdbfb81bff1333d516b8b43e77c5c2", + "url": "https://api.github.com/repos/utopia-php/database/zipball/6ce621ac9d97e3ff18e1595c328526b3050ab68b", + "reference": "6ce621ac9d97e3ff18e1595c328526b3050ab68b", "shasum": "" }, "require": { @@ -2163,7 +2163,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-collection-level-permissions" }, - "time": "2023-04-20T18:37:34+00:00" + "time": "2023-04-21T10:56:21+00:00" }, { "name": "utopia-php/domains", From ff82a24a4b23595c800801aa617e5d1c00cbe8b1 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 24 Apr 2023 13:00:23 +0200 Subject: [PATCH 16/25] feat: migration --- app/http.php | 7 +----- composer.lock | 20 ++++++++--------- src/Appwrite/Migration/Migration.php | 9 ++++++++ src/Appwrite/Migration/Version/V18.php | 31 ++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/app/http.php b/app/http.php index 4a0f1046dd..249e8dc2d9 100644 --- a/app/http.php +++ b/app/http.php @@ -115,12 +115,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { if (!$dbForConsole->getCollection($key)->isEmpty()) { continue; } - /** - * Skip to prevent 0.16 migration issues. - */ - if (in_array($key, ['cache', 'variables']) && $dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'), 'bucket_1')) { - continue; - } Console::success('[Setup] - Creating collection: ' . $collection['$id'] . '...'); @@ -215,6 +209,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } Console::success('[Setup] - Server database init completed...'); + var_dump($dbForConsole->find(Database::METADATA)); }); Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)'); diff --git a/composer.lock b/composer.lock index 254c2a4186..cbe17fdc2e 100644 --- a/composer.lock +++ b/composer.lock @@ -2113,12 +2113,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "6ce621ac9d97e3ff18e1595c328526b3050ab68b" + "reference": "c3dfecc21e3b8ce8f233425150b4a330739806b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/6ce621ac9d97e3ff18e1595c328526b3050ab68b", - "reference": "6ce621ac9d97e3ff18e1595c328526b3050ab68b", + "url": "https://api.github.com/repos/utopia-php/database/zipball/c3dfecc21e3b8ce8f233425150b4a330739806b5", + "reference": "c3dfecc21e3b8ce8f233425150b4a330739806b5", "shasum": "" }, "require": { @@ -2163,7 +2163,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-collection-level-permissions" }, - "time": "2023-04-21T10:56:21+00:00" + "time": "2023-04-24T09:13:37+00:00" }, { "name": "utopia-php/domains", @@ -3784,16 +3784,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.20.0", + "version": "1.20.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "10553ab3f0337ff1a71433c3417d7eb2a3eec1fd" + "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/10553ab3f0337ff1a71433c3417d7eb2a3eec1fd", - "reference": "10553ab3f0337ff1a71433c3417d7eb2a3eec1fd", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/90490bd8fd8530a272043c4950c180b6d0cf5f81", + "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81", "shasum": "" }, "require": { @@ -3823,9 +3823,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.2" }, - "time": "2023-04-20T11:18:07+00:00" + "time": "2023-04-22T12:59:35+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 4a79ffafbf..39740a1f1c 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -37,6 +37,9 @@ abstract class Migration */ protected Database $consoleDB; + /** + * @var \PDO + */ protected \PDO $pdo; /** @@ -102,6 +105,12 @@ abstract class Migration return $this; } + /** + * Set PDO for Migration. + * + * @param \PDO $pdo + * @return \Appwrite\Migration\Migration + */ public function setPDO(\PDO $pdo): self { $this->pdo = $pdo; diff --git a/src/Appwrite/Migration/Version/V18.php b/src/Appwrite/Migration/Version/V18.php index eba19fa861..3e57686e75 100644 --- a/src/Appwrite/Migration/Version/V18.php +++ b/src/Appwrite/Migration/Version/V18.php @@ -25,6 +25,7 @@ class V18 extends Migration Console::log('Migrating Project: ' . $this->project->getAttribute('name') . ' (' . $this->project->getId() . ')'); $this->projectDB->setNamespace("_{$this->project->getInternalId()}"); + $this->addDocumentSecurityToProject(); Console::info('Migrating Databases'); $this->migrateDatabases(); @@ -58,6 +59,15 @@ class V18 extends Migration } $this->changeAttributeInternalType($collectionTable, $attribute['key'], 'DOUBLE'); } + + try { + $documentSecurity = $collection->getAttribute('documentSecurity', false); + $permissions = $collection->getPermissions(); + + $this->projectDB->updateCollection($collectionTable, $permissions, $documentSecurity); + } catch (\Throwable $th) { + Console::warning($th->getMessage()); + } } } } @@ -168,4 +178,25 @@ class V18 extends Migration return $document; } + + protected function addDocumentSecurityToProject(): void + { + try { + /** + * Create 'documentSecurity' column + */ + $this->pdo->prepare("ALTER TABLE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` ADD COLUMN IF NOT EXISTS documentSecurity TINYINT(1);")->execute(); + } catch (\Throwable $th) { + Console::warning($th->getMessage()); + } + + try { + /** + * Set 'documentSecurity' column to 1 if NULL + */ + $this->pdo->prepare("UPDATE `{$this->projectDB->getDefaultDatabase()}`.`_{$this->project->getInternalId()}__metadata` SET documentSecurity = 1 WHERE documentSecurity IS NULL")->execute(); + } catch (\Throwable $th) { + Console::warning($th->getMessage()); + } + } } From 5ee3c592a48ebc5bce254447a0afecb88555b02e Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 24 Apr 2023 13:10:28 +0200 Subject: [PATCH 17/25] chore: release 1.3.2 --- CHANGES.md | 1 + README-CN.md | 6 +++--- README.md | 6 +++--- app/init.php | 2 +- src/Appwrite/Migration/Migration.php | 1 + 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5ab6e586cf..bac697cf71 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## Bugs - Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363) +- Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395) # Version 1.3.1 diff --git a/README-CN.md b/README-CN.md index bfbd98fb74..8233cfe873 100644 --- a/README-CN.md +++ b/README-CN.md @@ -67,7 +67,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` ### Windows @@ -79,7 +79,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` #### PowerShell @@ -89,7 +89,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 diff --git a/README.md b/README.md index 962fab5e01..7b05cac9bc 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` ### Windows @@ -88,7 +88,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` #### PowerShell @@ -98,7 +98,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.3.1 + appwrite/appwrite:1.3.2 ``` Once the Docker installation is complete, go to http://localhost to access the Appwrite console from your browser. Please note that on non-Linux native hosts, the server might take a few minutes to start after completing the installation. diff --git a/app/init.php b/app/init.php index 02fd9246f7..a35da92d0c 100644 --- a/app/init.php +++ b/app/init.php @@ -101,7 +101,7 @@ const APP_LIMIT_LIST_DEFAULT = 25; // Default maximum number of items to return const APP_KEY_ACCCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours const APP_CACHE_BUSTER = 503; -const APP_VERSION_STABLE = '1.3.1'; +const APP_VERSION_STABLE = '1.3.2'; const APP_DATABASE_ATTRIBUTE_EMAIL = 'email'; const APP_DATABASE_ATTRIBUTE_ENUM = 'enum'; const APP_DATABASE_ATTRIBUTE_IP = 'ip'; diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 39740a1f1c..1017728eee 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -57,6 +57,7 @@ abstract class Migration '1.2.1' => 'V17', '1.3.0' => 'V18', '1.3.1' => 'V18', + '1.3.2' => 'V18', ]; /** From 4ebe485f0558084c29c23ee2b77623b48f9b4558 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 24 Apr 2023 13:11:39 +0200 Subject: [PATCH 18/25] remove: leftover from http.php --- app/http.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/http.php b/app/http.php index 249e8dc2d9..7ee38958b9 100644 --- a/app/http.php +++ b/app/http.php @@ -209,7 +209,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { } Console::success('[Setup] - Server database init completed...'); - var_dump($dbForConsole->find(Database::METADATA)); }); Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)'); From 43a6945d3009d487511a6c031e244fb04b9fb891 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 24 Apr 2023 13:21:31 +0200 Subject: [PATCH 19/25] fix: migration --- src/Appwrite/Migration/Version/V18.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Appwrite/Migration/Version/V18.php b/src/Appwrite/Migration/Version/V18.php index 3e57686e75..1cbb337c04 100644 --- a/src/Appwrite/Migration/Version/V18.php +++ b/src/Appwrite/Migration/Version/V18.php @@ -6,6 +6,8 @@ use Appwrite\Migration\Migration; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Helpers\Permission; +use Utopia\Database\Helpers\Role; class V18 extends Migration { @@ -91,6 +93,12 @@ class V18 extends Migration $this->changeAttributeInternalType($id, $attribute['$id'], 'DOUBLE'); } + try { + $this->projectDB->updateCollection($id, [Permission::create(Role::any())], true); + } catch (\Throwable $th) { + Console::warning($th->getMessage()); + } + switch ($id) { case 'users': try { From d45bc5e60fc0403c381681d76d7c761cd59feb36 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 27 Apr 2023 15:54:07 +0200 Subject: [PATCH 20/25] chore: upgrade console --- .gitmodules | 2 +- app/console | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index a4bea14d38..15c60d9713 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "app/console"] path = app/console url = https://github.com/appwrite/console - branch = 2.3.3 + branch = 2.3.4 diff --git a/app/console b/app/console index ac4181aea4..9174d8f8cb 160000 --- a/app/console +++ b/app/console @@ -1 +1 @@ -Subproject commit ac4181aea403d888e63cb527c700e80013c68ea8 +Subproject commit 9174d8f8cb584744dd7a53f69d324f490ee82ee3 From e1cf068652f144824a3617ac410244220f9e1b40 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 27 Apr 2023 17:36:00 +0200 Subject: [PATCH 21/25] fix: platforms query --- app/controllers/api/projects.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 44329724b1..64ce9c8a67 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -1237,7 +1237,7 @@ App::get('/v1/projects/:projectId/platforms') } $platforms = $dbForConsole->find('platforms', [ - Query::equal('projectId', [$project->getId()]), + Query::equal('projectInternalId', [$project->getInternalId()]), Query::limit(5000), ]); From 31e65d954bad7aa191d2b734d171245b09b13f9b Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 27 Apr 2023 17:37:14 +0200 Subject: [PATCH 22/25] fix: deletes worker for projects --- app/workers/deletes.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 42ec0d2565..277e4b92d6 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -9,7 +9,6 @@ use Utopia\Database\Document; use Utopia\Database\Query; use Appwrite\Resque\Worker; use Executor\Executor; -use Utopia\Storage\Device\Local; use Utopia\Abuse\Abuse; use Utopia\Abuse\Adapters\TimeLimit; use Utopia\CLI\Console; @@ -291,12 +290,13 @@ class DeletesV1 extends Worker protected function deleteProject(Document $document): void { $projectId = $document->getId(); + $projectInternalId = $document->getInternalId(); - // Delete project domains and certificates + // Delete project certificates $dbForConsole = $this->getConsoleDB(); $domains = $dbForConsole->find('domains', [ - Query::equal('projectInternalId', [$document->getInternalId()]) + Query::equal('projectInternalId', [$projectInternalId]) ]); foreach ($domains as $domain) { @@ -318,6 +318,21 @@ class DeletesV1 extends Worker } } + // Delete Platforms + $this->deleteByGroup('platforms', [ + Query::equal('projectInternalId', [$projectInternalId]) + ], $dbForConsole); + + // Delete Domains + $this->deleteByGroup('domains', [ + Query::equal('projectInternalId', [$projectInternalId]) + ], $dbForConsole); + + // Delete Keys + $this->deleteByGroup('keys', [ + Query::equal('projectInternalId', [$projectInternalId]) + ], $dbForConsole); + // Delete metadata tables try { $dbForProject->deleteCollection('_metadata'); From 7529f02bd64af8c717af8bc72996d291c85df523 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 27 Apr 2023 17:41:14 +0200 Subject: [PATCH 23/25] fix: also delete webhooks on project deletion --- app/workers/deletes.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/workers/deletes.php b/app/workers/deletes.php index 277e4b92d6..f27bc4feb9 100644 --- a/app/workers/deletes.php +++ b/app/workers/deletes.php @@ -333,6 +333,11 @@ class DeletesV1 extends Worker Query::equal('projectInternalId', [$projectInternalId]) ], $dbForConsole); + // Delete Webhooks + $this->deleteByGroup('webhooks', [ + Query::equal('projectInternalId', [$projectInternalId]) + ], $dbForConsole); + // Delete metadata tables try { $dbForProject->deleteCollection('_metadata'); From e7c311044bdaa13c94d3d4794bf076f00855b68a Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 27 Apr 2023 18:04:00 +0200 Subject: [PATCH 24/25] chore: add changelog --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index bac697cf71..df4bc7105e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,7 @@ ## Bugs - Fixed auto-setting custom ID on nested documents [#5363](https://github.com/appwrite/appwrite/pull/5363) - Fixed listDocuments not returning all the documents [#5395](https://github.com/appwrite/appwrite/pull/5395) +- Fixed deleting keys, webhooks, platforms and domains after deleting project [#5395](https://github.com/appwrite/appwrite/pull/5395) # Version 1.3.1 From 11d523b05010598904dc76bf5f0b0ee21fda65b9 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 27 Apr 2023 10:42:55 -0700 Subject: [PATCH 25/25] Bump utopia abuse, audit, and database --- composer.json | 6 ++--- composer.lock | 71 ++++++++++++++++++++++----------------------------- 2 files changed, 34 insertions(+), 43 deletions(-) diff --git a/composer.json b/composer.json index 112a07e64c..78f960d3d1 100644 --- a/composer.json +++ b/composer.json @@ -43,13 +43,13 @@ "ext-sockets": "*", "appwrite/php-clamav": "1.1.*", "appwrite/php-runtimes": "0.11.*", - "utopia-php/abuse": "0.24.*", + "utopia-php/abuse": "0.25.*", "utopia-php/analytics": "0.2.*", - "utopia-php/audit": "0.25.*", + "utopia-php/audit": "0.26.*", "utopia-php/cache": "0.8.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-collection-level-permissions as 0.35.9", + "utopia-php/database": "0.36.*", "utopia-php/domains": "1.1.*", "utopia-php/framework": "0.28.*", "utopia-php/image": "0.5.*", diff --git a/composer.lock b/composer.lock index cbe17fdc2e..61826fd9b1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4e4bc742147d14591f8e54b63a9dd008", + "content-hash": "169ab6e7dd540e45309d3c5093506fad", "packages": [ { "name": "adhocore/jwt", @@ -1805,26 +1805,26 @@ }, { "name": "utopia-php/abuse", - "version": "0.24.0", + "version": "0.25.0", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "403641f16a53b81ac40b91111a86e5672da49e8c" + "reference": "49a180cab5316cddec9676d900d5112d03e97ffc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/403641f16a53b81ac40b91111a86e5672da49e8c", - "reference": "403641f16a53b81ac40b91111a86e5672da49e8c", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/49a180cab5316cddec9676d900d5112d03e97ffc", + "reference": "49a180cab5316cddec9676d900d5112d03e97ffc", "shasum": "" }, "require": { "ext-curl": "*", "ext-pdo": "*", "php": ">=8.0", - "utopia-php/database": "0.35.*" + "utopia-php/database": "0.36.*" }, "require-dev": { - "laravel/pint": "1.2.*", + "laravel/pint": "1.5.*", "phpstan/phpstan": "^1.9", "phpunit/phpunit": "^9.4" }, @@ -1848,9 +1848,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.24.0" + "source": "https://github.com/utopia-php/abuse/tree/0.25.0" }, - "time": "2023-04-11T05:31:55+00:00" + "time": "2023-04-27T15:43:47+00:00" }, { "name": "utopia-php/analytics", @@ -1909,24 +1909,24 @@ }, { "name": "utopia-php/audit", - "version": "0.25.0", + "version": "0.26.0", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31" + "reference": "e7228080f14df28737fbb050c180c26d86ac0403" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/adc209f2e16878e5468f0b9cfd9f7f7ab497db31", - "reference": "adc209f2e16878e5468f0b9cfd9f7f7ab497db31", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/e7228080f14df28737fbb050c180c26d86ac0403", + "reference": "e7228080f14df28737fbb050c180c26d86ac0403", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "0.35.*" + "utopia-php/database": "0.36.*" }, "require-dev": { - "laravel/pint": "1.2.*", + "laravel/pint": "1.5.*", "phpstan/phpstan": "^1.8", "phpunit/phpunit": "^9.3" }, @@ -1950,9 +1950,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.25.0" + "source": "https://github.com/utopia-php/audit/tree/0.26.0" }, - "time": "2023-04-11T05:31:15+00:00" + "time": "2023-04-27T15:43:50+00:00" }, { "name": "utopia-php/cache", @@ -2109,16 +2109,16 @@ }, { "name": "utopia-php/database", - "version": "dev-feat-collection-level-permissions", + "version": "0.36.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "c3dfecc21e3b8ce8f233425150b4a330739806b5" + "reference": "f6ab65e59a199da5155c114564077b1ab8c4daef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/c3dfecc21e3b8ce8f233425150b4a330739806b5", - "reference": "c3dfecc21e3b8ce8f233425150b4a330739806b5", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f6ab65e59a199da5155c114564077b1ab8c4daef", + "reference": "f6ab65e59a199da5155c114564077b1ab8c4daef", "shasum": "" }, "require": { @@ -2161,9 +2161,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/feat-collection-level-permissions" + "source": "https://github.com/utopia-php/database/tree/0.36.1" }, - "time": "2023-04-24T09:13:37+00:00" + "time": "2023-04-27T08:39:55+00:00" }, { "name": "utopia-php/domains", @@ -3784,16 +3784,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.20.2", + "version": "1.20.3", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81" + "reference": "6c04009f6cae6eda2f040745b6b846080ef069c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/90490bd8fd8530a272043c4950c180b6d0cf5f81", - "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6c04009f6cae6eda2f040745b6b846080ef069c2", + "reference": "6c04009f6cae6eda2f040745b6b846080ef069c2", "shasum": "" }, "require": { @@ -3823,9 +3823,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.2" + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.20.3" }, - "time": "2023-04-22T12:59:35+00:00" + "time": "2023-04-25T09:01:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -5652,18 +5652,9 @@ "time": "2023-02-08T07:49:20+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-feat-collection-level-permissions", - "alias": "0.35.9", - "alias_normalized": "0.35.9.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": {