diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..6f8ea5fa9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: "Release" + +on: + release: + types: [published] + +jobs: + tests: + name: Unit & E2E + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + # Fetch submodules + submodules: recursive + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v4 + with: + images: appwrite/appwrite + tags: | + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}}.{{minor}}.{{patch}} + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + platforms: linux/amd64,linux/arm64 + build-args: | + VERSION=${{ steps.meta.outputs.version }} + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/CHANGES.md b/CHANGES.md index 5ab6e586c..bac697cf7 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/Dockerfile b/Dockerfile index 4ea62fd0d..1a5520920 100755 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN composer install --ignore-platform-reqs --optimize-autoloader \ --no-plugins --no-scripts --prefer-dist \ `if [ "$TESTING" != "true" ]; then echo "--no-dev"; fi` -FROM node:16.14.2-alpine3.15 as node +FROM --platform=$BUILDPLATFORM node:16.14.2-alpine3.15 as node COPY app/console /usr/local/src/console diff --git a/README-CN.md b/README-CN.md index bfbd98fb7..8233cfe87 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 962fab5e0..7b05cac9b 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/config/errors.php b/app/config/errors.php index 0ad10f4f7..87a1ab36b 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -102,7 +102,7 @@ return [ ], Exception::USER_ALREADY_EXISTS => [ 'name' => Exception::USER_ALREADY_EXISTS, - 'description' => 'A user with the same email already exists in your project.', + 'description' => 'A user with the same id, email, or phone already exists in your project.', 'code' => 409, ], Exception::USER_BLOCKED => [ diff --git a/app/config/platforms.php b/app/config/platforms.php index 0bbbf76aa..caff21b28 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -28,7 +28,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-web.git', 'gitRepoName' => 'sdk-for-web', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', 'demos' => [ [ 'icon' => 'react.svg', @@ -76,7 +76,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-flutter.git', 'gitRepoName' => 'sdk-for-flutter', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'apple', @@ -94,7 +94,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-apple.git', 'gitRepoName' => 'sdk-for-apple', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'objective-c', @@ -111,7 +111,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-objective-c.git', 'gitRepoName' => 'sdk-for-objective-c', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'android', @@ -129,7 +129,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-android.git', 'gitRepoName' => 'sdk-for-android', 'gitUserName' => 'appwrite', - 'gitBranch' => 'main', + 'gitBranch' => 'dev', 'docDirectories' => [ 'Kotlin' => 'kotlin', 'Java' => 'java', @@ -196,14 +196,14 @@ return [ 'prism' => 'javascript', 'source' => \realpath(__DIR__ . '/../sdks/console-web'), 'gitUrl' => 'git@github.com:appwrite/sdk-for-console.git', - 'gitBranch' => 'main', + 'gitBranch' => 'dev', 'gitRepoName' => 'sdk-for-console', 'gitUserName' => 'appwrite', ], [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '2.0.0', + 'version' => '2.0.2', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, @@ -216,7 +216,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-cli.git', 'gitRepoName' => 'sdk-for-cli', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], ], ], @@ -244,7 +244,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-node.git', 'gitRepoName' => 'sdk-for-node', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'deno', @@ -262,7 +262,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-deno.git', 'gitRepoName' => 'sdk-for-deno', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'php', @@ -280,7 +280,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-php.git', 'gitRepoName' => 'sdk-for-php', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'python', @@ -298,7 +298,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-python.git', 'gitRepoName' => 'sdk-for-python', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'ruby', @@ -316,7 +316,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-ruby.git', 'gitRepoName' => 'sdk-for-ruby', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'go', @@ -334,7 +334,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-go.git', 'gitRepoName' => 'sdk-for-go', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'java', @@ -352,7 +352,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-java.git', 'gitRepoName' => 'sdk-for-java', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'dotnet', @@ -370,7 +370,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-dotnet.git', 'gitRepoName' => 'sdk-for-dotnet', 'gitUserName' => 'appwrite', - 'gitBranch' => 'main', + 'gitBranch' => 'dev', ], [ 'key' => 'dart', @@ -388,7 +388,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-dart.git', 'gitRepoName' => 'sdk-for-dart', 'gitUserName' => 'appwrite', - 'gitBranch' => 'master', + 'gitBranch' => 'dev', ], [ 'key' => 'kotlin', @@ -406,7 +406,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-kotlin.git', 'gitRepoName' => 'sdk-for-kotlin', 'gitUserName' => 'appwrite', - 'gitBranch' => 'main', + 'gitBranch' => 'dev', 'docDirectories' => [ 'Kotlin' => 'kotlin', 'Java' => 'java', @@ -428,7 +428,7 @@ return [ 'gitUrl' => 'git@github.com:appwrite/sdk-for-swift.git', 'gitRepoName' => 'sdk-for-swift', 'gitUserName' => 'appwrite', - 'gitBranch' => 'main', + 'gitBranch' => 'dev', ], [ 'key' => 'graphql', diff --git a/app/config/variables.php b/app/config/variables.php index 193e167b8..978a853ef 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -764,7 +764,7 @@ return [ ], [ 'name' => '_APP_FUNCTIONS_INACTIVE_THRESHOLD', - 'description' => 'The minimum time a function can be inactive before it\'s container is shutdown and put to sleep. The default value is 60 seconds', + 'description' => 'The minimum time a function must be inactive before it can be shut down and cleaned up. This feature is intended to clean up unused containers. Containers may remain active for longer than the interval before being shut down, as Appwrite only cleans up unused containers every hour. If no value is provided, the default is 60 seconds.', 'introduction' => '0.13.0', 'default' => '60', 'required' => false, diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 5146c945e..8419d0d43 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) { @@ -2759,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(); @@ -2885,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); @@ -2917,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()); @@ -2988,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, @@ -3054,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); @@ -3062,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()); @@ -3306,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 @@ -3354,7 +3326,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 @@ -3396,15 +3368,17 @@ App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:docum $checkPermissions($collection, $newDocument, $document, Database::PERMISSION_UPDATE); + $newDocument = new Document(\array_merge($document->getArrayCopy(), $data)); + 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) { diff --git a/app/http.php b/app/http.php index 4a0f1046d..7ee38958b 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'] . '...'); diff --git a/app/init.php b/app/init.php index 02fd9246f..a35da92d0 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/app/tasks/sdks.php b/app/tasks/sdks.php index 4945fcfe9..dadb08be3 100644 --- a/app/tasks/sdks.php +++ b/app/tasks/sdks.php @@ -239,8 +239,8 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND cd ' . $target . ' && \ git init --initial-branch=' . $gitBranch . ' && \ git remote add origin ' . $gitUrl . ' && \ - git fetch && \ - git pull ' . $gitUrl . ' && \ + git fetch origin ' . $gitBranch . ' && \ + git pull origin ' . $gitBranch . ' && \ rm -rf ' . $target . '/* && \ cp -r ' . $result . '/* ' . $target . '/ && \ git add . && \ diff --git a/app/workers/functions.php b/app/workers/functions.php index d7cb8c7ff..6c33447ea 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -82,18 +82,22 @@ class FunctionsV1 extends Worker Console::success('Iterating function: ' . $function->getAttribute('name')); - $this->execute( - project: $project, - function: $function, - dbForProject: $database, - trigger: 'event', - // Pass first, most verbose event pattern - event: $events[0], - eventData: $payload, - user: $user - ); + try { + $this->execute( + project: $project, + function: $function, + dbForProject: $database, + trigger: 'event', + // Pass first, most verbose event pattern + event: $events[0], + eventData: $payload, + user: $user + ); - Console::success('Triggered function: ' . $events[0]); + Console::success('Triggered function: ' . $events[0]); + } catch (\Throwable $th) { + Console::error("Failed to execute " . $function->getId() . " with error: " . $th->getMessage()); + } } } diff --git a/composer.json b/composer.json index fdd5df453..112a07e64 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 2d402ddb3..cbe17fdc2 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": "c3dfecc21e3b8ce8f233425150b4a330739806b5" }, "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/c3dfecc21e3b8ce8f233425150b4a330739806b5", + "reference": "c3dfecc21e3b8ce8f233425150b4a330739806b5", "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-24T09:13:37+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.20.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f" + "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81" }, "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/90490bd8fd8530a272043c4950c180b6d0cf5f81", + "reference": "90490bd8fd8530a272043c4950c180b6d0cf5f81", "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.20.2" }, - "time": "2023-04-07T11:51:11+00:00" + "time": "2023-04-22T12:59:35+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": { diff --git a/docs/examples/1.3.x/console-cli/examples/console/variables.md b/docs/examples/1.3.x/console-cli/examples/console/variables.md new file mode 100644 index 000000000..1c67cf5ad --- /dev/null +++ b/docs/examples/1.3.x/console-cli/examples/console/variables.md @@ -0,0 +1 @@ +appwrite console variables diff --git a/docs/sdks/apple/GETTING_STARTED.md b/docs/sdks/apple/GETTING_STARTED.md index 1da041112..e62f1ce3f 100644 --- a/docs/sdks/apple/GETTING_STARTED.md +++ b/docs/sdks/apple/GETTING_STARTED.md @@ -33,7 +33,7 @@ Next we need to add a hook to save cookies when our app is opened by its callbac > If you're using UIKit, you can skip this section. -In SwiftUI this is as simple as ensuring `.registerOAuthHanlder()` is called on the `View` you want to invoke an OAuth request from. +In SwiftUI this is as simple as ensuring `.registerOAuthHandler()` is called on the `View` you want to invoke an OAuth request from. ### Updating the SceneDelegate for UIKit diff --git a/src/Appwrite/Migration/Migration.php b/src/Appwrite/Migration/Migration.php index 4a79ffafb..1017728ee 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; /** @@ -54,6 +57,7 @@ abstract class Migration '1.2.1' => 'V17', '1.3.0' => 'V18', '1.3.1' => 'V18', + '1.3.2' => 'V18', ]; /** @@ -102,6 +106,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 eba19fa86..1cbb337c0 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 { @@ -25,6 +27,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 +61,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()); + } } } } @@ -81,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 { @@ -168,4 +186,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()); + } + } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php index 16692d215..4651aebd0 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php @@ -18,10 +18,10 @@ class AttributeDatetime extends Attribute 'example' => 'birthDay', ]) ->addRule('type', [ - 'type' => self::TYPE_DATETIME, + 'type' => self::TYPE_STRING, 'description' => 'Attribute type.', 'default' => '', - 'example' => self::TYPE_DATETIME_EXAMPLE, + 'example' => self::TYPE_DATETIME, ]) ->addRule('format', [ 'type' => self::TYPE_DATETIME, diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index a2cb48cf9..abff3437b 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 1bb42d8cb..dcbf3e4bf 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']); } }