From c4f1a682fd4e1002d117a96517ee9ad86b235f1d Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 15 May 2025 05:58:11 +0000 Subject: [PATCH 01/75] Fix: update messaging library --- composer.json | 2 +- composer.lock | 55 ++++++++++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/composer.json b/composer.json index 8b8bb811af..209c8bbb9e 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ "utopia-php/image": "0.8.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", - "utopia-php/messaging": "0.17.*", + "utopia-php/messaging": "0.18.*", "utopia-php/migration": "0.9.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", diff --git a/composer.lock b/composer.lock index 5e86bfafd2..2882375481 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": "2c14e20244a06f508dd67cda717aefeb", + "content-hash": "e6b10826abe8ee1a98acd0645366d550", "packages": [ { "name": "adhocore/jwt", @@ -709,16 +709,16 @@ }, { "name": "google/protobuf", - "version": "v4.30.2", + "version": "v4.31.0", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced" + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/a4c4d8565b40b9f76debc9dfeb221412eacb8ced", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/d59e31ce4bf0e4b48728e90c4d880839edb5be07", + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07", "shasum": "" }, "require": { @@ -747,9 +747,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.2" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.31.0" }, - "time": "2025-03-26T18:01:50+00:00" + "time": "2025-05-14T16:17:23+00:00" }, { "name": "league/csv", @@ -3499,16 +3499,16 @@ }, { "name": "utopia-php/database", - "version": "0.69.1", + "version": "0.69.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "cc6538e05e25d930244ab938c966d32db0922e83" + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/cc6538e05e25d930244ab938c966d32db0922e83", - "reference": "cc6538e05e25d930244ab938c966d32db0922e83", + "url": "https://api.github.com/repos/utopia-php/database/zipball/60591ab073bb80bb9843338754b679bb8169e4ed", + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed", "shasum": "" }, "require": { @@ -3549,9 +3549,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.69.1" + "source": "https://github.com/utopia-php/database/tree/0.69.2" }, - "time": "2025-05-13T12:00:31+00:00" + "time": "2025-05-14T07:51:44+00:00" }, { "name": "utopia-php/domains", @@ -3902,16 +3902,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.17.0", + "version": "0.18.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85" + "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c51915d0e030db3a3add37f1561751d18b2d9a85", - "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c151aa5d4d475c788ca15c210b5b2017e21c41d6", + "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6", "shasum": "" }, "require": { @@ -3947,9 +3947,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.17.0" + "source": "https://github.com/utopia-php/messaging/tree/0.18.0" }, - "time": "2025-05-12T16:14:08+00:00" + "time": "2025-05-15T05:00:03+00:00" }, { "name": "utopia-php/migration", @@ -4331,16 +4331,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.10", + "version": "0.18.11", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e" + "reference": "43bb91814e0ae9c70d2e4224fe0c9e85aa915c52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/43bb91814e0ae9c70d2e4224fe0c9e85aa915c52", + "reference": "43bb91814e0ae9c70d2e4224fe0c9e85aa915c52", "shasum": "" }, "require": { @@ -4353,9 +4353,10 @@ "ext-xz": "*", "ext-zlib": "*", "ext-zstd": "*", - "php": ">=8.0", + "php": ">=8.1", "utopia-php/framework": "0.*.*", - "utopia-php/system": "0.*.*" + "utopia-php/system": "0.*.*", + "utopia-php/telemetry": "0.1.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -4382,9 +4383,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.10" + "source": "https://github.com/utopia-php/storage/tree/0.18.11" }, - "time": "2025-03-03T10:47:54+00:00" + "time": "2025-05-14T16:00:30+00:00" }, { "name": "utopia-php/swoole", From ba3f907028877c565df05fce6d3b9124f5a17f53 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Wed, 21 May 2025 10:57:58 +0200 Subject: [PATCH 02/75] fix(storage): do not allow full range This prevents requests with `Range: 0-` and limits it to APP_STORAGE_READ_BUFFER --- app/controllers/api/storage.php | 60 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index a96b871bf2..4a158bb68e 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -996,7 +996,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm', Compression::NONE); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { + if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', APP_STORAGE_READ_BUFFER)) { if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; } else { @@ -1162,13 +1162,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } - $response - ->setContentType($file->getAttribute('mimeType')) - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') - ; - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1177,7 +1170,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { $end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1)); } @@ -1192,6 +1185,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($file->getAttribute('mimeType')) + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') + ; + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1321,15 +1321,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $contentType = $file->getAttribute('mimeType'); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ; - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1338,8 +1329,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { - $end = min(($start + 2000000 - 1), ($size - 1)); + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { + $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1353,6 +1344,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ; + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1474,14 +1474,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $contentType = $file->getAttribute('mimeType'); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()); - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1490,8 +1482,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { - $end = min(($start + 2000000 - 1), ($size - 1)); + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { + $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1505,6 +1497,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()); + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); From 241a0c88e1da48032739c89dd718ddac8de753fc Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Wed, 21 May 2025 16:21:11 +0200 Subject: [PATCH 03/75] fix: task coroutine hooks --- app/cli.php | 3 +-- composer.lock | 12 ++++++------ src/Appwrite/Platform/Tasks/ScheduleBase.php | 10 +++++----- src/Appwrite/Platform/Tasks/ScheduleFunctions.php | 2 +- src/Appwrite/Platform/Tasks/ScheduleMessages.php | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/cli.php b/app/cli.php index aaa8468ef3..7b8d6cd52f 100644 --- a/app/cli.php +++ b/app/cli.php @@ -284,6 +284,5 @@ $cli $cli->shutdown()->action(fn () => Timer::clearAll()); -// Enable coroutines, but disable TCP hooks. These don't work until we use `\Utopia\Cache\Adapter\Pool` and `\Utopia\Database\Adapter\Pool`. -Runtime::enableCoroutine(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); +Runtime::enableCoroutine(SWOOLE_HOOK_ALL); run($cli->run(...)); diff --git a/composer.lock b/composer.lock index 557b61f36c..57d627d493 100644 --- a/composer.lock +++ b/composer.lock @@ -4771,16 +4771,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.17", + "version": "0.40.18", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de" + "reference": "38de4b9c58112d7e83eb75955994c8412a401093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de", - "reference": "7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/38de4b9c58112d7e83eb75955994c8412a401093", + "reference": "38de4b9c58112d7e83eb75955994c8412a401093", "shasum": "" }, "require": { @@ -4816,9 +4816,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.40.17" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.18" }, - "time": "2025-05-16T15:10:54+00:00" + "time": "2025-05-21T14:14:47+00:00" }, { "name": "doctrine/annotations", diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 888d291a75..ea0476fc33 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -79,16 +79,16 @@ abstract class ScheduleBase extends Action // start with "0" to load all active documents. $lastSyncUpdate = "0"; - $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); Console::success("Starting timers at " . DateTime::now()); /** * The timer synchronize $schedules copy with database collection. */ - Timer::tick(static::UPDATE_TIMER * 1000, function () use ($pools, $dbForPlatform, $getProjectDB, &$lastSyncUpdate) { + Timer::tick(static::UPDATE_TIMER * 1000, function () use ($dbForPlatform, $getProjectDB, &$lastSyncUpdate) { $time = DateTime::now(); Console::log("Sync tick: Running at $time"); - $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); }); while (true) { @@ -103,7 +103,7 @@ abstract class ScheduleBase extends Action } } - private function collectSchedules(Group $pools, Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void + private function collectSchedules(Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void { // If we haven't synced yet, load all active schedules $initialLoad = $lastSyncUpdate === "0"; @@ -115,7 +115,7 @@ abstract class ScheduleBase extends Action * @throws Exception * @var Document $schedule */ - $getSchedule = function (Document $schedule) use ($pools, $dbForPlatform, $getProjectDB): array { + $getSchedule = function (Document $schedule) use ($dbForPlatform, $getProjectDB): array { $project = $dbForPlatform->getDocument('projects', $schedule->getAttribute('projectId')); $resource = $getProjectDB($project)->getDocument( diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index 19e068107a..7812b27832 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -76,7 +76,7 @@ class ScheduleFunctions extends ScheduleBase } foreach ($delayedExecutions as $delay => $schedules) { - \go(function () use ($delay, $schedules, $pools, $dbForPlatform) { + \go(function () use ($delay, $schedules, $dbForPlatform) { \sleep($delay); // in seconds foreach ($schedules as $delayConfig) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index 5e65f7a8a6..d23e3de575 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -40,7 +40,7 @@ class ScheduleMessages extends ScheduleBase continue; } - \go(function () use ($schedule, $scheduledAt, $pools, $dbForPlatform) { + \go(function () use ($schedule, $scheduledAt, $dbForPlatform) { $queueForMessaging = new Messaging($this->publisher); $this->updateProjectAccess($schedule['project'], $dbForPlatform); From 1a2a725cb0eb7fe7489bb8a10f4577df9cd6e16c Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 23 May 2025 09:03:42 +0000 Subject: [PATCH 04/75] Merge pull request #9868 from ArnabChatterjee20k/dat-532 added encrypt property in the attribute string response model --- app/controllers/api/databases.php | 13 ++++++--- app/init/database/filters.php | 21 ++++++++++----- .../Utopia/Response/Model/AttributeString.php | 7 +++++ .../e2e/Services/Databases/DatabasesBase.php | 2 +- .../Databases/DatabasesCustomServerTest.php | 27 ++++++++++++++++++- 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 68d8891067..9c4b8e7668 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1368,7 +1368,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string 'array' => $array, 'filters' => $filters, ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); - + $attribute->setAttribute('encrypt', $encrypt); $response ->setStatusCode(Response::STATUS_CODE_ACCEPTED) ->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING); @@ -2047,6 +2047,13 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') throw new Exception(Exception::GENERAL_QUERY_INVALID); } + foreach ($attributes as $attribute) { + if ($attribute->getAttribute('type') === Database::VAR_STRING) { + $filters = $attribute->getAttribute('filters', []); + $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); + } + } + $response->dynamic(new Document([ 'attributes' => $attributes, 'total' => $total, @@ -2111,7 +2118,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') $type = $attribute->getAttribute('type'); $format = $attribute->getAttribute('format'); $options = $attribute->getAttribute('options', []); - + $filters = $attribute->getAttribute('filters', []); foreach ($options as $key => $option) { $attribute->setAttribute($key, $option); } @@ -2131,7 +2138,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') }, default => Response::MODEL_ATTRIBUTE, }; - + $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); $response->dynamic($attribute, $model); }); diff --git a/app/init/database/filters.php b/app/init/database/filters.php index 8223b1c677..49d7845699 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -77,12 +77,21 @@ Database::addFilter( ]); foreach ($attributes as $attribute) { - if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { - $options = $attribute->getAttribute('options'); - foreach ($options as $key => $value) { - $attribute->setAttribute($key, $value); - } - $attribute->removeAttribute('options'); + $attributeType = $attribute->getAttribute('type'); + + switch ($attributeType) { + case Database::VAR_RELATIONSHIP: + $options = $attribute->getAttribute('options'); + foreach ($options as $key => $value) { + $attribute->setAttribute($key, $value); + } + $attribute->removeAttribute('options'); + break; + + case Database::VAR_STRING: + $filters = $attribute->getAttribute('filters', []); + $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); + break; } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index 12bb42009d..fded48fddc 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -24,6 +24,13 @@ class AttributeString extends Attribute 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this attribute is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 7c0060ecaa..9aed3684de 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -298,7 +298,7 @@ trait DatabasesBase $this->assertEquals($title['body']['type'], 'string'); $this->assertEquals($title['body']['size'], 256); $this->assertEquals($title['body']['required'], true); - + $this->assertFalse($title['body']['encrypt']); $this->assertEquals(202, $description['headers']['status-code']); $this->assertEquals($description['body']['key'], 'description'); $this->assertEquals($description['body']['type'], 'string'); diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 829960b54f..bae86066ee 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -697,7 +697,14 @@ class DatabasesCustomServerTest extends Scope 'required' => true, 'encrypt' => true, ]); - + $this->assertTrue($lastName['body']['encrypt']); + sleep(1); + $response = $this->client->call(Client::METHOD_GET, $attributesPath . '/lastName', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ])); + $this->assertTrue($response['body']['encrypt']); /** * Check status of every attribute @@ -741,6 +748,24 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(200, $document['headers']['status-code']); $this->assertEquals('Jonah', $document['body']['firstName']); $this->assertEquals('Jameson', $document['body']['lastName']); + + + $actors = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), []); + $attributes = $actors['body']['attributes']; + foreach ($attributes as $attribute) { + $this->assertArrayHasKey('encrypt', $attribute); + if ($attribute['key'] === 'firstName') { + $this->assertFalse($attribute['encrypt']); + } + if ($attribute['key'] === 'lastName') { + $this->assertTrue($attribute['encrypt']); + } + } + } public function testDeleteAttribute(): array From d27dba05d2b3bfe309a1b7e0eeb136d1ffc0e2a0 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 21 May 2025 08:51:31 +0000 Subject: [PATCH 05/75] Merge pull request #9841 from ArnabChatterjee20k/dat-532 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit added checking for encrypt and plan allowing encryption of string att… --- app/controllers/api/databases.php | 6 +++++- tests/e2e/Services/Databases/DatabasesCustomServerTest.php | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 9c4b8e7668..54a4c565f4 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1347,7 +1347,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { + ->inject('plan') + ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, array $plan) { + if ($encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string attributes are not available on your plan. Please upgrade to create encrypted string attributes.'); + } // Ensure attribute default is within required size $validator = new Text($size, 0); if (!is_null($default) && !$validator->isValid($default)) { diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index bae86066ee..c0d8763aa7 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -695,7 +695,7 @@ class DatabasesCustomServerTest extends Scope 'key' => 'lastName', 'size' => 256, 'required' => true, - 'encrypt' => true, + 'encrypt' => true ]); $this->assertTrue($lastName['body']['encrypt']); sleep(1); From 098f891f7cc5206b5fa6d367d21461cb0b090c20 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 23 May 2025 14:25:23 +0100 Subject: [PATCH 06/75] feat: add builds worker group --- src/Appwrite/Platform/Workers/Builds.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index 4057d4b190..59d9abacb8 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -46,6 +46,7 @@ class Builds extends Action { $this ->desc('Builds worker') + ->groups(['builds']) ->inject('message') ->inject('project') ->inject('dbForPlatform') From 70feb72de0332c6e1a5b652116285df0294a5d77 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Sat, 24 May 2025 03:04:46 +1200 Subject: [PATCH 07/75] Revert "Feat sync encrypt updates" --- app/controllers/api/databases.php | 19 +++--------- app/init/database/filters.php | 21 ++++---------- .../Utopia/Response/Model/AttributeString.php | 7 ----- .../e2e/Services/Databases/DatabasesBase.php | 2 +- .../Databases/DatabasesCustomServerTest.php | 29 ++----------------- 5 files changed, 13 insertions(+), 65 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 54a4c565f4..68d8891067 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1347,11 +1347,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('plan') - ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, array $plan) { - if ($encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string attributes are not available on your plan. Please upgrade to create encrypted string attributes.'); - } + ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { // Ensure attribute default is within required size $validator = new Text($size, 0); if (!is_null($default) && !$validator->isValid($default)) { @@ -1372,7 +1368,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string 'array' => $array, 'filters' => $filters, ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); - $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(Response::STATUS_CODE_ACCEPTED) ->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING); @@ -2051,13 +2047,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') throw new Exception(Exception::GENERAL_QUERY_INVALID); } - foreach ($attributes as $attribute) { - if ($attribute->getAttribute('type') === Database::VAR_STRING) { - $filters = $attribute->getAttribute('filters', []); - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); - } - } - $response->dynamic(new Document([ 'attributes' => $attributes, 'total' => $total, @@ -2122,7 +2111,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') $type = $attribute->getAttribute('type'); $format = $attribute->getAttribute('format'); $options = $attribute->getAttribute('options', []); - $filters = $attribute->getAttribute('filters', []); + foreach ($options as $key => $option) { $attribute->setAttribute($key, $option); } @@ -2142,7 +2131,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') }, default => Response::MODEL_ATTRIBUTE, }; - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); + $response->dynamic($attribute, $model); }); diff --git a/app/init/database/filters.php b/app/init/database/filters.php index 49d7845699..8223b1c677 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -77,21 +77,12 @@ Database::addFilter( ]); foreach ($attributes as $attribute) { - $attributeType = $attribute->getAttribute('type'); - - switch ($attributeType) { - case Database::VAR_RELATIONSHIP: - $options = $attribute->getAttribute('options'); - foreach ($options as $key => $value) { - $attribute->setAttribute($key, $value); - } - $attribute->removeAttribute('options'); - break; - - case Database::VAR_STRING: - $filters = $attribute->getAttribute('filters', []); - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); - break; + if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { + $options = $attribute->getAttribute('options'); + foreach ($options as $key => $value) { + $attribute->setAttribute($key, $value); + } + $attribute->removeAttribute('options'); } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index fded48fddc..12bb42009d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -24,13 +24,6 @@ class AttributeString extends Attribute 'required' => false, 'example' => 'default', ]) - ->addRule('encrypt', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Defines whether this attribute is encrypted or not.', - 'default' => false, - 'required' => false, - 'example' => false, - ]) ; } diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 9aed3684de..7c0060ecaa 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -298,7 +298,7 @@ trait DatabasesBase $this->assertEquals($title['body']['type'], 'string'); $this->assertEquals($title['body']['size'], 256); $this->assertEquals($title['body']['required'], true); - $this->assertFalse($title['body']['encrypt']); + $this->assertEquals(202, $description['headers']['status-code']); $this->assertEquals($description['body']['key'], 'description'); $this->assertEquals($description['body']['type'], 'string'); diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index c0d8763aa7..829960b54f 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -695,16 +695,9 @@ class DatabasesCustomServerTest extends Scope 'key' => 'lastName', 'size' => 256, 'required' => true, - 'encrypt' => true + 'encrypt' => true, ]); - $this->assertTrue($lastName['body']['encrypt']); - sleep(1); - $response = $this->client->call(Client::METHOD_GET, $attributesPath . '/lastName', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); - $this->assertTrue($response['body']['encrypt']); + /** * Check status of every attribute @@ -748,24 +741,6 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(200, $document['headers']['status-code']); $this->assertEquals('Jonah', $document['body']['firstName']); $this->assertEquals('Jameson', $document['body']['lastName']); - - - $actors = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), []); - $attributes = $actors['body']['attributes']; - foreach ($attributes as $attribute) { - $this->assertArrayHasKey('encrypt', $attribute); - if ($attribute['key'] === 'firstName') { - $this->assertFalse($attribute['encrypt']); - } - if ($attribute['key'] === 'lastName') { - $this->assertTrue($attribute['encrypt']); - } - } - } public function testDeleteAttribute(): array From 17eab0ecb500c67d99ab0e0df7fff841d7a67566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 24 May 2025 23:42:19 +0200 Subject: [PATCH 08/75] Upgrade to fix createDeployment chunk upload --- composer.json | 2 +- composer.lock | 47 ++++++++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 7e445cd36b..d166384e3a 100644 --- a/composer.json +++ b/composer.json @@ -86,7 +86,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "0.40.*", + "appwrite/sdk-generator": "dev-fix-functions-sites-files as 0.40.99", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index f36b815777..d4241739da 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": "9f5de64d73e2ef73d796fa64f2baf232", + "content-hash": "095386e258e35b6bf54f46c6b384aca7", "packages": [ { "name": "adhocore/jwt", @@ -1238,16 +1238,16 @@ }, { "name": "open-telemetry/exporter-otlp", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/exporter-otlp.git", - "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c" + "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", - "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", + "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/8b3ca1f86d01429c73b407bf1a2075d9c187001e", + "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e", "shasum": "" }, "require": { @@ -1298,7 +1298,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-12T00:36:35+00:00" + "time": "2025-05-21T12:02:20+00:00" }, { "name": "open-telemetry/gen-otlp-protobuf", @@ -1365,16 +1365,16 @@ }, { "name": "open-telemetry/sdk", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/sdk.git", - "reference": "939d3a28395c249a763676458140dad44b3a8011" + "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/939d3a28395c249a763676458140dad44b3a8011", - "reference": "939d3a28395c249a763676458140dad44b3a8011", + "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/cd0d7367599717fc29e04eb8838ec061e6c2c657", + "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657", "shasum": "" }, "require": { @@ -1451,7 +1451,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-07T12:32:21+00:00" + "time": "2025-05-22T02:33:34+00:00" }, { "name": "open-telemetry/sem-conv", @@ -4816,16 +4816,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.17", + "version": "dev-fix-functions-sites-files", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de" + "reference": "d831f172056e412158d4c950128e015daf9c11c6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de", - "reference": "7e333c1003bfd4763e4d6f3a0a799fde5e7bc4de", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/d831f172056e412158d4c950128e015daf9c11c6", + "reference": "d831f172056e412158d4c950128e015daf9c11c6", "shasum": "" }, "require": { @@ -4861,9 +4861,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.40.17" + "source": "https://github.com/appwrite/sdk-generator/tree/fix-functions-sites-files" }, - "time": "2025-05-16T15:10:54+00:00" + "time": "2025-05-24T21:40:27+00:00" }, { "name": "doctrine/annotations", @@ -8240,9 +8240,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "appwrite/sdk-generator", + "version": "dev-fix-functions-sites-files", + "alias": "0.40.99", + "alias_normalized": "0.40.99.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "appwrite/sdk-generator": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From eb8da87eedd66826b5e2c859cf98acd91ad873f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sat, 24 May 2025 23:47:27 +0200 Subject: [PATCH 09/75] Fix bug; trigger sdk generation --- app/config/specs/open-api3-latest-client.json | 25 ++++++++++++++- .../specs/open-api3-latest-console.json | 31 ++++++++++++++++++- app/config/specs/open-api3-latest-server.json | 31 ++++++++++++++++++- app/config/specs/swagger2-latest-client.json | 25 ++++++++++++++- app/config/specs/swagger2-latest-console.json | 31 ++++++++++++++++++- app/config/specs/swagger2-latest-server.json | 31 ++++++++++++++++++- composer.lock | 8 ++--- 7 files changed, 172 insertions(+), 10 deletions(-) diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index abeab8a56f..e87a892063 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -4490,6 +4490,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/components\/schemas\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 19ce78915c..ad500a8811 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8049,6 +8049,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/components\/schemas\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -36564,6 +36587,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index db615d642c..8ac05cb97b 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7530,6 +7530,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/components\/schemas\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -26532,6 +26555,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 5c1b764e1e..972b4a34da 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -4636,6 +4636,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/definitions\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 96705f3e61..a52f09d691 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8178,6 +8178,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/definitions\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -36793,6 +36816,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index c033008417..a37c972aae 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.3", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7649,6 +7649,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/definitions\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -26828,6 +26851,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ diff --git a/composer.lock b/composer.lock index d4241739da..d2c689437c 100644 --- a/composer.lock +++ b/composer.lock @@ -4820,12 +4820,12 @@ "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "d831f172056e412158d4c950128e015daf9c11c6" + "reference": "1579aa907eced019d2d4236e141081a83d3394e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/d831f172056e412158d4c950128e015daf9c11c6", - "reference": "d831f172056e412158d4c950128e015daf9c11c6", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1579aa907eced019d2d4236e141081a83d3394e1", + "reference": "1579aa907eced019d2d4236e141081a83d3394e1", "shasum": "" }, "require": { @@ -4863,7 +4863,7 @@ "issues": "https://github.com/appwrite/sdk-generator/issues", "source": "https://github.com/appwrite/sdk-generator/tree/fix-functions-sites-files" }, - "time": "2025-05-24T21:40:27+00:00" + "time": "2025-05-24T21:46:46+00:00" }, { "name": "doctrine/annotations", From aa9f554853519d99ecc4f1a983265ce3c3c20044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 25 May 2025 00:05:30 +0200 Subject: [PATCH 10/75] Fix chunk uploaded manual deployment --- .../Platform/Modules/Sites/Http/Deployments/Create.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php index 13b1e0c830..d78d43aec7 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Create.php @@ -347,10 +347,16 @@ class Create extends Action 'domain' => $domain, 'type' => 'deployment', 'trigger' => 'deployment', - 'value' => $deployment->getId(), + 'deploymentId' => $deployment->isEmpty() ? '' : $deployment->getId(), + 'deploymentInternalId' => $deployment->isEmpty() ? '' : $deployment->getInternalId(), + 'deploymentResourceType' => 'site', + 'deploymentResourceId' => $site->getId(), + 'deploymentResourceInternalId' => $site->getInternalId(), 'status' => 'verified', 'certificateId' => '', 'search' => implode(' ', [$ruleId, $domain]), + 'owner' => 'Appwrite', + 'region' => $project->getAttribute('region') ])) ); } else { From d3533840c8889561f0cedb301676229110ce580e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 25 May 2025 00:50:51 +0200 Subject: [PATCH 11/75] Chore: Use release, not branch --- composer.json | 2 +- composer.lock | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index d166384e3a..7e445cd36b 100644 --- a/composer.json +++ b/composer.json @@ -86,7 +86,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "dev-fix-functions-sites-files as 0.40.99", + "appwrite/sdk-generator": "0.40.*", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index d2c689437c..ef067116d0 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": "095386e258e35b6bf54f46c6b384aca7", + "content-hash": "9f5de64d73e2ef73d796fa64f2baf232", "packages": [ { "name": "adhocore/jwt", @@ -4816,16 +4816,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "dev-fix-functions-sites-files", + "version": "0.40.19", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1579aa907eced019d2d4236e141081a83d3394e1" + "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1579aa907eced019d2d4236e141081a83d3394e1", - "reference": "1579aa907eced019d2d4236e141081a83d3394e1", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", + "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", "shasum": "" }, "require": { @@ -4861,9 +4861,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/fix-functions-sites-files" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.19" }, - "time": "2025-05-24T21:46:46+00:00" + "time": "2025-05-24T22:49:50+00:00" }, { "name": "doctrine/annotations", @@ -8240,18 +8240,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "appwrite/sdk-generator", - "version": "dev-fix-functions-sites-files", - "alias": "0.40.99", - "alias_normalized": "0.40.99.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "appwrite/sdk-generator": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 24e0b3e8cb5fdf9ee6ea1e258c6431f0adc4c509 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 25 May 2025 12:19:52 +0530 Subject: [PATCH 12/75] fix: missing project check. --- app/controllers/api/teams.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 9c383803f2..cc930eca90 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1314,10 +1314,11 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') )) ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') + ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) { $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1341,6 +1342,27 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::TEAM_MEMBERSHIP_MISMATCH); } + if ($project->getId() === 'console') { + // Quick check: + // fetch up to 2 owners to determine if only one exists + $ownersCount = $dbForProject->count( + collection: 'memberships', + queries: [ + Query::contains('roles', ['owner']), + Query::equal('teamInternalId', [$team->getInternalId()]) + ], + max: 2 + ); + + if ($ownersCount === 1) { + /* Prevent removal if the user is the only owner. */ + throw new Exception( + Exception::GENERAL_ARGUMENT_INVALID, + 'There must be at least one owner in the organization.' + ); + } + } + try { $dbForProject->deleteDocument('memberships', $membership->getId()); } catch (AuthorizationException $exception) { From 3f839e380788e901c20336784e01c3183dc33ea2 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 25 May 2025 12:27:29 +0530 Subject: [PATCH 13/75] update: tests to account for console and custom client projects. --- tests/e2e/Services/Teams/TeamsBaseClient.php | 79 ++++++++++++++++--- .../Services/Teams/TeamsConsoleClientTest.php | 4 +- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 3fcd9c043d..2aacf4abc1 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -10,6 +10,17 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; trait TeamsBaseClient { + /** + * Checks if the current project is the Console project. + * + * This is necessary because the last admin of an org + * cannot be removed, which affects certain test conditions. + */ + private function isConsoleProject(): bool + { + return $this->getProject()['$id'] === 'console'; + } + /** * @depends testCreateTeam */ @@ -60,7 +71,11 @@ trait TeamsBaseClient ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']['memberships']); + if ($this->isConsoleProject()) { + $this->assertCount(1, $response['body']['memberships']); + } else { + $this->assertCount(0, $response['body']['memberships']); + } $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -84,7 +99,11 @@ trait TeamsBaseClient ]); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(0, $response['body']['memberships']); + if ($this->isConsoleProject()) { + $this->assertCount(1, $response['body']['memberships']); + } else { + $this->assertCount(0, $response['body']['memberships']); + } $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -373,7 +392,11 @@ trait TeamsBaseClient $this->assertEquals(200, $memberships['headers']['status-code']); $this->assertIsInt($memberships['body']['total']); $this->assertNotEmpty($memberships['body']['memberships']); - $this->assertCount(3, $memberships['body']['memberships']); + if ($this->isConsoleProject()) { + $this->assertCount(4, $memberships['body']['memberships']); + } else { + $this->assertCount(3, $memberships['body']['memberships']); + } $response = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -387,7 +410,11 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertIsInt($response['body']['total']); $this->assertNotEmpty($response['body']['memberships']); - $this->assertCount(2, $response['body']['memberships']); + if ($this->isConsoleProject()) { + $this->assertCount(3, $response['body']['memberships']); + } else { + $this->assertCount(2, $response['body']['memberships']); + } $this->assertEquals($memberships['body']['memberships'][1]['$id'], $response['body']['memberships'][0]['$id']); } @@ -724,7 +751,11 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(4, $response['body']['total']); + if ($this->isConsoleProject()) { + $this->assertCount(5, $response['body']['memberships']); + } else { + $this->assertCount(4, $response['body']['memberships']); + } $ownerMembershipUid = $response['body']['memberships'][0]['$id']; @@ -754,14 +785,18 @@ trait TeamsBaseClient 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); - $this->assertEquals(401, $response['headers']['status-code']); + if ($this->isConsoleProject()) { + $this->assertEquals(400, $response['headers']['status-code']); + } else { + $this->assertEquals(401, $response['headers']['status-code']); + } /** * Test for SUCCESS */ /** - * Test for when a user other than the owner tries to delete their membership + * Test for when a user other than the owner tries to delete an owner's membership. */ $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'origin' => 'http://localhost', @@ -770,8 +805,13 @@ trait TeamsBaseClient 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); - $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEmpty($response['body']); + if ($this->isConsoleProject()) { + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']); + } else { + $this->assertEquals(204, $response['headers']['status-code']); + $this->assertEmpty($response['body']); + } $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -779,7 +819,11 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(3, $response['body']['total']); + if ($this->isConsoleProject()) { + $this->assertEquals(5, $response['body']['total']); + } else { + $this->assertEquals(3, $response['body']['total']); + } /** * Test for when the owner tries to delete their membership @@ -790,8 +834,13 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEmpty($response['body']); + if ($this->isConsoleProject()) { + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']); + } else { + $this->assertEquals(204, $response['headers']['status-code']); + $this->assertEmpty($response['body']); + } $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', @@ -799,7 +848,11 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(404, $response['headers']['status-code']); + if ($this->isConsoleProject()) { + $this->assertEquals(200, $response['headers']['status-code']); + } else { + $this->assertEquals(404, $response['headers']['status-code']); + } return []; } diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 06358765f6..3798019884 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -73,7 +73,9 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals(204, $response['headers']['status-code']); + + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); return $data; } From ddf5b8e15665d505adbbeed8e4b0ec317b3f63d7 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 25 May 2025 19:39:06 +0200 Subject: [PATCH 14/75] Update console image to version 6.0.13 --- app/views/install/compose.phtml | 2 +- docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index d78bca7a38..7a25898647 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -177,7 +177,7 @@ $image = $this->getParam('image', ''); appwrite-console: <<: *x-logging container_name: appwrite-console - image: /console:6.0.11 + image: /console:6.0.13 restart: unless-stopped networks: - appwrite diff --git a/docker-compose.yml b/docker-compose.yml index 847e2fa72c..18dc0aa7b7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -213,7 +213,7 @@ services: appwrite-console: <<: *x-logging container_name: appwrite-console - image: appwrite/console:6.0.11 + image: appwrite/console:6.0.13 restart: unless-stopped networks: - appwrite From 7531c64b31ce6c5a1a9bed4e2d8fd112b624730f Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Sun, 25 May 2025 19:44:51 +0200 Subject: [PATCH 15/75] Update version from 1.7.3 to 1.7.4 --- README-CN.md | 6 +++--- README.md | 6 +++--- app/init/constants.php | 4 ++-- src/Appwrite/Migration/Migration.php | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/README-CN.md b/README-CN.md index 49a97aab53..a9a6b3c867 100644 --- a/README-CN.md +++ b/README-CN.md @@ -72,7 +72,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.7.3 + appwrite/appwrite:1.7.4 ``` ### Windows @@ -84,7 +84,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.7.3 + appwrite/appwrite:1.7.4 ``` #### PowerShell @@ -94,7 +94,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.7.3 + appwrite/appwrite:1.7.4 ``` 运行后,可以在浏览器上访问 http://localhost 找到 Appwrite 控制台。在非 Linux 的本机主机上完成安装后,服务器可能需要几分钟才能启动。 diff --git a/README.md b/README.md index d19d56fdd0..88d3fe89df 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,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.7.3 + appwrite/appwrite:1.7.4 ``` ### Windows @@ -90,7 +90,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.7.3 + appwrite/appwrite:1.7.4 ``` #### PowerShell @@ -100,7 +100,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.7.3 + appwrite/appwrite:1.7.4 ``` 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/constants.php b/app/init/constants.php index e1b595a10f..ebf79086a7 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -37,8 +37,8 @@ const APP_PROJECT_ACCESS = 24 * 60 * 60; // 24 hours const APP_RESOURCE_TOKEN_ACCESS = 24 * 60 * 60; // 24 hours const APP_FILE_ACCESS = 24 * 60 * 60; // 24 hours const APP_CACHE_UPDATE = 24 * 60 * 60; // 24 hours -const APP_CACHE_BUSTER = 4319; -const APP_VERSION_STABLE = '1.7.3'; +const APP_CACHE_BUSTER = 4320; +const APP_VERSION_STABLE = '1.7.4'; 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 a2b1109eb3..26b0a0301f 100644 --- a/src/Appwrite/Migration/Migration.php +++ b/src/Appwrite/Migration/Migration.php @@ -88,6 +88,7 @@ abstract class Migration '1.7.1' => 'V22', '1.7.2' => 'V22', '1.7.3' => 'V22', + '1.7.4' => 'V22', ]; /** From 856a9a714b4923f79cffe7b235bf842829cb167c Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 26 May 2025 11:29:46 +0530 Subject: [PATCH 16/75] fix: memberships patch and delete logic. --- app/controllers/api/teams.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index cc930eca90..7e0d440bd3 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1096,9 +1096,12 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') max: 2 ); + // Is the role change being requested by the user on their own membership? + $isCurrentUserAnOwner = $user->getInternalId() === $membership->getAttribute('userInternalId'); + // Prevent role change if there's only one owner left, - // the requester is that owner, and the new `$roles` no longer include 'owner'! - if ($ownersCount === 1 && $isOwner && !\in_array('owner', $roles)) { + // the requester is that owner, and the new `$roles` no longer include 'owner' + if ($ownersCount === 1 && $isOwner && $isCurrentUserAnOwner && !\in_array('owner', $roles)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.'); } } @@ -1314,11 +1317,12 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') )) ->param('teamId', '', new UID(), 'Team ID.') ->param('membershipId', '', new UID(), 'Membership ID.') + ->inject('user') ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, Document $user, Document $project, Response $response, Database $dbForProject, Event $queueForEvents) { $membership = $dbForProject->getDocument('memberships', $membershipId); @@ -1326,9 +1330,9 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::TEAM_INVITE_NOT_FOUND); } - $user = $dbForProject->getDocument('users', $membership->getAttribute('userId')); + $profile = $dbForProject->getDocument('users', $membership->getAttribute('userId')); - if ($user->isEmpty()) { + if ($profile->isEmpty()) { throw new Exception(Exception::USER_NOT_FOUND); } @@ -1354,7 +1358,10 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') max: 2 ); - if ($ownersCount === 1) { + // Is the deletion being requested by the user on their own membership? + $isCurrentUserAnOwner = $user->getInternalId() === $membership->getAttribute('userInternalId'); + + if ($ownersCount === 1 && $isCurrentUserAnOwner) { /* Prevent removal if the user is the only owner. */ throw new Exception( Exception::GENERAL_ARGUMENT_INVALID, @@ -1378,8 +1385,8 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') } $queueForEvents - ->setParam('userId', $user->getId()) ->setParam('teamId', $team->getId()) + ->setParam('userId', $profile->getId()) ->setParam('membershipId', $membership->getId()) ->setPayload($response->output($membership, Response::MODEL_MEMBERSHIP)) ; From 96bef81ebc2ac062fbe3bd2bde8be5775fe2cf1e Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 26 May 2025 11:33:58 +0530 Subject: [PATCH 17/75] fix: tests! --- tests/e2e/Services/Teams/TeamsBaseClient.php | 83 +++--------- .../Services/Teams/TeamsConsoleClientTest.php | 125 +++++++++++++++--- 2 files changed, 119 insertions(+), 89 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 2aacf4abc1..9b19572d7b 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -10,17 +10,6 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator; trait TeamsBaseClient { - /** - * Checks if the current project is the Console project. - * - * This is necessary because the last admin of an org - * cannot be removed, which affects certain test conditions. - */ - private function isConsoleProject(): bool - { - return $this->getProject()['$id'] === 'console'; - } - /** * @depends testCreateTeam */ @@ -71,11 +60,7 @@ trait TeamsBaseClient ]); $this->assertEquals(200, $response['headers']['status-code']); - if ($this->isConsoleProject()) { - $this->assertCount(1, $response['body']['memberships']); - } else { - $this->assertCount(0, $response['body']['memberships']); - } + $this->assertCount(0, $response['body']['memberships']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -99,11 +84,7 @@ trait TeamsBaseClient ]); $this->assertEquals(200, $response['headers']['status-code']); - if ($this->isConsoleProject()) { - $this->assertCount(1, $response['body']['memberships']); - } else { - $this->assertCount(0, $response['body']['memberships']); - } + $this->assertCount(0, $response['body']['memberships']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -392,11 +373,7 @@ trait TeamsBaseClient $this->assertEquals(200, $memberships['headers']['status-code']); $this->assertIsInt($memberships['body']['total']); $this->assertNotEmpty($memberships['body']['memberships']); - if ($this->isConsoleProject()) { - $this->assertCount(4, $memberships['body']['memberships']); - } else { - $this->assertCount(3, $memberships['body']['memberships']); - } + $this->assertCount(3, $memberships['body']['memberships']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $data['teamUid'] . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -410,11 +387,7 @@ trait TeamsBaseClient $this->assertEquals(200, $response['headers']['status-code']); $this->assertIsInt($response['body']['total']); $this->assertNotEmpty($response['body']['memberships']); - if ($this->isConsoleProject()) { - $this->assertCount(3, $response['body']['memberships']); - } else { - $this->assertCount(2, $response['body']['memberships']); - } + $this->assertCount(2, $response['body']['memberships']); $this->assertEquals($memberships['body']['memberships'][1]['$id'], $response['body']['memberships'][0]['$id']); } @@ -737,8 +710,8 @@ trait TeamsBaseClient } /** - * @depends testUpdateTeamMembershipRoles - */ + * @depends testUpdateTeamMembershipRoles + */ public function testDeleteTeamMembership($data): array { $teamUid = $data['teamUid'] ?? ''; @@ -751,11 +724,7 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - if ($this->isConsoleProject()) { - $this->assertCount(5, $response['body']['memberships']); - } else { - $this->assertCount(4, $response['body']['memberships']); - } + $this->assertEquals(4, $response['body']['total']); $ownerMembershipUid = $response['body']['memberships'][0]['$id']; @@ -785,18 +754,14 @@ trait TeamsBaseClient 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); - if ($this->isConsoleProject()) { - $this->assertEquals(400, $response['headers']['status-code']); - } else { - $this->assertEquals(401, $response['headers']['status-code']); - } + $this->assertEquals(401, $response['headers']['status-code']); /** * Test for SUCCESS */ /** - * Test for when a user other than the owner tries to delete an owner's membership. + * Test for when a user other than the owner tries to delete their membership */ $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'origin' => 'http://localhost', @@ -805,13 +770,8 @@ trait TeamsBaseClient 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); - if ($this->isConsoleProject()) { - $this->assertEquals(400, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']); - } else { - $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEmpty($response['body']); - } + $this->assertEquals(204, $response['headers']['status-code']); + $this->assertEmpty($response['body']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -819,11 +779,7 @@ trait TeamsBaseClient ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - if ($this->isConsoleProject()) { - $this->assertEquals(5, $response['body']['total']); - } else { - $this->assertEquals(3, $response['body']['total']); - } + $this->assertEquals(3, $response['body']['total']); /** * Test for when the owner tries to delete their membership @@ -834,13 +790,8 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - if ($this->isConsoleProject()) { - $this->assertEquals(400, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']); - } else { - $this->assertEquals(204, $response['headers']['status-code']); - $this->assertEmpty($response['body']); - } + $this->assertEquals(204, $response['headers']['status-code']); + $this->assertEmpty($response['body']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', @@ -848,11 +799,7 @@ trait TeamsBaseClient 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - if ($this->isConsoleProject()) { - $this->assertEquals(200, $response['headers']['status-code']); - } else { - $this->assertEquals(404, $response['headers']['status-code']); - } + $this->assertEquals(404, $response['headers']['status-code']); return []; } diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 3798019884..f414123788 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -41,7 +41,7 @@ class TeamsConsoleClientTest extends Scope /** * Test for SUCCESS */ - $response = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ + $developer = $this->client->call(Client::METHOD_POST, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ @@ -51,7 +51,8 @@ class TeamsConsoleClientTest extends Scope 'url' => 'http://localhost:5000/join-us#title' ]); - $this->assertEquals(201, $response['headers']['status-code']); + $developerUserId = $developer['body']['$id']; + $this->assertEquals(201, $developer['headers']['status-code']); $response = $this->client->call(Client::METHOD_GET, '/users', array_merge([ 'content-type' => 'application/json', @@ -66,7 +67,7 @@ class TeamsConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); - $ownerMembershipUid = $response['body']['memberships'][1]['$id']; + $ownerMembershipUid = $response['body']['memberships'][0]['$id']; $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ 'origin' => 'http://localhost', @@ -77,6 +78,16 @@ class TeamsConsoleClientTest extends Scope $this->assertEquals(400, $response['headers']['status-code']); $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); + // Remove the excess developer member to reduce the membership count in `TeamsBaseClient` tests. + // This is necessary because the only owner cannot be removed in the console project / top level team / organization. + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $developerUserId, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(204, $response['headers']['status-code']); + return $data; } @@ -87,21 +98,6 @@ class TeamsConsoleClientTest extends Scope $membershipUid = $data['membershipUid'] ?? ''; $session = $data['session'] ?? ''; - /** - * Test for FAILURE - */ - $roles = ['developer']; - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ - 'origin' => 'http://localhost', - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'roles' => $roles - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); - /** * Test for unknown team */ @@ -110,7 +106,7 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'roles' => $roles + 'roles' => ['developer'] ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -123,7 +119,7 @@ class TeamsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'roles' => $roles + 'roles' => ['developer'] ]); $this->assertEquals(404, $response['headers']['status-code']); @@ -138,7 +134,7 @@ class TeamsConsoleClientTest extends Scope 'x-appwrite-project' => $this->getProject()['$id'], 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ], [ - 'roles' => $roles + 'roles' => ['developer'] ]); $this->assertEquals(401, $response['headers']['status-code']); @@ -146,4 +142,91 @@ class TeamsConsoleClientTest extends Scope return $data; } + + /** + * @depends testUpdateTeamMembershipRoles + */ + public function testDeleteTeamMembership($data): array + { + $teamUid = $data['teamUid'] ?? ''; + $membershipUid = $data['membershipUid'] ?? ''; + $session = $data['session'] ?? ''; + + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(3, $response['body']['total']); + + $ownerMembershipUid = $response['body']['memberships'][0]['$id']; + + /** + * Test deleting a membership that does not exists + */ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/dne', [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]); + + $this->assertEquals(404, $response['headers']['status-code']); + + /** + * Test deleting another user's membership + */ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]); + + $this->assertEquals(401, $response['headers']['status-code']); + $this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']); + + /** + * Test for when a user other than the owner tries to delete their membership + */ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(3, $response['body']['total']); + + /** + * Test for when the owner tries to delete their membership + */ + $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); + + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + + return []; + } } From 64baf1071d5bd7137c0bd159a64c630c53dd8cff Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 26 May 2025 11:38:22 +0530 Subject: [PATCH 18/75] fix: wrong variable passed to cache purge. --- app/controllers/api/teams.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index 7e0d440bd3..5cac3dc9ea 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1378,7 +1378,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove membership from DB'); } - $dbForProject->purgeCachedDocument('users', $user->getId()); + $dbForProject->purgeCachedDocument('users', $profile->getId()); if ($membership->getAttribute('confirm')) { // Count only confirmed members Authorization::skip(fn () => $dbForProject->decreaseDocumentAttribute('teams', $team->getId(), 'total', 1, 0)); From 3adbe8a8f51030947ed09604ac9be30e4d3ebb67 Mon Sep 17 00:00:00 2001 From: Darshan Date: Mon, 26 May 2025 11:41:58 +0530 Subject: [PATCH 19/75] revert: minor change. --- tests/e2e/Services/Teams/TeamsBaseClient.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index 9b19572d7b..3fcd9c043d 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -710,8 +710,8 @@ trait TeamsBaseClient } /** - * @depends testUpdateTeamMembershipRoles - */ + * @depends testUpdateTeamMembershipRoles + */ public function testDeleteTeamMembership($data): array { $teamUid = $data['teamUid'] ?? ''; From b7d0c127a3bf571d97b2ff68c0abdb289febe18d Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Mon, 26 May 2025 21:37:21 +1200 Subject: [PATCH 20/75] Revert "Merge pull request #9878 from ArnabChatterjee20k/dat-532" This reverts commit a366feba803c7082259b8d72e28a103793194352, reversing changes made to 484988fcd7d730d6ac710b06840a5c5fe357ae3f. --- app/controllers/api/databases.php | 6 ------ app/init/constants.php | 1 - .../Services/Databases/DatabasesCustomServerTest.php | 12 ------------ 3 files changed, 19 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 4860f7a967..18b0d87053 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1352,12 +1352,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string if ($encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string attributes are not available on your plan. Please upgrade to create encrypted string attributes.'); } - if ($encrypt && $size < APP_DATABASE_ENCRYPT_SIZE_MIN) { - throw new Exception( - Exception::GENERAL_BAD_REQUEST, - "Size too small. Encrypted strings require a minimum size of " . APP_DATABASE_ENCRYPT_SIZE_MIN . " characters." - ); - } // Ensure attribute default is within required size $validator = new Text($size, 0); if (!is_null($default) && !$validator->isValid($default)) { diff --git a/app/init/constants.php b/app/init/constants.php index ebf79086a7..99881a4381 100644 --- a/app/init/constants.php +++ b/app/init/constants.php @@ -51,7 +51,6 @@ const APP_DATABASE_TIMEOUT_MILLISECONDS_API = 15 * 1000; // 15 seconds const APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER = 300 * 1000; // 5 minutes const APP_DATABASE_TIMEOUT_MILLISECONDS_TASK = 300 * 1000; // 5 minutes const APP_DATABASE_QUERY_MAX_VALUES = 500; -const APP_DATABASE_ENCRYPT_SIZE_MIN = 150; const APP_STORAGE_UPLOADS = '/storage/uploads'; const APP_STORAGE_SITES = '/storage/sites'; const APP_STORAGE_FUNCTIONS = '/storage/functions'; diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index e66207b215..c0d8763aa7 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -686,18 +686,6 @@ class DatabasesCustomServerTest extends Scope 'size' => 256, 'required' => true, ]); - // checking size test - $lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'lastName', - 'size' => 149, - 'required' => true, - 'encrypt' => true - ]); - $this->assertEquals("Size too small. Encrypted strings require a minimum size of " . APP_DATABASE_ENCRYPT_SIZE_MIN . " characters.", $lastName['body']['message']); $lastName = $this->client->call(Client::METHOD_POST, $attributesPath . '/string', array_merge([ 'content-type' => 'application/json', From ab97b7cc54becbcc48b1d1fdccef57a26ee484c8 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 23 May 2025 15:07:17 +0000 Subject: [PATCH 21/75] Merge pull request #9877 from appwrite/revert-9871-feat-sync Revert "Feat sync encrypt updates" --- app/controllers/api/databases.php | 19 +++--------- app/init/database/filters.php | 21 ++++---------- .../Utopia/Response/Model/AttributeString.php | 7 ----- .../e2e/Services/Databases/DatabasesBase.php | 2 +- .../Databases/DatabasesCustomServerTest.php | 29 ++----------------- 5 files changed, 13 insertions(+), 65 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 18b0d87053..277bfae16a 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -1347,11 +1347,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->inject('plan') - ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, array $plan) { - if ($encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string attributes are not available on your plan. Please upgrade to create encrypted string attributes.'); - } + ->action(function (string $databaseId, string $collectionId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { // Ensure attribute default is within required size $validator = new Text($size, 0); if (!is_null($default) && !$validator->isValid($default)) { @@ -1372,7 +1368,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/string 'array' => $array, 'filters' => $filters, ]), $response, $dbForProject, $queueForDatabase, $queueForEvents); - $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(Response::STATUS_CODE_ACCEPTED) ->dynamic($attribute, Response::MODEL_ATTRIBUTE_STRING); @@ -2051,13 +2047,6 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes') throw new Exception(Exception::GENERAL_QUERY_INVALID); } - foreach ($attributes as $attribute) { - if ($attribute->getAttribute('type') === Database::VAR_STRING) { - $filters = $attribute->getAttribute('filters', []); - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); - } - } - $response->dynamic(new Document([ 'attributes' => $attributes, 'total' => $total, @@ -2122,7 +2111,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') $type = $attribute->getAttribute('type'); $format = $attribute->getAttribute('format'); $options = $attribute->getAttribute('options', []); - $filters = $attribute->getAttribute('filters', []); + foreach ($options as $key => $option) { $attribute->setAttribute($key, $option); } @@ -2142,7 +2131,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/attributes/:key') }, default => Response::MODEL_ATTRIBUTE, }; - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); + $response->dynamic($attribute, $model); }); diff --git a/app/init/database/filters.php b/app/init/database/filters.php index c470329706..f110fe1554 100644 --- a/app/init/database/filters.php +++ b/app/init/database/filters.php @@ -77,21 +77,12 @@ Database::addFilter( ]); foreach ($attributes as $attribute) { - $attributeType = $attribute->getAttribute('type'); - - switch ($attributeType) { - case Database::VAR_RELATIONSHIP: - $options = $attribute->getAttribute('options'); - foreach ($options as $key => $value) { - $attribute->setAttribute($key, $value); - } - $attribute->removeAttribute('options'); - break; - - case Database::VAR_STRING: - $filters = $attribute->getAttribute('filters', []); - $attribute->setAttribute('encrypt', in_array('encrypt', $filters)); - break; + if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) { + $options = $attribute->getAttribute('options'); + foreach ($options as $key => $value) { + $attribute->setAttribute($key, $value); + } + $attribute->removeAttribute('options'); } } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php index fded48fddc..12bb42009d 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeString.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -24,13 +24,6 @@ class AttributeString extends Attribute 'required' => false, 'example' => 'default', ]) - ->addRule('encrypt', [ - 'type' => self::TYPE_BOOLEAN, - 'description' => 'Defines whether this attribute is encrypted or not.', - 'default' => false, - 'required' => false, - 'example' => false, - ]) ; } diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 9aed3684de..7c0060ecaa 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -298,7 +298,7 @@ trait DatabasesBase $this->assertEquals($title['body']['type'], 'string'); $this->assertEquals($title['body']['size'], 256); $this->assertEquals($title['body']['required'], true); - $this->assertFalse($title['body']['encrypt']); + $this->assertEquals(202, $description['headers']['status-code']); $this->assertEquals($description['body']['key'], 'description'); $this->assertEquals($description['body']['type'], 'string'); diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index c0d8763aa7..829960b54f 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -695,16 +695,9 @@ class DatabasesCustomServerTest extends Scope 'key' => 'lastName', 'size' => 256, 'required' => true, - 'encrypt' => true + 'encrypt' => true, ]); - $this->assertTrue($lastName['body']['encrypt']); - sleep(1); - $response = $this->client->call(Client::METHOD_GET, $attributesPath . '/lastName', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'], - ])); - $this->assertTrue($response['body']['encrypt']); + /** * Check status of every attribute @@ -748,24 +741,6 @@ class DatabasesCustomServerTest extends Scope $this->assertEquals(200, $document['headers']['status-code']); $this->assertEquals('Jonah', $document['body']['firstName']); $this->assertEquals('Jameson', $document['body']['lastName']); - - - $actors = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $actors['body']['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), []); - $attributes = $actors['body']['attributes']; - foreach ($attributes as $attribute) { - $this->assertArrayHasKey('encrypt', $attribute); - if ($attribute['key'] === 'firstName') { - $this->assertFalse($attribute['encrypt']); - } - if ($attribute['key'] === 'lastName') { - $this->assertTrue($attribute['encrypt']); - } - } - } public function testDeleteAttribute(): array From c7c9e057ab18480cec777b8100651217574675b1 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Mon, 26 May 2025 22:00:39 +1200 Subject: [PATCH 22/75] Update generator --- composer.json | 2 +- composer.lock | 60 +++++++++++++++++++++++++-------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/composer.json b/composer.json index 7e445cd36b..328791c56f 100644 --- a/composer.json +++ b/composer.json @@ -86,7 +86,7 @@ }, "require-dev": { "ext-fileinfo": "*", - "appwrite/sdk-generator": "0.40.*", + "appwrite/sdk-generator": "0.41.*", "phpunit/phpunit": "9.*", "swoole/ide-helper": "5.1.2", "phpstan/phpstan": "1.8.*", diff --git a/composer.lock b/composer.lock index ef067116d0..f5b3f796c8 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": "9f5de64d73e2ef73d796fa64f2baf232", + "content-hash": "a4b3f30b815230a17c33310f62ffb18d", "packages": [ { "name": "adhocore/jwt", @@ -2486,16 +2486,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -2508,7 +2508,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2533,7 +2533,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -2549,7 +2549,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/http-client", @@ -2648,16 +2648,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v3.5.2", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { @@ -2670,7 +2670,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2706,7 +2706,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { @@ -2722,7 +2722,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:49:48+00:00" + "time": "2025-04-29T11:18:49+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2883,16 +2883,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -2910,7 +2910,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2946,7 +2946,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -2962,7 +2962,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "tbachert/spi", @@ -4816,16 +4816,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.19", + "version": "0.41.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf" + "reference": "96316272a3cee1a3abf5b9f05ae49ebbff03725e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", - "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/96316272a3cee1a3abf5b9f05ae49ebbff03725e", + "reference": "96316272a3cee1a3abf5b9f05ae49ebbff03725e", "shasum": "" }, "require": { @@ -4861,9 +4861,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.40.19" + "source": "https://github.com/appwrite/sdk-generator/tree/0.41.0" }, - "time": "2025-05-24T22:49:50+00:00" + "time": "2025-05-26T09:47:45+00:00" }, { "name": "doctrine/annotations", @@ -8242,7 +8242,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8266,5 +8266,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 2a5ecb2547c8adce3e3d421c6b20271117df10a8 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Mon, 26 May 2025 22:25:12 +1200 Subject: [PATCH 23/75] Release cli --- app/config/platforms.php | 2 +- app/config/specs/open-api3-1.7.x-client.json | 2 +- app/config/specs/open-api3-1.7.x-console.json | 30 +++++++++++++++-- app/config/specs/open-api3-1.7.x-server.json | 30 +++++++++++++++-- app/config/specs/open-api3-latest-client.json | 25 +-------------- .../specs/open-api3-latest-console.json | 13 +++----- app/config/specs/open-api3-latest-server.json | 13 +++----- app/config/specs/swagger2-1.7.x-client.json | 2 +- app/config/specs/swagger2-1.7.x-console.json | 32 +++++++++++++++++-- app/config/specs/swagger2-1.7.x-server.json | 32 +++++++++++++++++-- app/config/specs/swagger2-latest-client.json | 25 +-------------- app/config/specs/swagger2-latest-console.json | 15 ++++----- app/config/specs/swagger2-latest-server.json | 15 ++++----- app/controllers/api/databases.php | 2 +- .../examples/databases/upsert-document.md | 6 ++++ .../examples/databases/upsert-documents.md | 2 +- 16 files changed, 149 insertions(+), 97 deletions(-) create mode 100644 docs/examples/1.7.x/console-cli/examples/databases/upsert-document.md diff --git a/app/config/platforms.php b/app/config/platforms.php index 358edd0cf8..7d481d508e 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -217,7 +217,7 @@ return [ [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '6.2.3', + 'version' => '7.0.0', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, diff --git a/app/config/specs/open-api3-1.7.x-client.json b/app/config/specs/open-api3-1.7.x-client.json index abeab8a56f..bbb78c6c66 100644 --- a/app/config/specs/open-api3-1.7.x-client.json +++ b/app/config/specs/open-api3-1.7.x-client.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", diff --git a/app/config/specs/open-api3-1.7.x-console.json b/app/config/specs/open-api3-1.7.x-console.json index 19ce78915c..90ef137fc2 100644 --- a/app/config/specs/open-api3-1.7.x-console.json +++ b/app/config/specs/open-api3-1.7.x-console.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8049,6 +8049,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/components\/schemas\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -8204,7 +8227,10 @@ "type": "object" } } - } + }, + "required": [ + "documents" + ] } } } diff --git a/app/config/specs/open-api3-1.7.x-server.json b/app/config/specs/open-api3-1.7.x-server.json index db615d642c..1ae9328864 100644 --- a/app/config/specs/open-api3-1.7.x-server.json +++ b/app/config/specs/open-api3-1.7.x-server.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7530,6 +7530,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/components\/schemas\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -7688,7 +7711,10 @@ "type": "object" } } - } + }, + "required": [ + "documents" + ] } } } diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index e87a892063..bbb78c6c66 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -4490,29 +4490,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "auth": { - "Key": [] - }, - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index ad500a8811..90ef137fc2 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8227,7 +8227,10 @@ "type": "object" } } - } + }, + "required": [ + "documents" + ] } } } @@ -36587,12 +36590,6 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true - }, - "encrypt": { - "type": "boolean", - "description": "Defines whether this attribute is encrypted or not.", - "x-example": false, - "nullable": true } }, "required": [ diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 8ac05cb97b..1ae9328864 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -1,7 +1,7 @@ { "openapi": "3.0.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7711,7 +7711,10 @@ "type": "object" } } - } + }, + "required": [ + "documents" + ] } } } @@ -26555,12 +26558,6 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true - }, - "encrypt": { - "type": "boolean", - "description": "Defines whether this attribute is encrypted or not.", - "x-example": false, - "nullable": true } }, "required": [ diff --git a/app/config/specs/swagger2-1.7.x-client.json b/app/config/specs/swagger2-1.7.x-client.json index 5c1b764e1e..92132151b4 100644 --- a/app/config/specs/swagger2-1.7.x-client.json +++ b/app/config/specs/swagger2-1.7.x-client.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", diff --git a/app/config/specs/swagger2-1.7.x-console.json b/app/config/specs/swagger2-1.7.x-console.json index 96705f3e61..e53a0dfb0b 100644 --- a/app/config/specs/swagger2-1.7.x-console.json +++ b/app/config/specs/swagger2-1.7.x-console.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8178,6 +8178,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/definitions\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -8323,13 +8346,16 @@ "documents": { "type": "array", "description": "Array of document data as JSON objects. May contain partial documents.", - "default": [], + "default": null, "x-example": null, "items": { "type": "object" } } - } + }, + "required": [ + "documents" + ] } } ] diff --git a/app/config/specs/swagger2-1.7.x-server.json b/app/config/specs/swagger2-1.7.x-server.json index c033008417..083290bcc0 100644 --- a/app/config/specs/swagger2-1.7.x-server.json +++ b/app/config/specs/swagger2-1.7.x-server.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.0", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7649,6 +7649,29 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." + }, + { + "name": "createDocuments", + "auth": { + "Key": [] + }, + "parameters": [ + "databaseId", + "collectionId", + "documents" + ], + "required": [ + "databaseId", + "collectionId", + "documents" + ], + "responses": [ + { + "code": 201, + "model": "#\/definitions\/documentList" + } + ], + "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -7797,13 +7820,16 @@ "documents": { "type": "array", "description": "Array of document data as JSON objects. May contain partial documents.", - "default": [], + "default": null, "x-example": null, "items": { "type": "object" } } - } + }, + "required": [ + "documents" + ] } } ] diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 972b4a34da..92132151b4 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -4636,29 +4636,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "auth": { - "Key": [] - }, - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index a52f09d691..e53a0dfb0b 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -8346,13 +8346,16 @@ "documents": { "type": "array", "description": "Array of document data as JSON objects. May contain partial documents.", - "default": [], + "default": null, "x-example": null, "items": { "type": "object" } } - } + }, + "required": [ + "documents" + ] } } ] @@ -36816,12 +36819,6 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true - }, - "encrypt": { - "type": "boolean", - "description": "Defines whether this attribute is encrypted or not.", - "x-example": false, - "x-nullable": true } }, "required": [ diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index a37c972aae..083290bcc0 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "version": "1.7.3", + "version": "1.7.4", "title": "Appwrite", "description": "Appwrite backend as a service cuts up to 70% of the time and costs required for building a modern application. We abstract and simplify common development tasks behind a REST APIs, to help you develop your app in a fast and secure way. For full API documentation and tutorials go to [https:\/\/appwrite.io\/docs](https:\/\/appwrite.io\/docs)", "termsOfService": "https:\/\/appwrite.io\/policy\/terms", @@ -7820,13 +7820,16 @@ "documents": { "type": "array", "description": "Array of document data as JSON objects. May contain partial documents.", - "default": [], + "default": null, "x-example": null, "items": { "type": "object" } } - } + }, + "required": [ + "documents" + ] } } ] @@ -26851,12 +26854,6 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true - }, - "encrypt": { - "type": "boolean", - "description": "Defines whether this attribute is encrypted or not.", - "x-example": false, - "x-nullable": true } }, "required": [ diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 277bfae16a..dcf547b688 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -4581,7 +4581,7 @@ App::put('/v1/databases/:databaseId/collections/:collectionId/documents') )) ->param('databaseId', '', new UID(), 'Database ID.') ->param('collectionId', '', new UID(), 'Collection ID.') - ->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of document data as JSON objects. May contain partial documents.', true, ['plan']) + ->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of document data as JSON objects. May contain partial documents.', false, ['plan']) ->inject('response') ->inject('dbForProject') ->inject('queueForStatsUsage') diff --git a/docs/examples/1.7.x/console-cli/examples/databases/upsert-document.md b/docs/examples/1.7.x/console-cli/examples/databases/upsert-document.md new file mode 100644 index 0000000000..40932014ba --- /dev/null +++ b/docs/examples/1.7.x/console-cli/examples/databases/upsert-document.md @@ -0,0 +1,6 @@ +appwrite databases upsertDocument \ + --databaseId \ + --collectionId \ + --documentId \ + --data '{ "key": "value" }' \ + diff --git a/docs/examples/1.7.x/console-cli/examples/databases/upsert-documents.md b/docs/examples/1.7.x/console-cli/examples/databases/upsert-documents.md index 3d0bd165d5..cb1677b14c 100644 --- a/docs/examples/1.7.x/console-cli/examples/databases/upsert-documents.md +++ b/docs/examples/1.7.x/console-cli/examples/databases/upsert-documents.md @@ -1,4 +1,4 @@ appwrite databases upsertDocuments \ --databaseId \ --collectionId \ - + --documents one two three From 44e16ce98dc1193ef2677802420f3575b6f1284e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 26 May 2025 12:56:23 +0200 Subject: [PATCH 24/75] Fix commit URLs max length --- app/controllers/api/vcs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 571c7ddca7..a986d1004b 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -324,7 +324,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId // VCS commit preview if (!empty($providerCommitHash)) { - $domain = "commit-{$providerCommitHash}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}"; + $domain = "commit-{$providerCommitHash}.{$sitesDomain}"; $ruleId = md5($domain); try { Authorization::skip( From f6dd9b0d33b0628ff76f679a5b9717e131c57d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 26 May 2025 16:24:27 +0200 Subject: [PATCH 25/75] Fix how we update rules on active deployment --- .../Http/Functions/Deployment/Update.php | 9 +-------- .../Modules/Functions/Workers/Builds.php | 20 +++---------------- .../Sites/Http/Sites/Deployment/Update.php | 9 +-------- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index 6de71cfae6..e63d3d3cd6 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -89,8 +89,6 @@ class Update extends Base throw new Exception(Exception::BUILD_NOT_READY); } - $oldDeploymentInternalId = $function->getAttribute('deploymentInternalId', ''); - $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ 'deploymentInternalId' => $deployment->getInternalId(), 'deploymentId' => $deployment->getId(), @@ -110,14 +108,9 @@ class Update extends Base Query::equal("type", ["deployment"]), Query::equal("deploymentResourceType", ["function"]), Query::equal("deploymentResourceInternalId", [$function->getInternalId()]), + Query::equal("deploymentVcsProviderBranch", [""]), ]; - if (empty($oldDeploymentInternalId)) { - $queries[] = Query::equal("deploymentInternalId", [""]); - } else { - $queries[] = Query::equal("deploymentInternalId", [$oldDeploymentInternalId]); - } - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 0ecf1d3f73..fd366841e3 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1075,8 +1075,6 @@ class Builds extends Action $resource->setAttribute('live', true); switch ($resource->getCollection()) { case 'functions': - $oldDeploymentInternalId = $resource->getAttribute('deploymentInternalId', ''); - $resource->setAttribute('deploymentId', $deployment->getId()); $resource->setAttribute('deploymentInternalId', $deployment->getInternalId()); $resource->setAttribute('deploymentCreatedAt', $deployment->getCreatedAt()); @@ -1088,14 +1086,9 @@ class Builds extends Action Query::equal("deploymentResourceInternalId", [$resource->getInternalId()]), Query::equal('deploymentResourceType', ['function']), Query::equal('trigger', ['manual']), + Query::equal('deploymentVcsProviderBranch', ['']), ]; - if (empty($oldDeploymentInternalId)) { - $queries[] = Query::equal("deploymentInternalId", [""]); - } else { - $queries[] = Query::equal("deploymentInternalId", [$oldDeploymentInternalId]); - } - $rulesUpdated = false; $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment, &$rulesUpdated) { $rulesUpdated = true; @@ -1106,8 +1099,6 @@ class Builds extends Action }); break; case 'sites': - $oldDeploymentInternalId = $resource->getAttribute('deploymentInternalId', ''); - $resource->setAttribute('deploymentId', $deployment->getId()); $resource->setAttribute('deploymentInternalId', $deployment->getInternalId()); $resource->setAttribute('deploymentScreenshotDark', $deployment->getAttribute('screenshotDark', '')); @@ -1120,14 +1111,9 @@ class Builds extends Action Query::equal("deploymentResourceInternalId", [$resource->getInternalId()]), Query::equal('deploymentResourceType', ['site']), Query::equal('trigger', ['manual']), + Query::equal('deploymentVcsProviderBranch', ['']), ]; - if (empty($oldDeploymentInternalId)) { - $queries[] = Query::equal("deploymentInternalId", [""]); - } else { - $queries[] = Query::equal("deploymentInternalId", [$oldDeploymentInternalId]); - } - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) @@ -1144,7 +1130,7 @@ class Builds extends Action $branchName = $deployment->getAttribute('providerBranch'); if (!empty($branchName)) { $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); - $domain = "branch-{$branchName}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}"; + $domain = "branch-{$branchName}.{$sitesDomain}"; $ruleId = md5($domain); try { diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index 7f1681c0f1..7a8fb68499 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -86,8 +86,6 @@ class Update extends Base throw new Exception(Exception::BUILD_NOT_READY); } - $oldDeploymentInternalId = $site->getAttribute('deploymentInternalId', ''); - $site = $dbForProject->updateDocument('sites', $site->getId(), new Document(array_merge($site->getArrayCopy(), [ 'deploymentInternalId' => $deployment->getInternalId(), 'deploymentId' => $deployment->getId(), @@ -101,14 +99,9 @@ class Update extends Base Query::equal("type", ["deployment"]), Query::equal("deploymentResourceType", ["site"]), Query::equal("deploymentResourceInternalId", [$site->getInternalId()]), + Query::equal("deploymentVcsProviderBranch", [""]), ]; - if (empty($oldDeploymentInternalId)) { - $queries[] = Query::equal("deploymentInternalId", [""]); - } else { - $queries[] = Query::equal("deploymentInternalId", [$oldDeploymentInternalId]); - } - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) From 51f6751b9441b5b781baf8f15329a553294d9fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 26 May 2025 16:39:23 +0200 Subject: [PATCH 26/75] Revert --- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index fd366841e3..b5bd2ee8e6 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1130,7 +1130,7 @@ class Builds extends Action $branchName = $deployment->getAttribute('providerBranch'); if (!empty($branchName)) { $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); - $domain = "branch-{$branchName}.{$sitesDomain}"; + $domain = "branch-{$branchName}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}"; $ruleId = md5($domain); try { From deffe25c305cf35dcd97e306aeac6129a6e55819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 26 May 2025 17:54:06 +0200 Subject: [PATCH 27/75] Fix queries not updating well --- .../Modules/Functions/Http/Functions/Deployment/Update.php | 2 +- .../Platform/Modules/Sites/Http/Sites/Deployment/Update.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index e63d3d3cd6..d97bb92b73 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -104,7 +104,7 @@ class Update extends Base Authorization::skip(fn () => $dbForPlatform->updateDocument('schedules', $schedule->getId(), $schedule)); $queries = [ - Query::equal('trigger', 'manual'), + Query::equal('trigger', ['manual']), Query::equal("type", ["deployment"]), Query::equal("deploymentResourceType", ["function"]), Query::equal("deploymentResourceInternalId", [$function->getInternalId()]), diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index 7a8fb68499..aa36b52c5a 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -95,7 +95,7 @@ class Update extends Base ]))); $queries = [ - Query::equal('trigger', 'manual'), + Query::equal('trigger', ['manual']), Query::equal("type", ["deployment"]), Query::equal("deploymentResourceType", ["site"]), Query::equal("deploymentResourceInternalId", [$site->getInternalId()]), From 968b6302d0c54b50a7d143eccf8d0f8b1e19f1dc Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 27 May 2025 07:36:28 +0000 Subject: [PATCH 28/75] Feat: add flutter 3.32 and dart 3.8 --- .env | 2 +- app/config/template-runtimes.php | 4 ++-- app/views/install/compose.phtml | 2 +- docker-compose.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index d7aa8b8d9e..b7dd9e24f3 100644 --- a/.env +++ b/.env @@ -85,7 +85,7 @@ _APP_COMPUTE_RUNTIMES_NETWORK=runtimes _APP_EXECUTOR_SECRET=your-secret-key _APP_EXECUTOR_HOST=http://exc1/v1 _APP_FUNCTIONS_RUNTIMES=php-8.0,node-18.0,python-3.9,ruby-3.1 -_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.29 +_APP_SITES_RUNTIMES=static-1,node-22,flutter-3.32 _APP_MAINTENANCE_INTERVAL=86400 _APP_MAINTENANCE_START_TIME=12:00 _APP_MAINTENANCE_RETENTION_CACHE=2592000 diff --git a/app/config/template-runtimes.php b/app/config/template-runtimes.php index 8f1c0198c2..d1bb1a5b6a 100644 --- a/app/config/template-runtimes.php +++ b/app/config/template-runtimes.php @@ -14,7 +14,7 @@ return [ ], 'DART' => [ 'name' => 'dart', - 'versions' => ['3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16'] + 'versions' => ['3.8', '3.5', '3.3', '3.1', '3.0', '2.19', '2.18', '2.17', '2.16'] ], 'GO' => [ 'name' => 'go', @@ -38,6 +38,6 @@ return [ ], 'FLUTTER' => [ 'name' => 'flutter', - 'versions' => ['3.24'] + 'versions' => ['3.32', '3.24'] ], ]; diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 7a25898647..2d8f2b35ab 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -864,7 +864,7 @@ $image = $this->getParam('image', ''); <<: *x-logging restart: unless-stopped stop_signal: SIGINT - image: openruntimes/executor:0.7.14 + image: openruntimes/executor:0.7.20 networks: - appwrite - runtimes diff --git a/docker-compose.yml b/docker-compose.yml index 18dc0aa7b7..cefd082c2f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -951,7 +951,7 @@ services: hostname: exc1 <<: *x-logging stop_signal: SIGINT - image: openruntimes/executor:0.7.16 + image: openruntimes/executor:0.7.20 restart: unless-stopped networks: - appwrite From 8a09a4b4153547cd74a42f30e118d8202c7c7b95 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 27 May 2025 08:21:31 +0000 Subject: [PATCH 29/75] fix linter --- composer.json | 8 +-- composer.lock | 172 ++++++++++++++++++++++++++------------------------ 2 files changed, 93 insertions(+), 87 deletions(-) diff --git a/composer.json b/composer.json index a5feb2fddc..f377a44910 100644 --- a/composer.json +++ b/composer.json @@ -74,10 +74,10 @@ "utopia-php/vcs": "0.9.*", "utopia-php/websocket": "0.3.*", "matomo/device-detector": "6.1.*", - "dragonmantank/cron-expression": "3.3.2", - "phpmailer/phpmailer": "6.9.1", - "chillerlan/php-qrcode": "4.3.4", - "adhocore/jwt": "1.1.2", + "dragonmantank/cron-expression": "^3.3.2", + "phpmailer/phpmailer": "^6.9.1", + "chillerlan/php-qrcode": "^4.3.4", + "adhocore/jwt": "^1.1.2", "spomky-labs/otphp": "^10.0", "webonyx/graphql-php": "14.11.*", "league/csv": "9.14.*" diff --git a/composer.lock b/composer.lock index 8eb130cfca..f5eef2b00f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "63feb1a7cf4cfa2cc7fa0870236e61ea", + "content-hash": "da423b25b2bd26a7e8768bbf0b172044", "packages": [ { "name": "adhocore/jwt", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/adhocore/php-jwt.git", - "reference": "6c434af7170090bb7a8880d2bc220a2254ba7899" + "reference": "ad417603d9d45578b6af2089ad5b78f101c82367" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/adhocore/php-jwt/zipball/6c434af7170090bb7a8880d2bc220a2254ba7899", - "reference": "6c434af7170090bb7a8880d2bc220a2254ba7899", + "url": "https://api.github.com/repos/adhocore/php-jwt/zipball/ad417603d9d45578b6af2089ad5b78f101c82367", + "reference": "ad417603d9d45578b6af2089ad5b78f101c82367", "shasum": "" }, "require": { "php": "^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^6.5 || ^7.5" + "phpunit/phpunit": "^7.5 || ^8.5" }, "type": "library", "autoload": { @@ -53,15 +53,19 @@ ], "support": { "issues": "https://github.com/adhocore/php-jwt/issues", - "source": "https://github.com/adhocore/php-jwt/tree/1.1.2" + "source": "https://github.com/adhocore/php-jwt/tree/1.1.3" }, "funding": [ { "url": "https://paypal.me/ji10", "type": "custom" + }, + { + "url": "https://github.com/adhocore", + "type": "github" } ], - "time": "2021-02-20T09:56:44+00:00" + "time": "2025-02-18T01:00:50+00:00" }, { "name": "appwrite/appwrite", @@ -339,31 +343,34 @@ }, { "name": "chillerlan/php-qrcode", - "version": "4.3.4", + "version": "4.4.2", "source": { "type": "git", "url": "https://github.com/chillerlan/php-qrcode.git", - "reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d" + "reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d", - "reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d", + "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4", + "reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4", "shasum": "" }, "require": { - "chillerlan/php-settings-container": "^2.1.4", + "chillerlan/php-settings-container": "^2.1.6 || ^3.2.1", "ext-mbstring": "*", "php": "^7.4 || ^8.0" }, "require-dev": { - "phan/phan": "^5.3", - "phpunit/phpunit": "^9.5", - "setasign/fpdf": "^1.8.2" + "phan/phan": "^5.4.5", + "phpmd/phpmd": "^2.15", + "phpunit/phpunit": "^9.6", + "setasign/fpdf": "^1.8.2", + "squizlabs/php_codesniffer": "^3.11" }, "suggest": { "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", - "setasign/fpdf": "Required to use the QR FPDF output." + "setasign/fpdf": "Required to use the QR FPDF output.", + "simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code" }, "type": "library", "autoload": { @@ -390,7 +397,7 @@ "homepage": "https://github.com/chillerlan/php-qrcode/graphs/contributors" } ], - "description": "A QR code generator. PHP 7.4+", + "description": "A QR code generator with a user friendly API. PHP 7.4+", "homepage": "https://github.com/chillerlan/php-qrcode", "keywords": [ "phpqrcode", @@ -401,43 +408,39 @@ ], "support": { "issues": "https://github.com/chillerlan/php-qrcode/issues", - "source": "https://github.com/chillerlan/php-qrcode/tree/4.3.4" + "source": "https://github.com/chillerlan/php-qrcode/tree/4.4.2" }, "funding": [ - { - "url": "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4", - "type": "custom" - }, { "url": "https://ko-fi.com/codemasher", "type": "ko_fi" } ], - "time": "2022-07-25T09:12:45+00:00" + "time": "2024-11-15T15:36:24+00:00" }, { "name": "chillerlan/php-settings-container", - "version": "2.1.6", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/chillerlan/php-settings-container.git", - "reference": "5553558bd381fce5108c6d0343c12e488cfec6bb" + "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/5553558bd381fce5108c6d0343c12e488cfec6bb", - "reference": "5553558bd381fce5108c6d0343c12e488cfec6bb", + "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681", + "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.4 || ^8.0" + "php": "^8.1" }, "require-dev": { "phpmd/phpmd": "^2.15", "phpstan/phpstan": "^1.11", "phpstan/phpstan-deprecation-rules": "^1.2", - "phpunit/phpunit": "^9.6", + "phpunit/phpunit": "^10.5", "squizlabs/php_codesniffer": "^3.10" }, "type": "library", @@ -457,10 +460,9 @@ "homepage": "https://github.com/codemasher" } ], - "description": "A container class for immutable settings objects. Not a DI container. PHP 7.4+", + "description": "A container class for immutable settings objects. Not a DI container.", "homepage": "https://github.com/chillerlan/php-settings-container", "keywords": [ - "PHP7", "Settings", "configuration", "container", @@ -480,7 +482,7 @@ "type": "ko_fi" } ], - "time": "2024-07-17T01:04:28+00:00" + "time": "2024-07-16T11:13:48+00:00" }, { "name": "composer/semver", @@ -565,16 +567,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.3.2", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8" + "reference": "8c784d071debd117328803d86b2097615b457500" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/782ca5968ab8b954773518e9e49a6f892a34b2a8", - "reference": "782ca5968ab8b954773518e9e49a6f892a34b2a8", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", "shasum": "" }, "require": { @@ -587,10 +589,14 @@ "require-dev": { "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.0", - "phpstan/phpstan-webmozart-assert": "^1.0", "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, "autoload": { "psr-4": { "Cron\\": "src/Cron/" @@ -614,7 +620,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.2" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" }, "funding": [ { @@ -622,7 +628,7 @@ "type": "github" } ], - "time": "2022-09-10T18:51:20+00:00" + "time": "2024-10-09T13:47:03+00:00" }, { "name": "giggsey/libphonenumber-for-php-lite", @@ -1238,16 +1244,16 @@ }, { "name": "open-telemetry/exporter-otlp", - "version": "1.3.0", + "version": "1.3.1", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/exporter-otlp.git", - "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c" + "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", - "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", + "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/8b3ca1f86d01429c73b407bf1a2075d9c187001e", + "reference": "8b3ca1f86d01429c73b407bf1a2075d9c187001e", "shasum": "" }, "require": { @@ -1298,7 +1304,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-12T00:36:35+00:00" + "time": "2025-05-21T12:02:20+00:00" }, { "name": "open-telemetry/gen-otlp-protobuf", @@ -1365,16 +1371,16 @@ }, { "name": "open-telemetry/sdk", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/sdk.git", - "reference": "939d3a28395c249a763676458140dad44b3a8011" + "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/939d3a28395c249a763676458140dad44b3a8011", - "reference": "939d3a28395c249a763676458140dad44b3a8011", + "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/cd0d7367599717fc29e04eb8838ec061e6c2c657", + "reference": "cd0d7367599717fc29e04eb8838ec061e6c2c657", "shasum": "" }, "require": { @@ -1451,7 +1457,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-07T12:32:21+00:00" + "time": "2025-05-22T02:33:34+00:00" }, { "name": "open-telemetry/sem-conv", @@ -2486,16 +2492,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", - "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { @@ -2508,7 +2514,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2533,7 +2539,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -2549,7 +2555,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/http-client", @@ -2648,16 +2654,16 @@ }, { "name": "symfony/http-client-contracts", - "version": "v3.5.2", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" + "reference": "75d7043853a42837e68111812f4d964b01e5101c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c", + "reference": "75d7043853a42837e68111812f4d964b01e5101c", "shasum": "" }, "require": { @@ -2670,7 +2676,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2706,7 +2712,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0" }, "funding": [ { @@ -2722,7 +2728,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T08:49:48+00:00" + "time": "2025-04-29T11:18:49+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2883,16 +2889,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.5.1", + "version": "v3.6.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", - "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { @@ -2910,7 +2916,7 @@ "name": "symfony/contracts" }, "branch-alias": { - "dev-main": "3.5-dev" + "dev-main": "3.6-dev" } }, "autoload": { @@ -2946,7 +2952,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -2962,7 +2968,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2025-04-25T09:37:31+00:00" }, { "name": "tbachert/spi", @@ -4332,16 +4338,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.12", + "version": "0.18.13", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97" + "reference": "3d8ce53ae042173bf230445e996056c5f65ded22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", - "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/3d8ce53ae042173bf230445e996056c5f65ded22", + "reference": "3d8ce53ae042173bf230445e996056c5f65ded22", "shasum": "" }, "require": { @@ -4384,9 +4390,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.12" + "source": "https://github.com/utopia-php/storage/tree/0.18.13" }, - "time": "2025-05-15T07:55:58+00:00" + "time": "2025-05-26T13:10:35+00:00" }, { "name": "utopia-php/swoole", @@ -4771,16 +4777,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.18", + "version": "0.40.19", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "38de4b9c58112d7e83eb75955994c8412a401093" + "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/38de4b9c58112d7e83eb75955994c8412a401093", - "reference": "38de4b9c58112d7e83eb75955994c8412a401093", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", + "reference": "05b53cf30c59fe5934d57207fefbc8ae8feb5dbf", "shasum": "" }, "require": { @@ -4816,9 +4822,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.40.18" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.19" }, - "time": "2025-05-21T14:14:47+00:00" + "time": "2025-05-24T22:49:50+00:00" }, { "name": "doctrine/annotations", From 852c6fc3fe84e79fad7bbc6dc0e12309378780b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 May 2025 10:35:08 +0200 Subject: [PATCH 30/75] Fix rules non-updated --- src/Appwrite/Platform/Modules/Compute/Base.php | 2 +- .../Modules/Functions/Http/Functions/Deployment/Update.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 47529a142b..14acacb89a 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -251,7 +251,7 @@ class Base extends Action $queries[] = Query::cursorAfter($cursor); } - $results = $database->find('rules', $queries); + $results = Authorization::skip(fn () => $database->find('rules', $queries)); $total = \count($results); if ($total > 0) { diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index d97bb92b73..c52be0d95f 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -115,7 +115,7 @@ class Update extends Base $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); - $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); + Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }); $queueForEvents From 64cea46183362172fd5f155f3f8e0e2699d253bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 May 2025 10:47:28 +0200 Subject: [PATCH 31/75] Permissiosn fix for sites --- .../Platform/Modules/Sites/Http/Sites/Deployment/Update.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index aa36b52c5a..d28113c303 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -12,6 +12,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; @@ -106,7 +107,7 @@ class Update extends Base $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); - $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); + Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); }); $queueForEvents From cedc4eb2df7cec743d261df84c05f0d311a44c42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 May 2025 11:06:08 +0200 Subject: [PATCH 32/75] Add logging --- src/Appwrite/Platform/Modules/Compute/Base.php | 5 +++++ .../Functions/Http/Functions/Deployment/Update.php | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 14acacb89a..d09daa29da 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -251,7 +251,9 @@ class Base extends Action $queries[] = Query::cursorAfter($cursor); } + \var_dump("Actual find"); $results = Authorization::skip(fn () => $database->find('rules', $queries)); + \var_dump($results); $total = \count($results); if ($total > 0) { @@ -263,8 +265,11 @@ class Base extends Action } foreach ($results as $document) { + \var_dump("In foreach"); if (is_callable($callback)) { + \var_dump("Callback start"); $callback($document); + \var_dump("Callback end"); } } } while (!\is_null($cursor)); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index c52be0d95f..726c1dec2b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -111,12 +111,21 @@ class Update extends Base Query::equal("deploymentVcsProviderBranch", [""]), ]; + \var_dump("About to set to deployment ID " . $deployment->getId()); + \var_dump("Project ID: " . $project->getId()); + \var_dump("Project internal ID: " . $project->getInternalId()); + \var_dump("Function internal ID: " . $function->getInternalId()); + $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { + \var_dump("Updating rule" . $rule->getId()); $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); + \var_dump("Successfully updated " . $rule->getId()); }); + + \var_dump("Post update"); $queueForEvents ->setParam('functionId', $function->getId()) From 675179def889829556956f2f83f564cfa8a3d804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 May 2025 11:41:46 +0200 Subject: [PATCH 33/75] Improve logs --- src/Appwrite/Platform/Modules/Compute/Base.php | 10 ++++------ .../Functions/Http/Functions/Deployment/Update.php | 9 --------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index d09daa29da..46f82af661 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -240,8 +240,10 @@ class Base extends Action { $limit = 100; $cursor = null; - + do { + \var_dump("Project internal ID: " . $project->getInternalId()); + $queries = \array_merge([ Query::limit($limit), Query::equal("projectInternalId", [$project->getInternalId()]) @@ -251,9 +253,8 @@ class Base extends Action $queries[] = Query::cursorAfter($cursor); } - \var_dump("Actual find"); + \var_dump($queries); $results = Authorization::skip(fn () => $database->find('rules', $queries)); - \var_dump($results); $total = \count($results); if ($total > 0) { @@ -265,11 +266,8 @@ class Base extends Action } foreach ($results as $document) { - \var_dump("In foreach"); if (is_callable($callback)) { - \var_dump("Callback start"); $callback($document); - \var_dump("Callback end"); } } } while (!\is_null($cursor)); diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index 726c1dec2b..f57ec8483c 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -110,22 +110,13 @@ class Update extends Base Query::equal("deploymentResourceInternalId", [$function->getInternalId()]), Query::equal("deploymentVcsProviderBranch", [""]), ]; - - \var_dump("About to set to deployment ID " . $deployment->getId()); - \var_dump("Project ID: " . $project->getId()); - \var_dump("Project internal ID: " . $project->getInternalId()); - \var_dump("Function internal ID: " . $function->getInternalId()); $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { - \var_dump("Updating rule" . $rule->getId()); $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); - \var_dump("Successfully updated " . $rule->getId()); }); - - \var_dump("Post update"); $queueForEvents ->setParam('functionId', $function->getId()) From 501d29f696ab84dce85e9749aa07d94bc66ea409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 27 May 2025 11:54:34 +0200 Subject: [PATCH 34/75] Implement a fix --- .../Platform/Modules/Compute/Base.php | 38 ------------- .../Http/Functions/Deployment/Update.php | 9 ++-- .../Modules/Functions/Workers/Builds.php | 53 +++++-------------- .../Sites/Http/Sites/Deployment/Update.php | 7 +-- 4 files changed, 21 insertions(+), 86 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 46f82af661..0541df551a 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -4,7 +4,6 @@ namespace Appwrite\Platform\Modules\Compute; use Appwrite\Event\Build; use Appwrite\Extend\Exception; -use Appwrite\Query; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Helpers\ID; @@ -235,41 +234,4 @@ class Base extends Action return $deployment; } - - protected function listRules(Document $project, array $queries, Database $database, callable $callback): void - { - $limit = 100; - $cursor = null; - - do { - \var_dump("Project internal ID: " . $project->getInternalId()); - - $queries = \array_merge([ - Query::limit($limit), - Query::equal("projectInternalId", [$project->getInternalId()]) - ], $queries); - - if ($cursor !== null) { - $queries[] = Query::cursorAfter($cursor); - } - - \var_dump($queries); - $results = Authorization::skip(fn () => $database->find('rules', $queries)); - - $total = \count($results); - if ($total > 0) { - $cursor = $results[$total - 1]; - } - - if ($total < $limit) { - $cursor = null; - } - - foreach ($results as $document) { - if (is_callable($callback)) { - $callback($document); - } - } - } while (!\is_null($cursor)); - } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php index f57ec8483c..e840441774 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Deployment/Update.php @@ -5,7 +5,6 @@ namespace Appwrite\Platform\Modules\Functions\Http\Functions\Deployment; use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Base; -use Appwrite\Query; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; @@ -13,6 +12,7 @@ use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\DateTime; use Utopia\Database\Document; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -109,14 +109,15 @@ class Update extends Base Query::equal("deploymentResourceType", ["function"]), Query::equal("deploymentResourceInternalId", [$function->getInternalId()]), Query::equal("deploymentVcsProviderBranch", [""]), + Query::equal("projectInternalId", [$project->getInternalId()]) ]; - - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { + + Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); - }); + }, $queries)); $queueForEvents ->setParam('functionId', $function->getId()) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index b5bd2ee8e6..b05da8485b 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1087,16 +1087,17 @@ class Builds extends Action Query::equal('deploymentResourceType', ['function']), Query::equal('trigger', ['manual']), Query::equal('deploymentVcsProviderBranch', ['']), + Query::equal("projectInternalId", [$project->getInternalId()]) ]; $rulesUpdated = false; - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment, &$rulesUpdated) { + $dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment, &$rulesUpdated) { $rulesUpdated = true; $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); - }); + }, $queries); break; case 'sites': $resource->setAttribute('deploymentId', $deployment->getId()); @@ -1112,14 +1113,15 @@ class Builds extends Action Query::equal('deploymentResourceType', ['site']), Query::equal('trigger', ['manual']), Query::equal('deploymentVcsProviderBranch', ['']), + Query::equal("projectInternalId", [$project->getInternalId()]) ]; - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { + $dbForPlatform->forEach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); - }); + }, $queries); break; } @@ -1161,19 +1163,22 @@ class Builds extends Action $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); } - $this->listRules($project, [ + $queries = [ Query::equal("projectInternalId", [$project->getInternalId()]), Query::equal("type", ["deployment"]), Query::equal("deploymentResourceInternalId", [$resource->getInternalId()]), Query::equal('deploymentResourceType', ['site']), Query::equal("deploymentVcsProviderBranch", [$branchName]), Query::equal("trigger", ['manual']), - ], $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { + Query::equal("projectInternalId", [$project->getInternalId()]) + ]; + + $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); $dbForPlatform->updateDocument('rules', $rule->getId(), $rule); - }); + }, $queries); } } @@ -1476,38 +1481,4 @@ class Builds extends Action } } } - - protected function listRules(Document $project, array $queries, Database $database, callable $callback): void - { - $limit = 100; - $cursor = null; - - do { - $queries = \array_merge([ - Query::limit($limit), - Query::equal("projectInternalId", [$project->getInternalId()]) - ], $queries); - - if ($cursor !== null) { - $queries[] = Query::cursorAfter($cursor); - } - - $results = $database->find('rules', $queries); - - $total = \count($results); - if ($total > 0) { - $cursor = $results[$total - 1]; - } - - if ($total < $limit) { - $cursor = null; - } - - foreach ($results as $document) { - if (is_callable($callback)) { - $callback($document); - } - } - } while (!\is_null($cursor)); - } } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php index d28113c303..a54d0c7889 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Deployment/Update.php @@ -5,13 +5,13 @@ namespace Appwrite\Platform\Modules\Sites\Http\Sites\Deployment; use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Base; -use Appwrite\Query; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; use Appwrite\SDK\Response as SDKResponse; use Appwrite\Utopia\Response; use Utopia\Database\Database; use Utopia\Database\Document; +use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\UID; use Utopia\Platform\Action; @@ -101,14 +101,15 @@ class Update extends Base Query::equal("deploymentResourceType", ["site"]), Query::equal("deploymentResourceInternalId", [$site->getInternalId()]), Query::equal("deploymentVcsProviderBranch", [""]), + Query::equal("projectInternalId", [$project->getInternalId()]) ]; - $this->listRules($project, $queries, $dbForPlatform, function (Document $rule) use ($dbForPlatform, $deployment) { + Authorization::skip(fn () => $dbForPlatform->foreach('rules', function (Document $rule) use ($dbForPlatform, $deployment) { $rule = $rule ->setAttribute('deploymentId', $deployment->getId()) ->setAttribute('deploymentInternalId', $deployment->getInternalId()); Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), $rule)); - }); + }, $queries)); $queueForEvents ->setParam('siteId', $site->getId()) From 7e6f4befa58dcf83d86fc976eeeb7eec2e8bf170 Mon Sep 17 00:00:00 2001 From: Darshan Date: Tue, 27 May 2025 19:21:28 +0530 Subject: [PATCH 35/75] reset: stuff from main. --- app/cli.php | 3 +- app/controllers/api/storage.php | 60 +++++++++---------- src/Appwrite/Platform/Tasks/ScheduleBase.php | 10 ++-- .../Platform/Tasks/ScheduleFunctions.php | 2 +- .../Platform/Tasks/ScheduleMessages.php | 2 +- 5 files changed, 39 insertions(+), 38 deletions(-) diff --git a/app/cli.php b/app/cli.php index 7c2daf4500..9517347420 100644 --- a/app/cli.php +++ b/app/cli.php @@ -284,5 +284,6 @@ $cli $cli->shutdown()->action(fn () => Timer::clearAll()); -Runtime::enableCoroutine(SWOOLE_HOOK_ALL); +// Enable coroutines, but disable TCP hooks. These don't work until we use `\Utopia\Cache\Adapter\Pool` and `\Utopia\Database\Adapter\Pool`. +Runtime::enableCoroutine(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); run($cli->run(...)); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index d2edf476f6..b3b8fb906a 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1004,7 +1004,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm', Compression::NONE); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', APP_STORAGE_READ_BUFFER)) { + if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; } else { @@ -1178,6 +1178,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } + $response + ->setContentType($file->getAttribute('mimeType')) + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') + ; + $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1186,7 +1193,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { + if ($end === null) { $end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1)); } @@ -1201,13 +1208,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } - $response - ->setContentType($file->getAttribute('mimeType')) - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') - ; - $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1345,6 +1345,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $contentType = $file->getAttribute('mimeType'); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ; + $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1353,8 +1362,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { - $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); + if ($end === null) { + $end = min(($start + 2000000 - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1368,15 +1377,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ; - $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1498,6 +1498,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $contentType = $file->getAttribute('mimeType'); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()); + $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1506,8 +1514,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { - $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); + if ($end === null) { + $end = min(($start + 2000000 - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1521,14 +1529,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()); - $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 28c77c1832..286ffe45cb 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -79,16 +79,16 @@ abstract class ScheduleBase extends Action // start with "0" to load all active documents. $lastSyncUpdate = "0"; - $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); Console::success("Starting timers at " . DateTime::now()); /** * The timer synchronize $schedules copy with database collection. */ - Timer::tick(static::UPDATE_TIMER * 1000, function () use ($dbForPlatform, $getProjectDB, &$lastSyncUpdate) { + Timer::tick(static::UPDATE_TIMER * 1000, function () use ($pools, $dbForPlatform, $getProjectDB, &$lastSyncUpdate) { $time = DateTime::now(); Console::log("Sync tick: Running at $time"); - $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); }); while (true) { @@ -103,7 +103,7 @@ abstract class ScheduleBase extends Action } } - private function collectSchedules(Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void + private function collectSchedules(Group $pools, Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void { // If we haven't synced yet, load all active schedules $initialLoad = $lastSyncUpdate === "0"; @@ -115,7 +115,7 @@ abstract class ScheduleBase extends Action * @throws Exception * @var Document $schedule */ - $getSchedule = function (Document $schedule) use ($dbForPlatform, $getProjectDB): array { + $getSchedule = function (Document $schedule) use ($pools, $dbForPlatform, $getProjectDB): array { $project = $dbForPlatform->getDocument('projects', $schedule->getAttribute('projectId')); $resource = $getProjectDB($project)->getDocument( diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index 7812b27832..19e068107a 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -76,7 +76,7 @@ class ScheduleFunctions extends ScheduleBase } foreach ($delayedExecutions as $delay => $schedules) { - \go(function () use ($delay, $schedules, $dbForPlatform) { + \go(function () use ($delay, $schedules, $pools, $dbForPlatform) { \sleep($delay); // in seconds foreach ($schedules as $delayConfig) { diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index d23e3de575..5e65f7a8a6 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -40,7 +40,7 @@ class ScheduleMessages extends ScheduleBase continue; } - \go(function () use ($schedule, $scheduledAt, $dbForPlatform) { + \go(function () use ($schedule, $scheduledAt, $pools, $dbForPlatform) { $queueForMessaging = new Messaging($this->publisher); $this->updateProjectAccess($schedule['project'], $dbForPlatform); From 320bf69208e743b9a9e3ac03f7da65f30bc0a49b Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Wed, 28 May 2025 12:50:47 +0530 Subject: [PATCH 36/75] Shorten commit url --- app/controllers/api/vcs.php | 8 ++++++- composer.lock | 24 +++++++++---------- .../Modules/Functions/Workers/Builds.php | 8 ++++++- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index a986d1004b..2529425bd1 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -293,7 +293,13 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId // VCS branch preview if (!empty($providerBranch)) { - $domain = "branch-{$providerBranch}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}"; + $branchPrefix = substr($providerBranch, 0, 16); + if (strlen($providerBranch) > 16) { + $remainingChars = substr($providerBranch, 16); + $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); + } + $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); + $domain = "branch-{$branchPrefix}{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { Authorization::skip( diff --git a/composer.lock b/composer.lock index f5b3f796c8..7f1799ac73 100644 --- a/composer.lock +++ b/composer.lock @@ -157,16 +157,16 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.19.0", + "version": "0.19.1", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "8d21483efc19b9d977e323188989ee67a188464b" + "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/runtimes/zipball/8d21483efc19b9d977e323188989ee67a188464b", - "reference": "8d21483efc19b9d977e323188989ee67a188464b", + "url": "https://api.github.com/repos/appwrite/runtimes/zipball/7bd0cc3cb97de625d7b07230bd91b121f88e72ae", + "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae", "shasum": "" }, "require": { @@ -206,9 +206,9 @@ ], "support": { "issues": "https://github.com/appwrite/runtimes/issues", - "source": "https://github.com/appwrite/runtimes/tree/0.19.0" + "source": "https://github.com/appwrite/runtimes/tree/0.19.1" }, - "time": "2025-03-25T22:37:51+00:00" + "time": "2025-05-27T07:12:56+00:00" }, { "name": "beberlei/assert", @@ -4378,16 +4378,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.12", + "version": "0.18.13", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97" + "reference": "3d8ce53ae042173bf230445e996056c5f65ded22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", - "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/3d8ce53ae042173bf230445e996056c5f65ded22", + "reference": "3d8ce53ae042173bf230445e996056c5f65ded22", "shasum": "" }, "require": { @@ -4430,9 +4430,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.12" + "source": "https://github.com/utopia-php/storage/tree/0.18.13" }, - "time": "2025-05-15T07:55:58+00:00" + "time": "2025-05-26T13:10:35+00:00" }, { "name": "utopia-php/swoole", diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index b05da8485b..40e1aa1547 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1132,7 +1132,13 @@ class Builds extends Action $branchName = $deployment->getAttribute('providerBranch'); if (!empty($branchName)) { $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); - $domain = "branch-{$branchName}-{$resource->getId()}-{$project->getId()}.{$sitesDomain}"; + $branchPrefix = substr($branchName, 0, 16); + if (strlen($branchName) > 16) { + $remainingChars = substr($branchName, 16); + $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); + } + $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); + $domain = "branch-{$branchPrefix}{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { From 66ac440f9da16c82c656df7b8c8b7824ac1d6d0b Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Wed, 28 May 2025 12:55:50 +0530 Subject: [PATCH 37/75] Add missing separator --- app/controllers/api/vcs.php | 2 +- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 2529425bd1..85c071151d 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -299,7 +299,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); } $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); - $domain = "branch-{$branchPrefix}{$resourceProjectHash}.{$sitesDomain}"; + $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { Authorization::skip( diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 40e1aa1547..b3d11d8b54 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1138,7 +1138,7 @@ class Builds extends Action $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); } $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); - $domain = "branch-{$branchPrefix}{$resourceProjectHash}.{$sitesDomain}"; + $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; $ruleId = md5($domain); try { From aa07ba002787826bd9a3f193b94cc46d7bcd85cb Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Wed, 28 May 2025 14:01:55 +0530 Subject: [PATCH 38/75] Update app/controllers/api/vcs.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matej Bačo --- app/controllers/api/vcs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 85c071151d..f80a51d497 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -296,7 +296,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId $branchPrefix = substr($providerBranch, 0, 16); if (strlen($providerBranch) > 16) { $remainingChars = substr($providerBranch, 16); - $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); + $branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7); } $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; From 707ef16f79caefd47c6d29ebaa4a94e6c98e5efc Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Wed, 28 May 2025 14:02:03 +0530 Subject: [PATCH 39/75] Update src/Appwrite/Platform/Modules/Functions/Workers/Builds.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matej Bačo --- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index b3d11d8b54..de5543c9f3 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1135,7 +1135,7 @@ class Builds extends Action $branchPrefix = substr($branchName, 0, 16); if (strlen($branchName) > 16) { $remainingChars = substr($branchName, 16); - $branchPrefix .= substr(hash('sha256', $remainingChars), 0, 7); + $branchPrefix .= '-' . substr(hash('sha256', $remainingChars), 0, 7); } $resourceProjectHash = substr(hash('sha256', $resource->getId() . $project->getId()), 0, 7); $domain = "branch-{$branchPrefix}-{$resourceProjectHash}.{$sitesDomain}"; From 814abddf937e773aafe04141ab7c849ee2c7310f Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Wed, 28 May 2025 14:10:12 +0530 Subject: [PATCH 40/75] Truncate commit hash to 16 chars --- app/controllers/api/vcs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index f80a51d497..588ca417cf 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -330,7 +330,7 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId // VCS commit preview if (!empty($providerCommitHash)) { - $domain = "commit-{$providerCommitHash}.{$sitesDomain}"; + $domain = "commit-" . substr($providerCommitHash, 0, 16) . ".{$sitesDomain}"; $ruleId = md5($domain); try { Authorization::skip( From 0d46d4d6e9348980cb5ab17207e6ee6eca0dde63 Mon Sep 17 00:00:00 2001 From: fogelito Date: Wed, 28 May 2025 15:54:58 +0300 Subject: [PATCH 41/75] Remove roles index --- app/config/collections/common.php | 7 ------- src/Appwrite/Migration/Version/V22.php | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/app/config/collections/common.php b/app/config/collections/common.php index e77d5403d2..6de7eb224b 100644 --- a/app/config/collections/common.php +++ b/app/config/collections/common.php @@ -1439,13 +1439,6 @@ return [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], - [ - '$id' => ID::custom('_key_roles'), - 'type' => Database::INDEX_KEY, - 'attributes' => ['roles'], - 'lengths' => [128], - 'orders' => [], - ], ], ], diff --git a/src/Appwrite/Migration/Version/V22.php b/src/Appwrite/Migration/Version/V22.php index 2a6a64ed48..33e18e2956 100644 --- a/src/Appwrite/Migration/Version/V22.php +++ b/src/Appwrite/Migration/Version/V22.php @@ -145,17 +145,17 @@ class V22 extends Migration $this->dbForProject->purgeCachedCollection($id); break; case 'memberships': - $indexes = [ - '_key_roles', - ]; - foreach ($indexes as $index) { - try { - $this->createIndexFromCollection($this->dbForProject, $id, $index); - } catch (Throwable $th) { - Console::warning("Failed to create index \"$index\" from {$id}: {$th->getMessage()}"); - } - } - $this->dbForProject->purgeCachedCollection($id); +// $indexes = [ +// '_key_roles', +// ]; +// foreach ($indexes as $index) { +// try { +// $this->createIndexFromCollection($this->dbForProject, $id, $index); +// } catch (Throwable $th) { +// Console::warning("Failed to create index \"$index\" from {$id}: {$th->getMessage()}"); +// } +// } +// $this->dbForProject->purgeCachedCollection($id); break; case 'migrations': $attributes = [ From 601b6760a5cef97cd423eea66f932e474c45b63d Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 29 May 2025 05:33:26 +0000 Subject: [PATCH 42/75] fix version pinning --- composer.json | 8 +++--- composer.lock | 68 +++++++++++++++++++++++++-------------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/composer.json b/composer.json index f24bfac20e..833f1a462b 100644 --- a/composer.json +++ b/composer.json @@ -76,10 +76,10 @@ "utopia-php/vcs": "0.10.*", "utopia-php/websocket": "0.3.*", "matomo/device-detector": "6.1.*", - "dragonmantank/cron-expression": "^3.3.2", - "phpmailer/phpmailer": "^6.9.1", - "chillerlan/php-qrcode": "^4.3.4", - "adhocore/jwt": "^1.1.2", + "dragonmantank/cron-expression": "3.3.*", + "phpmailer/phpmailer": "6.9.*", + "chillerlan/php-qrcode": "4.3.*", + "adhocore/jwt": "1.1.*", "spomky-labs/otphp": "^10.0", "webonyx/graphql-php": "14.11.*", "league/csv": "9.14.*" diff --git a/composer.lock b/composer.lock index 8c6de32697..7c838626b0 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": "b7bac964db0e1b6d640eb743b8ac0d9b", + "content-hash": "de0a0fb794f826fcc412c788185b69f4", "packages": [ { "name": "adhocore/jwt", @@ -343,34 +343,31 @@ }, { "name": "chillerlan/php-qrcode", - "version": "4.4.2", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/chillerlan/php-qrcode.git", - "reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4" + "reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4", - "reference": "345ed8e4ffb56e6b3fcd9f42e3970b9026fa6ce4", + "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d", + "reference": "2ca4bf5ae048af1981d1023ee42a0a2a9d51e51d", "shasum": "" }, "require": { - "chillerlan/php-settings-container": "^2.1.6 || ^3.2.1", + "chillerlan/php-settings-container": "^2.1.4", "ext-mbstring": "*", "php": "^7.4 || ^8.0" }, "require-dev": { - "phan/phan": "^5.4.5", - "phpmd/phpmd": "^2.15", - "phpunit/phpunit": "^9.6", - "setasign/fpdf": "^1.8.2", - "squizlabs/php_codesniffer": "^3.11" + "phan/phan": "^5.3", + "phpunit/phpunit": "^9.5", + "setasign/fpdf": "^1.8.2" }, "suggest": { "chillerlan/php-authenticator": "Yet another Google authenticator! Also creates URIs for mobile apps.", - "setasign/fpdf": "Required to use the QR FPDF output.", - "simple-icons/simple-icons": "SVG icons that you can use to embed as logos in the QR Code" + "setasign/fpdf": "Required to use the QR FPDF output." }, "type": "library", "autoload": { @@ -397,7 +394,7 @@ "homepage": "https://github.com/chillerlan/php-qrcode/graphs/contributors" } ], - "description": "A QR code generator with a user friendly API. PHP 7.4+", + "description": "A QR code generator. PHP 7.4+", "homepage": "https://github.com/chillerlan/php-qrcode", "keywords": [ "phpqrcode", @@ -408,39 +405,43 @@ ], "support": { "issues": "https://github.com/chillerlan/php-qrcode/issues", - "source": "https://github.com/chillerlan/php-qrcode/tree/4.4.2" + "source": "https://github.com/chillerlan/php-qrcode/tree/4.3.4" }, "funding": [ + { + "url": "https://www.paypal.com/donate?hosted_button_id=WLYUNAT9ZTJZ4", + "type": "custom" + }, { "url": "https://ko-fi.com/codemasher", "type": "ko_fi" } ], - "time": "2024-11-15T15:36:24+00:00" + "time": "2022-07-25T09:12:45+00:00" }, { "name": "chillerlan/php-settings-container", - "version": "3.2.1", + "version": "2.1.6", "source": { "type": "git", "url": "https://github.com/chillerlan/php-settings-container.git", - "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681" + "reference": "5553558bd381fce5108c6d0343c12e488cfec6bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/95ed3e9676a1d47cab2e3174d19b43f5dbf52681", - "reference": "95ed3e9676a1d47cab2e3174d19b43f5dbf52681", + "url": "https://api.github.com/repos/chillerlan/php-settings-container/zipball/5553558bd381fce5108c6d0343c12e488cfec6bb", + "reference": "5553558bd381fce5108c6d0343c12e488cfec6bb", "shasum": "" }, "require": { "ext-json": "*", - "php": "^8.1" + "php": "^7.4 || ^8.0" }, "require-dev": { "phpmd/phpmd": "^2.15", "phpstan/phpstan": "^1.11", "phpstan/phpstan-deprecation-rules": "^1.2", - "phpunit/phpunit": "^10.5", + "phpunit/phpunit": "^9.6", "squizlabs/php_codesniffer": "^3.10" }, "type": "library", @@ -460,9 +461,10 @@ "homepage": "https://github.com/codemasher" } ], - "description": "A container class for immutable settings objects. Not a DI container.", + "description": "A container class for immutable settings objects. Not a DI container. PHP 7.4+", "homepage": "https://github.com/chillerlan/php-settings-container", "keywords": [ + "PHP7", "Settings", "configuration", "container", @@ -482,7 +484,7 @@ "type": "ko_fi" } ], - "time": "2024-07-16T11:13:48+00:00" + "time": "2024-07-17T01:04:28+00:00" }, { "name": "composer/semver", @@ -567,16 +569,16 @@ }, { "name": "dragonmantank/cron-expression", - "version": "v3.4.0", + "version": "v3.3.3", "source": { "type": "git", "url": "https://github.com/dragonmantank/cron-expression.git", - "reference": "8c784d071debd117328803d86b2097615b457500" + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", - "reference": "8c784d071debd117328803d86b2097615b457500", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", + "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a", "shasum": "" }, "require": { @@ -589,14 +591,10 @@ "require-dev": { "phpstan/extension-installer": "^1.0", "phpstan/phpstan": "^1.0", + "phpstan/phpstan-webmozart-assert": "^1.0", "phpunit/phpunit": "^7.0|^8.0|^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "autoload": { "psr-4": { "Cron\\": "src/Cron/" @@ -620,7 +618,7 @@ ], "support": { "issues": "https://github.com/dragonmantank/cron-expression/issues", - "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3" }, "funding": [ { @@ -628,7 +626,7 @@ "type": "github" } ], - "time": "2024-10-09T13:47:03+00:00" + "time": "2023-08-10T19:36:49+00:00" }, { "name": "giggsey/libphonenumber-for-php-lite", From 7d284a9872bc124c868359a1219833deb1cf8c3f Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Thu, 29 May 2025 14:34:21 +0530 Subject: [PATCH 43/75] Remove powered by from error pages --- app/views/general/error.phtml | 4 ++-- tests/e2e/Services/Sites/SitesCustomServerTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/general/error.phtml b/app/views/general/error.phtml index de1c2b6541..9706c8ee94 100644 --- a/app/views/general/error.phtml +++ b/app/views/general/error.phtml @@ -512,7 +512,7 @@ switch ($type) { -
+ \ No newline at end of file diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index d3b4922b87..3a70a21e37 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1446,7 +1446,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(404, $response['headers']['status-code']); $this->assertStringContainsString("Page not found", $response['body']); // Title $this->assertStringContainsString("Go to homepage", $response['body']); // Button - $this->assertStringContainsString("Powered by", $response['body']); // Brand + // $this->assertStringContainsString("Powered by", $response['body']); // Brand $this->cleanupSite($siteId); } @@ -1502,7 +1502,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertStringContainsString("Customized 404 page", $response['body']); - $this->assertStringNotContainsString("Powered by", $response['body']); // Brand + // $this->assertStringNotContainsString("Powered by", $response['body']); // Brand $this->cleanupSite($siteId); } From c4510004ce15969edd951c7187a772182351a120 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Thu, 29 May 2025 14:46:25 +0530 Subject: [PATCH 44/75] update test --- tests/e2e/Services/Sites/SitesCustomServerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 3a70a21e37..8459e46c6f 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1446,7 +1446,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(404, $response['headers']['status-code']); $this->assertStringContainsString("Page not found", $response['body']); // Title $this->assertStringContainsString("Go to homepage", $response['body']); // Button - // $this->assertStringContainsString("Powered by", $response['body']); // Brand + $this->assertStringNotContainsString("Powered by", $response['body']); // Brand $this->cleanupSite($siteId); } @@ -1502,7 +1502,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); $this->assertStringContainsString("Customized 404 page", $response['body']); - // $this->assertStringNotContainsString("Powered by", $response['body']); // Brand + $this->assertStringNotContainsString("Powered by", $response['body']); //brand $this->cleanupSite($siteId); } From 823d8604bd8afb78604e2693fecf7539faa622c0 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 29 May 2025 22:39:12 +1200 Subject: [PATCH 45/75] Update database --- composer.lock | 91 ++++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/composer.lock b/composer.lock index 7c838626b0..8ecfcf6a18 100644 --- a/composer.lock +++ b/composer.lock @@ -2557,16 +2557,16 @@ }, { "name": "symfony/http-client", - "version": "v7.2.4", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6" + "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", - "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", + "url": "https://api.github.com/repos/symfony/http-client/zipball/57e4fb86314015a695a750ace358d07a7e37b8a9", + "reference": "57e4fb86314015a695a750ace358d07a7e37b8a9", "shasum": "" }, "require": { @@ -2632,7 +2632,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.0" }, "funding": [ { @@ -2648,7 +2648,7 @@ "type": "tidelift" } ], - "time": "2025-02-13T10:27:23+00:00" + "time": "2025-05-02T08:23:16+00:00" }, { "name": "symfony/http-client-contracts", @@ -3503,16 +3503,16 @@ }, { "name": "utopia-php/database", - "version": "0.69.5", + "version": "0.69.6", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "4abe53609dfc23b2ea82884d12b149df6a8af2f5" + "reference": "42bfc0d87de4ade26cfd9915aaad84912761466b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/4abe53609dfc23b2ea82884d12b149df6a8af2f5", - "reference": "4abe53609dfc23b2ea82884d12b149df6a8af2f5", + "url": "https://api.github.com/repos/utopia-php/database/zipball/42bfc0d87de4ade26cfd9915aaad84912761466b", + "reference": "42bfc0d87de4ade26cfd9915aaad84912761466b", "shasum": "" }, "require": { @@ -3553,9 +3553,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.69.5" + "source": "https://github.com/utopia-php/database/tree/0.69.6" }, - "time": "2025-05-17T08:01:51+00:00" + "time": "2025-05-29T10:36:03+00:00" }, { "name": "utopia-php/detector", @@ -7266,23 +7266,24 @@ }, { "name": "symfony/console", - "version": "v7.2.6", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218" + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0e2e3f38c192e93e622e41ec37f4ca70cfedf218", - "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218", + "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^6.4|^7.0" + "symfony/string": "^7.2" }, "conflict": { "symfony/dependency-injection": "<6.4", @@ -7339,7 +7340,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.2.6" + "source": "https://github.com/symfony/console/tree/v7.3.0" }, "funding": [ { @@ -7355,11 +7356,11 @@ "type": "tidelift" } ], - "time": "2025-04-07T19:09:28+00:00" + "time": "2025-05-24T10:34:04+00:00" }, { "name": "symfony/filesystem", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", @@ -7405,7 +7406,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.0" }, "funding": [ { @@ -7425,16 +7426,16 @@ }, { "name": "symfony/finder", - "version": "v7.2.2", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", - "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", "shasum": "" }, "require": { @@ -7469,7 +7470,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.2.2" + "source": "https://github.com/symfony/finder/tree/v7.3.0" }, "funding": [ { @@ -7485,20 +7486,20 @@ "type": "tidelift" } ], - "time": "2024-12-30T19:00:17+00:00" + "time": "2024-12-30T19:00:26+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.2.0", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", - "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/afb9a8038025e5dbc657378bfab9198d75f10fca", + "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca", "shasum": "" }, "require": { @@ -7536,7 +7537,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.0" }, "funding": [ { @@ -7552,7 +7553,7 @@ "type": "tidelift" } ], - "time": "2024-11-20T11:17:29+00:00" + "time": "2025-04-04T13:12:05+00:00" }, { "name": "symfony/polyfill-ctype", @@ -7870,16 +7871,16 @@ }, { "name": "symfony/process", - "version": "v7.2.5", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { @@ -7911,7 +7912,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.5" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -7927,20 +7928,20 @@ "type": "tidelift" } ], - "time": "2025-03-13T12:21:46+00:00" + "time": "2025-04-17T09:11:12+00:00" }, { "name": "symfony/string", - "version": "v7.2.6", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931" + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931", - "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", "shasum": "" }, "require": { @@ -7998,7 +7999,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.2.6" + "source": "https://github.com/symfony/string/tree/v7.3.0" }, "funding": [ { @@ -8014,7 +8015,7 @@ "type": "tidelift" } ], - "time": "2025-04-20T20:18:16+00:00" + "time": "2025-04-20T20:19:01+00:00" }, { "name": "textalk/websocket", From d7653c68cebaffb3d299f9058604604ac39831ad Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 29 May 2025 14:51:18 +0300 Subject: [PATCH 46/75] formatting --- src/Appwrite/Migration/Version/V22.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Appwrite/Migration/Version/V22.php b/src/Appwrite/Migration/Version/V22.php index 33e18e2956..a3197ec3d9 100644 --- a/src/Appwrite/Migration/Version/V22.php +++ b/src/Appwrite/Migration/Version/V22.php @@ -145,17 +145,17 @@ class V22 extends Migration $this->dbForProject->purgeCachedCollection($id); break; case 'memberships': -// $indexes = [ -// '_key_roles', -// ]; -// foreach ($indexes as $index) { -// try { -// $this->createIndexFromCollection($this->dbForProject, $id, $index); -// } catch (Throwable $th) { -// Console::warning("Failed to create index \"$index\" from {$id}: {$th->getMessage()}"); -// } -// } -// $this->dbForProject->purgeCachedCollection($id); + // $indexes = [ + // '_key_roles', + // ]; + // foreach ($indexes as $index) { + // try { + // $this->createIndexFromCollection($this->dbForProject, $id, $index); + // } catch (Throwable $th) { + // Console::warning("Failed to create index \"$index\" from {$id}: {$th->getMessage()}"); + // } + // } + // $this->dbForProject->purgeCachedCollection($id); break; case 'migrations': $attributes = [ From c6b1209b8ff351c336c15b7139eb19d9b76f6ef1 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 30 May 2025 00:32:55 +1200 Subject: [PATCH 47/75] Disable TCP hook on stats resources --- src/Appwrite/Platform/Tasks/StatsResources.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index ca2a6860ff..bcc2d242d7 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -4,6 +4,7 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Event\StatsResources as EventStatsResources; use Appwrite\Platform\Action; +use Swoole\Runtime; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; @@ -50,6 +51,8 @@ class StatsResources extends Action public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue): void { + Runtime::enableCoroutine(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); + $this->logError = $logError; $this->dbForPlatform = $dbForPlatform; From 0097a0edcd996896e34c4c83a1539601401e1614 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 29 May 2025 15:37:08 +0300 Subject: [PATCH 48/75] Update migration self-hosted --- src/Appwrite/Migration/Version/V22.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Appwrite/Migration/Version/V22.php b/src/Appwrite/Migration/Version/V22.php index a3197ec3d9..fd80af565b 100644 --- a/src/Appwrite/Migration/Version/V22.php +++ b/src/Appwrite/Migration/Version/V22.php @@ -145,17 +145,16 @@ class V22 extends Migration $this->dbForProject->purgeCachedCollection($id); break; case 'memberships': - // $indexes = [ - // '_key_roles', - // ]; - // foreach ($indexes as $index) { - // try { - // $this->createIndexFromCollection($this->dbForProject, $id, $index); - // } catch (Throwable $th) { - // Console::warning("Failed to create index \"$index\" from {$id}: {$th->getMessage()}"); - // } - // } - // $this->dbForProject->purgeCachedCollection($id); + $indexes = [ + '_key_roles', + ]; + foreach ($indexes as $index) { + try { + $this->dbForProject->deleteIndex($id, $index); + } catch (Throwable $th) { + Console::warning("Failed to delete index \"$index\" from {$id}: {$th->getMessage()}"); + } + } break; case 'migrations': $attributes = [ From 9829ba2afba6fc621ff581bda8754ed41bc3a0a0 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 29 May 2025 15:40:11 +0300 Subject: [PATCH 49/75] Not sure we need it but ok --- src/Appwrite/Migration/Version/V22.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Appwrite/Migration/Version/V22.php b/src/Appwrite/Migration/Version/V22.php index fd80af565b..cfe4f1fe57 100644 --- a/src/Appwrite/Migration/Version/V22.php +++ b/src/Appwrite/Migration/Version/V22.php @@ -155,6 +155,7 @@ class V22 extends Migration Console::warning("Failed to delete index \"$index\" from {$id}: {$th->getMessage()}"); } } + $this->dbForProject->purgeCachedCollection($id); break; case 'migrations': $attributes = [ From 0a80ffe4a7e6b781e9eaf3cd42f876fc5c6b6554 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Thu, 29 May 2025 18:29:15 +0530 Subject: [PATCH 50/75] Fix error --- tests/e2e/Services/Sites/SitesCustomServerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 8459e46c6f..879182539a 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1446,7 +1446,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(404, $response['headers']['status-code']); $this->assertStringContainsString("Page not found", $response['body']); // Title $this->assertStringContainsString("Go to homepage", $response['body']); // Button - $this->assertStringNotContainsString("Powered by", $response['body']); // Brand + $this->assertStringContainsString("Powered by", $response['body']); // Brand $this->cleanupSite($siteId); } From 972c9dde210a64d42ae4c7123119bf856f205a41 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 30 May 2025 01:51:00 +1200 Subject: [PATCH 51/75] Revert "Merge pull request #9932 from appwrite/fix-disable-tcp-hook" This reverts commit 7a34c7b8dfd3784f2c393f30d1d5f2398642ef37, reversing changes made to 2b9b76f7bd6fc3dec0d8b85e9cea94c15035d3a7. --- src/Appwrite/Platform/Tasks/StatsResources.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/StatsResources.php b/src/Appwrite/Platform/Tasks/StatsResources.php index bcc2d242d7..ca2a6860ff 100644 --- a/src/Appwrite/Platform/Tasks/StatsResources.php +++ b/src/Appwrite/Platform/Tasks/StatsResources.php @@ -4,7 +4,6 @@ namespace Appwrite\Platform\Tasks; use Appwrite\Event\StatsResources as EventStatsResources; use Appwrite\Platform\Action; -use Swoole\Runtime; use Utopia\CLI\Console; use Utopia\Database\Database; use Utopia\Database\DateTime; @@ -51,8 +50,6 @@ class StatsResources extends Action public function action(Database $dbForPlatform, callable $logError, EventStatsResources $queue): void { - Runtime::enableCoroutine(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); - $this->logError = $logError; $this->dbForPlatform = $dbForPlatform; From 502b7df2d0b18393b17890c033fbaedef9889cf2 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Fri, 30 May 2025 11:26:05 +0530 Subject: [PATCH 52/75] Remove powered by from all error pages --- app/views/general/404.phtml | 4 ++-- tests/e2e/Services/Sites/SitesCustomServerTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/general/404.phtml b/app/views/general/404.phtml index 5e63344c8a..fb06c07f3e 100644 --- a/app/views/general/404.phtml +++ b/app/views/general/404.phtml @@ -152,7 +152,7 @@
-
+ \ No newline at end of file diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 879182539a..8459e46c6f 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -1446,7 +1446,7 @@ class SitesCustomServerTest extends Scope $this->assertEquals(404, $response['headers']['status-code']); $this->assertStringContainsString("Page not found", $response['body']); // Title $this->assertStringContainsString("Go to homepage", $response['body']); // Button - $this->assertStringContainsString("Powered by", $response['body']); // Brand + $this->assertStringNotContainsString("Powered by", $response['body']); // Brand $this->cleanupSite($siteId); } From 34150f0c380dbe79b2213088378598fdba519cf1 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Fri, 30 May 2025 12:39:33 +0530 Subject: [PATCH 53/75] Remove div --- app/views/general/404.phtml | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/app/views/general/404.phtml b/app/views/general/404.phtml index fb06c07f3e..2a9ff7f312 100644 --- a/app/views/general/404.phtml +++ b/app/views/general/404.phtml @@ -151,37 +151,6 @@
- - \ No newline at end of file From 2ef2c59d187acebaea28974678355873e31d23c9 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 14:03:51 +0530 Subject: [PATCH 54/75] update: exceptions and messages. --- app/config/errors.php | 10 ++++++++++ app/controllers/api/teams.php | 7 ++----- src/Appwrite/Extend/Exception.php | 2 ++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index 6d9d29a8ea..8365e8c705 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -393,6 +393,16 @@ return [ 'description' => 'Membership is already confirmed.', 'code' => 409, ], + Exception::MEMBERSHIP_DELETION_PROHIBITED => [ + 'name' => Exception::MEMBERSHIP_DELETION_PROHIBITED, + 'description' => 'Membership deletion is prohibited.', + 'code' => 400, + ], + Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED => [ + 'name' => Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED, + 'description' => 'Membership role downgrade is prohibited.', + 'code' => 400, + ], /** Avatars */ Exception::AVATAR_SET_NOT_FOUND => [ diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index aa85852049..cc10b7cead 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1103,7 +1103,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') // Prevent role change if there's only one owner left, // the requester is that owner, and the new `$roles` no longer include 'owner' if ($ownersCount === 1 && $isOwner && $isCurrentUserAnOwner && !\in_array('owner', $roles)) { - throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.'); + throw new Exception(Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED, 'There must be at least one owner.'); } } @@ -1364,10 +1364,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') if ($ownersCount === 1 && $isCurrentUserAnOwner) { /* Prevent removal if the user is the only owner. */ - throw new Exception( - Exception::GENERAL_ARGUMENT_INVALID, - 'There must be at least one owner in the organization.' - ); + throw new Exception(Exception::MEMBERSHIP_DELETION_PROHIBITED, 'There must be at least one owner.'); } } diff --git a/src/Appwrite/Extend/Exception.php b/src/Appwrite/Extend/Exception.php index 296434ed57..3af6d9962c 100644 --- a/src/Appwrite/Extend/Exception.php +++ b/src/Appwrite/Extend/Exception.php @@ -124,6 +124,8 @@ class Exception extends \Exception /** Membership */ public const MEMBERSHIP_NOT_FOUND = 'membership_not_found'; public const MEMBERSHIP_ALREADY_CONFIRMED = 'membership_already_confirmed'; + public const MEMBERSHIP_DELETION_PROHIBITED = 'membership_deletion_prohibited'; + public const MEMBERSHIP_DOWNGRADE_PROHIBITED = 'membership_downgrade_prohibited'; /** Avatars */ public const AVATAR_SET_NOT_FOUND = 'avatar_set_not_found'; From 65ae22d7cd6af437066320d210b44ad1defe0513 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 14:08:25 +0530 Subject: [PATCH 55/75] update: messages because the check is only for console project > organizations. --- app/controllers/api/teams.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index cc10b7cead..ede61115e2 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1103,7 +1103,7 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') // Prevent role change if there's only one owner left, // the requester is that owner, and the new `$roles` no longer include 'owner' if ($ownersCount === 1 && $isOwner && $isCurrentUserAnOwner && !\in_array('owner', $roles)) { - throw new Exception(Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED, 'There must be at least one owner.'); + throw new Exception(Exception::MEMBERSHIP_DOWNGRADE_PROHIBITED, 'There must be at least one owner in the organization.'); } } @@ -1364,7 +1364,7 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') if ($ownersCount === 1 && $isCurrentUserAnOwner) { /* Prevent removal if the user is the only owner. */ - throw new Exception(Exception::MEMBERSHIP_DELETION_PROHIBITED, 'There must be at least one owner.'); + throw new Exception(Exception::MEMBERSHIP_DELETION_PROHIBITED, 'There must be at least one owner in the organization.'); } } From b3098085924e4a1df7d0d242ad8347ab6c478f71 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Fri, 30 May 2025 14:18:35 +0530 Subject: [PATCH 56/75] Remove all 'powered by' divs --- app/views/general/error.phtml | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/app/views/general/error.phtml b/app/views/general/error.phtml index 9706c8ee94..a427f1d5e8 100644 --- a/app/views/general/error.phtml +++ b/app/views/general/error.phtml @@ -512,36 +512,6 @@ switch ($type) { - \ No newline at end of file From 3063ac899c9a1cd971e068db3f04020a358fe1b4 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 14:21:11 +0530 Subject: [PATCH 57/75] update: tests. --- tests/e2e/Services/Teams/TeamsBase.php | 2 +- tests/e2e/Services/Teams/TeamsConsoleClientTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 80ac1621ee..fccfded1e1 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -64,7 +64,7 @@ trait TeamsBase // Step 4: Assert failure — cannot remove the only OWNER from a team $this->assertEquals(400, $response['headers']['status-code']); - $this->assertEquals('general_argument_invalid', $response['body']['type']); + $this->assertEquals('membership_downgrade_prohibited', $response['body']['type']); $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); } diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 59945b1191..dda7f8e4ae 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -100,6 +100,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals('membership_deletion_prohibited', $response['body']['type']); $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); // Remove the excess developer member to reduce the membership count in `TeamsBaseClient` tests. @@ -241,6 +242,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals('membership_deletion_prohibited', $response['body']['type']); $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships/' . $ownerMembershipUid, array_merge([ From 4fc84bec7d6153a5dacf4cc1f8df8177988b6350 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 14:33:37 +0530 Subject: [PATCH 58/75] reset: stuff on target branch. --- .github/workflows/sdk-preview.yml | 2 +- app/cli.php | 3 +- app/config/platforms.php | 6 +- app/controllers/api/storage.php | 60 +++++++++---------- docs/sdks/flutter/CHANGELOG.md | 4 +- src/Appwrite/Platform/Tasks/ScheduleBase.php | 10 ++-- .../Platform/Tasks/ScheduleFunctions.php | 2 +- 7 files changed, 42 insertions(+), 45 deletions(-) diff --git a/.github/workflows/sdk-preview.yml b/.github/workflows/sdk-preview.yml index 8abe2c2f91..e317845768 100644 --- a/.github/workflows/sdk-preview.yml +++ b/.github/workflows/sdk-preview.yml @@ -47,7 +47,7 @@ jobs: node-version: 20 - name: Build and Publish SDK - working-directory: ./app/sdks/${{ steps.set-sdk.outputs.platform }}-${{ steps.set-sdk.outputs.sdk_type }} + working-directory: ./app/sdks/console-web run: | npm install npm run build diff --git a/app/cli.php b/app/cli.php index 9517347420..7c2daf4500 100644 --- a/app/cli.php +++ b/app/cli.php @@ -284,6 +284,5 @@ $cli $cli->shutdown()->action(fn () => Timer::clearAll()); -// Enable coroutines, but disable TCP hooks. These don't work until we use `\Utopia\Cache\Adapter\Pool` and `\Utopia\Database\Adapter\Pool`. -Runtime::enableCoroutine(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); +Runtime::enableCoroutine(SWOOLE_HOOK_ALL); run($cli->run(...)); diff --git a/app/config/platforms.php b/app/config/platforms.php index 4b2faf0487..7d481d508e 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -11,7 +11,7 @@ return [ [ 'key' => 'web', 'name' => 'Web', - 'version' => '18.1.1', + 'version' => '18.1.0', 'url' => 'https://github.com/appwrite/sdk-for-web', 'package' => 'https://www.npmjs.com/package/appwrite', 'enabled' => true, @@ -59,7 +59,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '17.0.0', + 'version' => '16.1.0', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, @@ -134,7 +134,7 @@ return [ [ 'key' => 'react-native', 'name' => 'React Native', - 'version' => '0.9.2', + 'version' => '0.9.1', 'url' => 'https://github.com/appwrite/sdk-for-react-native', 'package' => 'https://npmjs.com/package/react-native-appwrite', 'enabled' => true, diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index b3b8fb906a..d2edf476f6 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -1004,7 +1004,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $algorithm = $file->getAttribute('algorithm', Compression::NONE); $cipher = $file->getAttribute('openSSLCipher'); $mime = $file->getAttribute('mimeType'); - if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', 20000000)) { + if (!\in_array($mime, $inputs) || $file->getAttribute('sizeActual') > (int) System::getEnv('_APP_STORAGE_PREVIEW_LIMIT', APP_STORAGE_READ_BUFFER)) { if (!\in_array($mime, $inputs)) { $path = (\array_key_exists($mime, $fileLogos)) ? $fileLogos[$mime] : $fileLogos['default']; } else { @@ -1178,13 +1178,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') throw new Exception(Exception::STORAGE_FILE_NOT_FOUND, 'File not found in ' . $path); } - $response - ->setContentType($file->getAttribute('mimeType')) - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') - ; - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1193,7 +1186,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { $end = min(($start + MAX_OUTPUT_CHUNK_SIZE - 1), ($size - 1)); } @@ -1208,6 +1201,13 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($file->getAttribute('mimeType')) + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') + ; + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1345,15 +1345,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $contentType = $file->getAttribute('mimeType'); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()) - ; - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1362,8 +1353,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { - $end = min(($start + 2000000 - 1), ($size - 1)); + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { + $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1377,6 +1368,15 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()) + ; + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); @@ -1498,14 +1498,6 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $contentType = $file->getAttribute('mimeType'); } - $response - ->setContentType($contentType) - ->addHeader('Content-Security-Policy', 'script-src none;') - ->addHeader('X-Content-Type-Options', 'nosniff') - ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days - ->addHeader('X-Peak', \memory_get_peak_usage()); - $size = $file->getAttribute('sizeOriginal', 0); $rangeHeader = $request->getHeader('range'); @@ -1514,8 +1506,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') $end = $request->getRangeEnd(); $unit = $request->getRangeUnit(); - if ($end === null) { - $end = min(($start + 2000000 - 1), ($size - 1)); + if ($end === null || $end - $start > APP_STORAGE_READ_BUFFER) { + $end = min(($start + APP_STORAGE_READ_BUFFER - 1), ($size - 1)); } if ($unit != 'bytes' || $start >= $end || $end >= $size) { @@ -1529,6 +1521,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->setStatusCode(Response::STATUS_CODE_PARTIALCONTENT); } + $response + ->setContentType($contentType) + ->addHeader('Content-Security-Policy', 'script-src none;') + ->addHeader('X-Content-Type-Options', 'nosniff') + ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days + ->addHeader('X-Peak', \memory_get_peak_usage()); + $source = ''; if (!empty($file->getAttribute('openSSLCipher'))) { // Decrypt $source = $deviceForFiles->read($path); diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md index 1a9b8c2e29..f707c645e6 100644 --- a/docs/sdks/flutter/CHANGELOG.md +++ b/docs/sdks/flutter/CHANGELOG.md @@ -1,11 +1,9 @@ # Change Log -## 17.0.0 +## 16.1.1 * Update `flutter_web_auth_2` dependency to version 4.1.0 * Update `auth.html` example in README.md to align with `flutter_web_auth_2` documentation -* Breaking changes: - * Minimum iOS version supported is now 17.4 due to the updated requirements of `flutter_web_auth_2` version 4.1.0 ## 16.1.0 diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 286ffe45cb..28c77c1832 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -79,16 +79,16 @@ abstract class ScheduleBase extends Action // start with "0" to load all active documents. $lastSyncUpdate = "0"; - $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); Console::success("Starting timers at " . DateTime::now()); /** * The timer synchronize $schedules copy with database collection. */ - Timer::tick(static::UPDATE_TIMER * 1000, function () use ($pools, $dbForPlatform, $getProjectDB, &$lastSyncUpdate) { + Timer::tick(static::UPDATE_TIMER * 1000, function () use ($dbForPlatform, $getProjectDB, &$lastSyncUpdate) { $time = DateTime::now(); Console::log("Sync tick: Running at $time"); - $this->collectSchedules($pools, $dbForPlatform, $getProjectDB, $lastSyncUpdate); + $this->collectSchedules($dbForPlatform, $getProjectDB, $lastSyncUpdate); }); while (true) { @@ -103,7 +103,7 @@ abstract class ScheduleBase extends Action } } - private function collectSchedules(Group $pools, Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void + private function collectSchedules(Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void { // If we haven't synced yet, load all active schedules $initialLoad = $lastSyncUpdate === "0"; @@ -115,7 +115,7 @@ abstract class ScheduleBase extends Action * @throws Exception * @var Document $schedule */ - $getSchedule = function (Document $schedule) use ($pools, $dbForPlatform, $getProjectDB): array { + $getSchedule = function (Document $schedule) use ($dbForPlatform, $getProjectDB): array { $project = $dbForPlatform->getDocument('projects', $schedule->getAttribute('projectId')); $resource = $getProjectDB($project)->getDocument( diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index 19e068107a..7812b27832 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -76,7 +76,7 @@ class ScheduleFunctions extends ScheduleBase } foreach ($delayedExecutions as $delay => $schedules) { - \go(function () use ($delay, $schedules, $pools, $dbForPlatform) { + \go(function () use ($delay, $schedules, $dbForPlatform) { \sleep($delay); // in seconds foreach ($schedules as $delayConfig) { From 36bc41a748a03f3820d514d9064edd4cc1b4bad4 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 14:34:21 +0530 Subject: [PATCH 59/75] reset: stuff on target branch [missed]. --- src/Appwrite/Platform/Tasks/ScheduleMessages.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index 5e65f7a8a6..d23e3de575 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -40,7 +40,7 @@ class ScheduleMessages extends ScheduleBase continue; } - \go(function () use ($schedule, $scheduledAt, $pools, $dbForPlatform) { + \go(function () use ($schedule, $scheduledAt, $dbForPlatform) { $queueForMessaging = new Messaging($this->publisher); $this->updateProjectAccess($schedule['project'], $dbForPlatform); From 1f5d2b0ec61a09fa8a91bd420228dae67cb9310b Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Fri, 30 May 2025 22:08:04 +1200 Subject: [PATCH 60/75] Update queue --- composer.json | 2 +- composer.lock | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 833f1a462b..b7f7809219 100644 --- a/composer.json +++ b/composer.json @@ -67,7 +67,7 @@ "utopia-php/platform": "0.7.*", "utopia-php/pools": "0.8.*", "utopia-php/preloader": "0.2.*", - "utopia-php/queue": "0.10.*", + "utopia-php/queue": "0.11.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", "utopia-php/swoole": "0.8.*", diff --git a/composer.lock b/composer.lock index 8ecfcf6a18..b7b1f23545 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": "de0a0fb794f826fcc412c788185b69f4", + "content-hash": "3230eea9e592f0b712e78c1ef5f5e244", "packages": [ { "name": "adhocore/jwt", @@ -4109,16 +4109,16 @@ }, { "name": "utopia-php/platform", - "version": "0.7.7", + "version": "0.7.8", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "8c43cd866148a7c4c495e3401268429e338004b3" + "reference": "e3a4536c46f10988b1a446ec6b8dd8a9914be854" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/8c43cd866148a7c4c495e3401268429e338004b3", - "reference": "8c43cd866148a7c4c495e3401268429e338004b3", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/e3a4536c46f10988b1a446ec6b8dd8a9914be854", + "reference": "e3a4536c46f10988b1a446ec6b8dd8a9914be854", "shasum": "" }, "require": { @@ -4127,7 +4127,7 @@ "php": ">=8.0", "utopia-php/cli": "0.15.*", "utopia-php/framework": "0.33.*", - "utopia-php/queue": "0.10.*" + "utopia-php/queue": "0.11.*" }, "require-dev": { "laravel/pint": "1.*", @@ -4153,9 +4153,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.7.7" + "source": "https://github.com/utopia-php/platform/tree/0.7.8" }, - "time": "2025-05-20T09:23:44+00:00" + "time": "2025-05-30T10:05:43+00:00" }, { "name": "utopia-php/pools", @@ -4264,16 +4264,16 @@ }, { "name": "utopia-php/queue", - "version": "0.10.0", + "version": "0.11.0", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "0eccc559168ea72241c39a4c482d868314666be1" + "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/0eccc559168ea72241c39a4c482d868314666be1", - "reference": "0eccc559168ea72241c39a4c482d868314666be1", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", + "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", "shasum": "" }, "require": { @@ -4324,9 +4324,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.10.0" + "source": "https://github.com/utopia-php/queue/tree/0.11.0" }, - "time": "2025-04-17T12:15:52+00:00" + "time": "2025-05-30T09:52:38+00:00" }, { "name": "utopia-php/registry", From 8d5d9dc463c4995fba597bb7f7f0d0b3edc268d1 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Mon, 14 Apr 2025 12:17:12 +0200 Subject: [PATCH 61/75] chore: use exec to replace /bin/sh shell with the actual program --- bin/doctor | 2 +- bin/install | 2 +- bin/maintenance | 2 +- bin/migrate | 2 +- bin/queue-count-failed | 2 +- bin/queue-count-processing | 2 +- bin/queue-count-success | 2 +- bin/queue-retry | 2 +- bin/realtime | 2 +- bin/schedule-executions | 2 +- bin/schedule-functions | 2 +- bin/schedule-messages | 2 +- bin/sdks | 2 +- bin/specs | 2 +- bin/ssl | 2 +- bin/stats-resources | 2 +- bin/test | 2 +- bin/upgrade | 2 +- bin/vars | 2 +- bin/worker-audits | 2 +- bin/worker-builds | 2 +- bin/worker-certificates | 2 +- bin/worker-databases | 2 +- bin/worker-deletes | 2 +- bin/worker-functions | 2 +- bin/worker-mails | 2 +- bin/worker-messaging | 2 +- bin/worker-migrations | 2 +- bin/worker-stats-resources | 2 +- bin/worker-stats-usage | 2 +- bin/worker-webhooks | 2 +- 31 files changed, 31 insertions(+), 31 deletions(-) diff --git a/bin/doctor b/bin/doctor index b2a4547156..92b3cf6bf8 100755 --- a/bin/doctor +++ b/bin/doctor @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php doctor $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php doctor $@ diff --git a/bin/install b/bin/install index e669e91e6b..126d5373bf 100755 --- a/bin/install +++ b/bin/install @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php install $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php install $@ diff --git a/bin/maintenance b/bin/maintenance index 099551cb32..70273feb61 100644 --- a/bin/maintenance +++ b/bin/maintenance @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php maintenance $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php maintenance $@ diff --git a/bin/migrate b/bin/migrate index 28ebbd19e7..32bf7ee2f4 100755 --- a/bin/migrate +++ b/bin/migrate @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php migrate $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php migrate $@ diff --git a/bin/queue-count-failed b/bin/queue-count-failed index ca8f2b4291..93a6b3136c 100644 --- a/bin/queue-count-failed +++ b/bin/queue-count-failed @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php queue-count --type=failed $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php queue-count --type=failed $@ diff --git a/bin/queue-count-processing b/bin/queue-count-processing index 325d86111d..18e89664bd 100644 --- a/bin/queue-count-processing +++ b/bin/queue-count-processing @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php queue-count --type=processing $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php queue-count --type=processing $@ diff --git a/bin/queue-count-success b/bin/queue-count-success index 34fc54b4c1..b38bfa2159 100644 --- a/bin/queue-count-success +++ b/bin/queue-count-success @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php queue-count --type=success $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php queue-count --type=success $@ diff --git a/bin/queue-retry b/bin/queue-retry index f9473e6b07..2224a66b3b 100644 --- a/bin/queue-retry +++ b/bin/queue-retry @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php queue-retry $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php queue-retry $@ diff --git a/bin/realtime b/bin/realtime index e43dc269e0..debd4baf2a 100644 --- a/bin/realtime +++ b/bin/realtime @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/realtime.php $@ \ No newline at end of file +exec php /usr/src/code/app/realtime.php $@ diff --git a/bin/schedule-executions b/bin/schedule-executions index f239cad206..5d503e374c 100644 --- a/bin/schedule-executions +++ b/bin/schedule-executions @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php schedule-executions $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php schedule-executions $@ diff --git a/bin/schedule-functions b/bin/schedule-functions index 10edbe8226..beca1a0420 100644 --- a/bin/schedule-functions +++ b/bin/schedule-functions @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php schedule-functions $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php schedule-functions $@ diff --git a/bin/schedule-messages b/bin/schedule-messages index fa7219f6ea..3f17a279b5 100644 --- a/bin/schedule-messages +++ b/bin/schedule-messages @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php schedule-messages $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php schedule-messages $@ diff --git a/bin/sdks b/bin/sdks index ab73414829..3180813ea1 100644 --- a/bin/sdks +++ b/bin/sdks @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php sdks $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php sdks $@ diff --git a/bin/specs b/bin/specs index e77d1487d4..52875a1675 100644 --- a/bin/specs +++ b/bin/specs @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php specs $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php specs $@ diff --git a/bin/ssl b/bin/ssl index 83dcf6a026..0cc12375d0 100755 --- a/bin/ssl +++ b/bin/ssl @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php ssl $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php ssl $@ diff --git a/bin/stats-resources b/bin/stats-resources index 3104bab896..9cc67fb4a6 100644 --- a/bin/stats-resources +++ b/bin/stats-resources @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php stats-resources $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php stats-resources $@ diff --git a/bin/test b/bin/test index a2153fc536..c3b0d9b74c 100755 --- a/bin/test +++ b/bin/test @@ -1,3 +1,3 @@ #!/bin/sh -/usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@ \ No newline at end of file +exec /usr/src/code/vendor/bin/phpunit --configuration /usr/src/code/phpunit.xml $@ diff --git a/bin/upgrade b/bin/upgrade index ce32b9ca30..fd1f35b65a 100755 --- a/bin/upgrade +++ b/bin/upgrade @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php upgrade $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php upgrade $@ diff --git a/bin/vars b/bin/vars index 19e3f1ebf2..238d004675 100644 --- a/bin/vars +++ b/bin/vars @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php vars $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php vars $@ diff --git a/bin/worker-audits b/bin/worker-audits index 3df65d65e8..9bf81b93e2 100644 --- a/bin/worker-audits +++ b/bin/worker-audits @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php audits $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php audits $@ diff --git a/bin/worker-builds b/bin/worker-builds index 3400111cb5..7ddf5792de 100644 --- a/bin/worker-builds +++ b/bin/worker-builds @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php builds $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php builds $@ diff --git a/bin/worker-certificates b/bin/worker-certificates index 901688c4c8..958627bc33 100755 --- a/bin/worker-certificates +++ b/bin/worker-certificates @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php certificates $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php certificates $@ diff --git a/bin/worker-databases b/bin/worker-databases index 61e09aa9f1..235c16927c 100644 --- a/bin/worker-databases +++ b/bin/worker-databases @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php databases $@ +exec php /usr/src/code/app/worker.php databases $@ diff --git a/bin/worker-deletes b/bin/worker-deletes index 7c9793e6cb..c9711a4e66 100644 --- a/bin/worker-deletes +++ b/bin/worker-deletes @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php deletes $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php deletes $@ diff --git a/bin/worker-functions b/bin/worker-functions index 4757b1b72a..e82506d0e2 100644 --- a/bin/worker-functions +++ b/bin/worker-functions @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php functions $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php functions $@ diff --git a/bin/worker-mails b/bin/worker-mails index fee8a96da7..ffb4f7ea77 100644 --- a/bin/worker-mails +++ b/bin/worker-mails @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php mails $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php mails $@ diff --git a/bin/worker-messaging b/bin/worker-messaging index e6edf80f06..6f39348419 100644 --- a/bin/worker-messaging +++ b/bin/worker-messaging @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php messaging $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php messaging $@ diff --git a/bin/worker-migrations b/bin/worker-migrations index 32d4aef468..2728d9d22c 100644 --- a/bin/worker-migrations +++ b/bin/worker-migrations @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php migrations $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php migrations $@ diff --git a/bin/worker-stats-resources b/bin/worker-stats-resources index 9c5d2bebff..70bfacbe52 100644 --- a/bin/worker-stats-resources +++ b/bin/worker-stats-resources @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php stats-resources $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php stats-resources $@ diff --git a/bin/worker-stats-usage b/bin/worker-stats-usage index 2c267d805e..e6dd849a48 100644 --- a/bin/worker-stats-usage +++ b/bin/worker-stats-usage @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php stats-usage $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php stats-usage $@ diff --git a/bin/worker-webhooks b/bin/worker-webhooks index 93f8027a81..63fc13e3c5 100644 --- a/bin/worker-webhooks +++ b/bin/worker-webhooks @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/worker.php webhooks $@ \ No newline at end of file +exec php /usr/src/code/app/worker.php webhooks $@ From d98c06abf2fbae4bfb7bd661aacf51cb671e9e74 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Sun, 25 May 2025 17:48:09 +0200 Subject: [PATCH 62/75] feat(worker): install stop hooks and close consumer --- app/worker.php | 13 +++++++++++-- bin/screenshot | 2 +- composer.lock | 12 ++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/app/worker.php b/app/worker.php index 597e8a9943..b5b65890ea 100644 --- a/app/worker.php +++ b/app/worker.php @@ -18,7 +18,9 @@ use Appwrite\Event\StatsUsage; use Appwrite\Event\Webhook; use Appwrite\Platform\Appwrite; use Executor\Executor; +use Swoole\Process; use Swoole\Runtime; +use Swoole\Timer; use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis; use Utopia\Cache\Adapter\Pool as CachePool; use Utopia\Cache\Adapter\Sharding; @@ -480,8 +482,15 @@ $worker }); $worker->workerStart() - ->action(function () use ($workerName) { - Console::info("Worker $workerName started"); + ->action(function () use ($worker, $workerName) { + Console::info("Worker $workerName started"); + + Process::signal(SIGTERM, function () use ($worker, $workerName) { + Console::info("Stopping worker $workerName."); + + $worker->stop(); + Timer::clearAll(); + }); }); $worker->start(); diff --git a/bin/screenshot b/bin/screenshot index 4d8ceb998f..aef15eb96f 100755 --- a/bin/screenshot +++ b/bin/screenshot @@ -1,3 +1,3 @@ #!/bin/sh -php /usr/src/code/app/cli.php screenshot $@ \ No newline at end of file +exec php /usr/src/code/app/cli.php screenshot $@ \ No newline at end of file diff --git a/composer.lock b/composer.lock index b7b1f23545..8603361673 100644 --- a/composer.lock +++ b/composer.lock @@ -4264,16 +4264,16 @@ }, { "name": "utopia-php/queue", - "version": "0.11.0", + "version": "0.11.1", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5" + "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", - "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/498bbbef418b1db71b51e1bb62f5d1d752ddd8d6", + "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6", "shasum": "" }, "require": { @@ -4324,9 +4324,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.11.0" + "source": "https://github.com/utopia-php/queue/tree/0.11.1" }, - "time": "2025-05-30T09:52:38+00:00" + "time": "2025-05-30T11:50:34+00:00" }, { "name": "utopia-php/registry", From e1ee9ba89e756e2ae4985a8d18ea7095e5f0fb77 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 18:04:57 +0530 Subject: [PATCH 63/75] fix: logic. --- app/controllers/api/teams.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index ede61115e2..7e52b16911 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1359,10 +1359,12 @@ App::delete('/v1/teams/:teamId/memberships/:membershipId') max: 2 ); - // Is the deletion being requested by the user on their own membership? - $isCurrentUserAnOwner = $user->getInternalId() === $membership->getAttribute('userInternalId'); + // Is the deletion being requested by the user on their own membership and they are also the owner? + $isSelfOwner = + in_array('owner', $membership->getAttribute('roles')) && + $membership->getAttribute('userInternalId') === $user->getInternalId(); - if ($ownersCount === 1 && $isCurrentUserAnOwner) { + if ($ownersCount === 1 && $isSelfOwner) { /* Prevent removal if the user is the only owner. */ throw new Exception(Exception::MEMBERSHIP_DELETION_PROHIBITED, 'There must be at least one owner in the organization.'); } From 67cb3aad2f505946cb649c27f8ee79503fd40e32 Mon Sep 17 00:00:00 2001 From: Darshan Date: Fri, 30 May 2025 18:05:03 +0530 Subject: [PATCH 64/75] fix: test. --- tests/e2e/Services/Teams/TeamsConsoleClientTest.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index dda7f8e4ae..7949761d7f 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -212,9 +212,6 @@ class TeamsConsoleClientTest extends Scope $this->assertEquals(401, $response['headers']['status-code']); $this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']); - /** - * Test for when a user other than the owner tries to delete their membership - */ $response = $this->client->call(Client::METHOD_DELETE, '/teams/' . $teamUid . '/memberships/' . $membershipUid, [ 'origin' => 'http://localhost', 'content-type' => 'application/json', @@ -222,7 +219,7 @@ class TeamsConsoleClientTest extends Scope 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, ]); - $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals(204, $response['headers']['status-code']); $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ 'content-type' => 'application/json', @@ -230,7 +227,7 @@ class TeamsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(3, $response['body']['total']); + $this->assertEquals(2, $response['body']['total']); /** * Test for when the owner tries to delete their membership From 8716ef98ca5581f7403f7d122b4d60d366995097 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Sat, 31 May 2025 02:44:54 +1200 Subject: [PATCH 65/75] Update database for upsert fix --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index b7b1f23545..729174e86a 100644 --- a/composer.lock +++ b/composer.lock @@ -3503,16 +3503,16 @@ }, { "name": "utopia-php/database", - "version": "0.69.6", + "version": "0.69.7", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "42bfc0d87de4ade26cfd9915aaad84912761466b" + "reference": "3db51ec544b3f287511209e34bab3f5ec85fa56e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/42bfc0d87de4ade26cfd9915aaad84912761466b", - "reference": "42bfc0d87de4ade26cfd9915aaad84912761466b", + "url": "https://api.github.com/repos/utopia-php/database/zipball/3db51ec544b3f287511209e34bab3f5ec85fa56e", + "reference": "3db51ec544b3f287511209e34bab3f5ec85fa56e", "shasum": "" }, "require": { @@ -3553,9 +3553,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.69.6" + "source": "https://github.com/utopia-php/database/tree/0.69.7" }, - "time": "2025-05-29T10:36:03+00:00" + "time": "2025-05-30T14:41:25+00:00" }, { "name": "utopia-php/detector", @@ -4264,16 +4264,16 @@ }, { "name": "utopia-php/queue", - "version": "0.11.0", + "version": "0.11.1", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5" + "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", - "reference": "06b5ced0eaed2ecc6aab6d8e1b4d96bff37a1ce5", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/498bbbef418b1db71b51e1bb62f5d1d752ddd8d6", + "reference": "498bbbef418b1db71b51e1bb62f5d1d752ddd8d6", "shasum": "" }, "require": { @@ -4324,9 +4324,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.11.0" + "source": "https://github.com/utopia-php/queue/tree/0.11.1" }, - "time": "2025-05-30T09:52:38+00:00" + "time": "2025-05-30T11:50:34+00:00" }, { "name": "utopia-php/registry", From 0ac6decc99829b09cc93a9d50cbe3587477face4 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Mon, 2 Jun 2025 14:04:03 +0530 Subject: [PATCH 66/75] Fix github comments and deployment creation on branch deletion --- app/controllers/api/vcs.php | 5 +- composer.lock | 108 +++++++++++++++++------------------ docker-compose.yml | 2 +- src/Appwrite/Vcs/Comment.php | 16 ++++-- 4 files changed, 66 insertions(+), 65 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index 588ca417cf..c8a0a36a85 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -1215,6 +1215,7 @@ App::post('/v1/vcs/github/events') if ($event == $github::EVENT_PUSH) { $providerBranchCreated = $parsedPayload["branchCreated"] ?? false; + $providerBranchDeleted = $parsedPayload["branchDeleted"] ?? false; $providerBranch = $parsedPayload["branch"] ?? ''; $providerBranchUrl = $parsedPayload["branchUrl"] ?? ''; $providerRepositoryId = $parsedPayload["repositoryId"] ?? ''; @@ -1236,8 +1237,8 @@ App::post('/v1/vcs/github/events') Query::limit(100), ])); - // create new deployment only on push and not when branch is created - if (!$providerBranchCreated) { + // create new deployment only on push and not when branch is created or deleted + if (!$providerBranchCreated && !$providerBranchDeleted) { $createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $queueForBuilds, $getProjectDB, $request); } } elseif ($event == $github::EVENT_INSTALLATION) { diff --git a/composer.lock b/composer.lock index 729174e86a..8c8bcc0a6e 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": "3230eea9e592f0b712e78c1ef5f5e244", + "content-hash": "d1e8bc951ce7d70a3254381a9f639971", "packages": [ { "name": "adhocore/jwt", @@ -283,16 +283,16 @@ }, { "name": "brick/math", - "version": "0.12.3", + "version": "0.13.1", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" + "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", + "url": "https://api.github.com/repos/brick/math/zipball/fc7ed316430118cc7836bf45faff18d5dfc8de04", + "reference": "fc7ed316430118cc7836bf45faff18d5dfc8de04", "shasum": "" }, "require": { @@ -331,7 +331,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.12.3" + "source": "https://github.com/brick/math/tree/0.13.1" }, "funding": [ { @@ -339,7 +339,7 @@ "type": "github" } ], - "time": "2025-02-28T13:11:00+00:00" + "time": "2025-03-29T13:50:30+00:00" }, { "name": "chillerlan/php-qrcode", @@ -2323,20 +2323,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.6", + "version": "4.8.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "91039bc1faa45ba123c4328958e620d382ec7088" + "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", - "reference": "91039bc1faa45ba123c4328958e620d382ec7088", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", + "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -2345,26 +2345,23 @@ "rhumsaa/uuid": "self.version" }, "require-dev": { - "captainhook/captainhook": "^5.10", + "captainhook/captainhook": "^5.25", "captainhook/plugin-composer": "^5.3", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", - "doctrine/annotations": "^1.8", - "ergebnis/composer-normalize": "^2.15", - "mockery/mockery": "^1.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", "paragonie/random-lib": "^2", - "php-mock/php-mock": "^2.2", - "php-mock/php-mock-mockery": "^1.3", - "php-parallel-lint/php-parallel-lint": "^1.1", - "phpbench/phpbench": "^1.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^8.5 || ^9", - "ramsey/composer-repl": "^1.4", - "slevomat/coding-standard": "^8.4", - "squizlabs/php_codesniffer": "^3.5", - "vimeo/psalm": "^4.9" + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" }, "suggest": { "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", @@ -2399,19 +2396,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.6" + "source": "https://github.com/ramsey/uuid/tree/4.8.1" }, - "funding": [ - { - "url": "https://github.com/ramsey", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", - "type": "tidelift" - } - ], - "time": "2024-04-27T21:32:50+00:00" + "time": "2025-06-01T06:28:46+00:00" }, { "name": "spomky-labs/otphp", @@ -4597,16 +4584,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.10.2", + "version": "dev-feat-check-deleted-attribute-on-push", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "1f9823ebcb8fd098607de0074f18f48e28985012" + "reference": "ba43fd0e797a61c92197885413b650aed6a45577" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/1f9823ebcb8fd098607de0074f18f48e28985012", - "reference": "1f9823ebcb8fd098607de0074f18f48e28985012", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/ba43fd0e797a61c92197885413b650aed6a45577", + "reference": "ba43fd0e797a61c92197885413b650aed6a45577", "shasum": "" }, "require": { @@ -4640,9 +4627,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.10.2" + "source": "https://github.com/utopia-php/vcs/tree/feat-check-deleted-attribute-on-push" }, - "time": "2025-04-17T04:35:25+00:00" + "time": "2025-06-02T08:03:56+00:00" }, { "name": "utopia-php/websocket", @@ -5344,16 +5331,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.4.0", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", - "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { @@ -5396,9 +5383,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-12-30T11:07:19+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", @@ -8245,9 +8232,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/vcs", + "version": "dev-feat-check-deleted-attribute-on-push", + "alias": "0.10.99", + "alias_normalized": "0.10.99.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/vcs": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/docker-compose.yml b/docker-compose.yml index cefd082c2f..29a43aca91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -213,7 +213,7 @@ services: appwrite-console: <<: *x-logging container_name: appwrite-console - image: appwrite/console:6.0.13 + image: appwrite/console:6.0.32 restart: unless-stopped networks: - appwrite diff --git a/src/Appwrite/Vcs/Comment.php b/src/Appwrite/Vcs/Comment.php index 7c550ad528..3fc4e287f8 100644 --- a/src/Appwrite/Vcs/Comment.php +++ b/src/Appwrite/Vcs/Comment.php @@ -105,8 +105,10 @@ class Comment foreach ($project['site'] as $siteId => $site) { $extension = $site['status'] === 'building' ? 'gif' : 'png'; - $pathLight = '/images/vcs/status-' . $site['status'] . '-light.' . $extension; - $pathDark = '/images/vcs/status-' . $site['status'] . '-dark.' . $extension; + $imageStatus = in_array($site['status'], ['processing', 'building']) ? 'building' : $site['status']; + + $pathLight = '/images/vcs/status-' . $imageStatus . '-light.' . $extension; + $pathDark = '/images/vcs/status-' . $imageStatus . '-dark.' . $extension; $status = match ($site['status']) { 'waiting' => $this->generatImage($pathLight, $pathDark, 'Queued', 85) . ' _Queued_', @@ -149,10 +151,11 @@ class Comment $text .= "| :- | :- | :- | :- |\n"; foreach ($project['function'] as $functionId => $function) { - $extension = $function['status'] === 'building' ? 'gif' : 'png'; + $imageStatus = in_array($function['status'], ['processing', 'building']) ? 'building' : $function['status']; + $extension = $imageStatus === 'building' ? 'gif' : 'png'; - $pathLight = '/images/vcs/status-' . $function['status'] . '-light.' . $extension; - $pathDark = '/images/vcs/status-' . $function['status'] . '-dark.' . $extension; + $pathLight = '/images/vcs/status-' . $imageStatus . '-light.' . $extension; + $pathDark = '/images/vcs/status-' . $imageStatus . '-dark.' . $extension; $status = match ($function['status']) { 'waiting' => $this->generatImage($pathLight, $pathDark, 'Queued', 85) . ' _Queued_', @@ -168,7 +171,8 @@ class Comment $action = '[Authorize](' . $function['action']['url'] . ')'; } - $text .= "|  **{$function['name']}**
`$functionId`"; + $text .= "|  **{$function['name']}**"; + $text .= "| `{$functionId}`"; $text .= "| {$status}"; $text .= "| {$action}"; $text .= "|\n"; From e7963e68257cca174d7eb0f04def3823e2dad534 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Mon, 2 Jun 2025 14:07:53 +0530 Subject: [PATCH 67/75] Update composer.lock --- composer.lock | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index 8c8bcc0a6e..fb9db2aa20 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": "d1e8bc951ce7d70a3254381a9f639971", + "content-hash": "3230eea9e592f0b712e78c1ef5f5e244", "packages": [ { "name": "adhocore/jwt", @@ -4584,16 +4584,16 @@ }, { "name": "utopia-php/vcs", - "version": "dev-feat-check-deleted-attribute-on-push", + "version": "0.10.3", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "ba43fd0e797a61c92197885413b650aed6a45577" + "reference": "a51ca929aa8a82cc790c2df8b653d6c60cb889d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/ba43fd0e797a61c92197885413b650aed6a45577", - "reference": "ba43fd0e797a61c92197885413b650aed6a45577", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/a51ca929aa8a82cc790c2df8b653d6c60cb889d3", + "reference": "a51ca929aa8a82cc790c2df8b653d6c60cb889d3", "shasum": "" }, "require": { @@ -4627,9 +4627,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/feat-check-deleted-attribute-on-push" + "source": "https://github.com/utopia-php/vcs/tree/0.10.3" }, - "time": "2025-06-02T08:03:56+00:00" + "time": "2025-06-02T08:23:44+00:00" }, { "name": "utopia-php/websocket", @@ -8232,18 +8232,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/vcs", - "version": "dev-feat-check-deleted-attribute-on-push", - "alias": "0.10.99", - "alias_normalized": "0.10.99.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/vcs": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From 288f3b2cc83083241f359f1aab0a0af32fc0d789 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Mon, 2 Jun 2025 14:12:25 +0530 Subject: [PATCH 68/75] Fix order --- src/Appwrite/Vcs/Comment.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Vcs/Comment.php b/src/Appwrite/Vcs/Comment.php index 3fc4e287f8..d1d50c2ffd 100644 --- a/src/Appwrite/Vcs/Comment.php +++ b/src/Appwrite/Vcs/Comment.php @@ -103,10 +103,10 @@ class Comment $text .= "| :- | :- | :- | :- | :- |\n"; foreach ($project['site'] as $siteId => $site) { - $extension = $site['status'] === 'building' ? 'gif' : 'png'; - $imageStatus = in_array($site['status'], ['processing', 'building']) ? 'building' : $site['status']; + $extension = $site['status'] === 'building' ? 'gif' : 'png'; + $pathLight = '/images/vcs/status-' . $imageStatus . '-light.' . $extension; $pathDark = '/images/vcs/status-' . $imageStatus . '-dark.' . $extension; From 7049a58f212b1a7a8b277905855244bee82cf634 Mon Sep 17 00:00:00 2001 From: Khushboo Verma Date: Mon, 2 Jun 2025 15:06:00 +0530 Subject: [PATCH 69/75] Update composer.lock --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index fb9db2aa20..9e757f9db8 100644 --- a/composer.lock +++ b/composer.lock @@ -4584,16 +4584,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.10.3", + "version": "0.10.4", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "a51ca929aa8a82cc790c2df8b653d6c60cb889d3" + "reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/a51ca929aa8a82cc790c2df8b653d6c60cb889d3", - "reference": "a51ca929aa8a82cc790c2df8b653d6c60cb889d3", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/f635b368909eb3c3fe57344fe43525e74e8fdc03", + "reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03", "shasum": "" }, "require": { @@ -4627,9 +4627,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.10.3" + "source": "https://github.com/utopia-php/vcs/tree/0.10.4" }, - "time": "2025-06-02T08:23:44+00:00" + "time": "2025-06-02T09:18:36+00:00" }, { "name": "utopia-php/websocket", From c92a14d31805b693de8046dc06bfb6f368c8b80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 2 Jun 2025 12:47:13 +0200 Subject: [PATCH 70/75] Simplify router redirect --- app/controllers/general.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index bff701792e..5beac9e1e8 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -749,12 +749,6 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw return false; } elseif ($type === 'redirect') { $url = $rule->getAttribute('redirectUrl', ''); - - $query = ($swooleRequest->server['query_string'] ?? ''); - if (!empty($query)) { - $url .= '?' . $query; - } - $response->redirect($url, \intval($rule->getAttribute('redirectStatusCode', 301))); return true; } else { From c449144926aa6280f358be9a56ac16e628f626d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 2 Jun 2025 17:56:13 +0200 Subject: [PATCH 71/75] Fix flaky usage tests --- tests/e2e/General/UsageTest.php | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 5549ef800d..f0bb32156d 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -183,9 +183,11 @@ class UsageTest extends Scope /** * @depends testPrepareUsersStats */ - #[Retry(count: 1)] + #[Retry(count: 10)] public function testUsersStats(array $data): array { + \sleep(1); // To prevent all 10 retries from running instantly + $requestsTotal = $data['requestsTotal']; $response = $this->client->call( @@ -362,6 +364,8 @@ class UsageTest extends Scope #[Retry(count: 10)] public function testStorageStats(array $data): array { + \sleep(1); // To prevent all 10 retries from running instantly + $bucketId = $data['bucketId']; $bucketsTotal = $data['bucketsTotal']; $requestsTotal = $data['requestsTotal']; @@ -577,9 +581,11 @@ class UsageTest extends Scope } /** @depends testPrepareDatabaseStats */ - #[Retry(count: 1)] + #[Retry(count: 10)] public function testDatabaseStats(array $data): array { + \sleep(1); // To prevent all 10 retries from running instantly + $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; $requestsTotal = $data['requestsTotal']; @@ -799,9 +805,11 @@ class UsageTest extends Scope } /** @depends testPrepareFunctionsStats */ - #[Retry(count: 1)] + #[Retry(count: 10)] public function testFunctionsStats(array $data): array { + \sleep(1); // To prevent all 10 retries from running instantly + $functionId = $data['functionId']; $executionTime = $data['executionTime']; $executions = $data['executions']; @@ -927,9 +935,11 @@ class UsageTest extends Scope } /** @depends testPrepareSitesStats */ - #[Retry(count: 1)] + #[Retry(count: 10)] public function testSitesStats(array $data) { + \sleep(1); // To prevent all 10 retries from running instantly + $siteId = $data['siteId']; $executionTime = $data['executionTime'] ?? 0; $executions = $data['executions'] ?? 0; From 854304dd1643a1763b44a31b65aaab099078bc0c Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 2 Jun 2025 17:09:03 +0100 Subject: [PATCH 72/75] tests: fix flaky account tests commit-id:3865765d --- tests/e2e/Scopes/Scope.php | 14 +++++++++ .../Account/AccountCustomClientTest.php | 30 ++++++++----------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index 6deaa62c05..2fa6416bf7 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -2,6 +2,7 @@ namespace Tests\E2E\Scopes; +use Appwrite\Tests\Async; use Appwrite\Tests\Retryable; use PHPUnit\Framework\TestCase; use Tests\E2E\Client; @@ -10,6 +11,7 @@ use Utopia\Database\Helpers\ID; abstract class Scope extends TestCase { use Retryable; + use Async; protected ?Client $client = null; protected string $endpoint = 'http://localhost/v1'; @@ -43,6 +45,18 @@ abstract class Scope extends TestCase return []; } + protected function assertLastRequest(callable $probe, $timeoutMs = 20_000, $waitMs = 500): array + { + $this->assertEventually(function () use (&$request, $probe) { + $request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true); + $request['data'] = json_decode($request['data'], true); + + call_user_func($probe, $request); + }, $timeoutMs, $waitMs); + + return $request; + } + protected function getLastRequest(): array { sleep(2); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 452b725c11..0cc2eb893a 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -2034,7 +2034,6 @@ class AccountCustomClientTest extends Scope $this->assertEquals($response['body']['users'][0]['email'], $email); } - #[Retry(count: 2)] public function testCreatePhone(): array { $number = '+123456789'; @@ -2058,17 +2057,15 @@ class AccountCustomClientTest extends Scope $userId = $response['body']['userId']; - \sleep(7); - - $smsRequest = $this->getLastRequest(); - - $this->assertEquals('http://request-catcher:5000/mock-sms', $smsRequest['url']); - $this->assertEquals('Appwrite Mock Message Sender', $smsRequest['headers']['User-Agent']); - $this->assertEquals('username', $smsRequest['headers']['X-Username']); - $this->assertEquals('password', $smsRequest['headers']['X-Key']); - $this->assertEquals('POST', $smsRequest['method']); - $this->assertEquals('+123456789', $smsRequest['data']['from']); - $this->assertEquals($number, $smsRequest['data']['to']); + $smsRequest = $this->assertLastRequest(function (array $request) use ($number) { + $this->assertEquals('http://request-catcher:5000/mock-sms', $request['url']); + $this->assertEquals('Appwrite Mock Message Sender', $request['headers']['User-Agent']); + $this->assertEquals('username', $request['headers']['X-Username']); + $this->assertEquals('password', $request['headers']['X-Key']); + $this->assertEquals('POST', $request['method']); + $this->assertEquals('+123456789', $request['data']['from']); + $this->assertEquals($number, $request['data']['to']); + }); $data['token'] = $smsRequest['data']['message']; $data['id'] = $userId; @@ -2396,7 +2393,6 @@ class AccountCustomClientTest extends Scope /** * @depends testUpdatePhone */ - #[Retry(count: 3)] public function testPhoneVerification(array $data): array { $session = $data['session'] ?? ''; @@ -2416,10 +2412,10 @@ class AccountCustomClientTest extends Scope $this->assertEmpty($response['body']['secret']); $this->assertTrue((new DatetimeValidator())->isValid($response['body']['expire'])); - $smsRequest = $this->getLastRequest(); - - $message = $smsRequest['data']['message']; - $token = substr($message, 0, 6); + $smsRequest = $this->assertLastRequest(function ($request) { + $this->assertArrayHasKey('data', $request); + $this->assertArrayHasKey('message', $request['data']); + }); /** * Test for FAILURE From b9579c8922eede87d5a398af5392a0321ba2be9c Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:36:48 +0100 Subject: [PATCH 73/75] tests: fix flaky messaging test commit-id:336a4f07 --- .../Messaging/MessagingConsoleClientTest.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php index 245eb3e8de..49d13128e2 100644 --- a/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php +++ b/tests/e2e/Services/Messaging/MessagingConsoleClientTest.php @@ -206,15 +206,17 @@ class MessagingConsoleClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); - $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + $this->assertEventually(function () use ($topic) { + $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); - $this->assertEquals($logs['headers']['status-code'], 200); - $this->assertIsArray($logs['body']['logs']); - $this->assertCount(2, $logs['body']['logs']); - $this->assertIsNumeric($logs['body']['total']); + $this->assertEquals($logs['headers']['status-code'], 200); + $this->assertIsArray($logs['body']['logs']); + $this->assertCount(2, $logs['body']['logs']); + $this->assertIsNumeric($logs['body']['total']); + }); $logs = $this->client->call(Client::METHOD_GET, '/messaging/topics/' . $topic['body']['$id'] . '/logs', \array_merge([ 'content-type' => 'application/json', From c19d123d48f0f83353845e2600495287550951f0 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:20:08 +0100 Subject: [PATCH 74/75] tests: make usagetests robust commit-id:35fcc17d --- tests/e2e/General/UsageTest.php | 506 ++++++++++++++++---------------- 1 file changed, 258 insertions(+), 248 deletions(-) diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index f0bb32156d..6ff9dafada 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -3,7 +3,6 @@ namespace Tests\E2E\General; use Appwrite\Platform\Modules\Compute\Specification; -use Appwrite\Tests\Retry; use CURLFile; use DateTime; use Tests\E2E\Client; @@ -183,42 +182,43 @@ class UsageTest extends Scope /** * @depends testPrepareUsersStats */ - #[Retry(count: 10)] public function testUsersStats(array $data): array { - \sleep(1); // To prevent all 10 retries from running instantly - $requestsTotal = $data['requestsTotal']; - $response = $this->client->call( - Client::METHOD_GET, - '/project/usage', - $this->getConsoleHeaders(), - [ - 'period' => '1h', - 'startDate' => self::getToday(), - 'endDate' => self::getTomorrow(), - ] - ); + $this->assertEventually(function () { + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertGreaterThanOrEqual(31, count($response['body'])); - $this->validateDates($response['body']['network']); - $this->validateDates($response['body']['requests']); - $this->validateDates($response['body']['users']); - $this->assertArrayHasKey('executionsBreakdown', $response['body']); - $this->assertArrayHasKey('bucketsBreakdown', $response['body']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertGreaterThanOrEqual(31, count($response['body'])); + $this->validateDates($response['body']['network']); + $this->validateDates($response['body']['requests']); + $this->validateDates($response['body']['users']); + $this->assertArrayHasKey('executionsBreakdown', $response['body']); + $this->assertArrayHasKey('bucketsBreakdown', $response['body']); + }); - $response = $this->client->call( - Client::METHOD_GET, - '/users/usage?range=90d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () { + $response = $this->client->call( + Client::METHOD_GET, + '/users/usage?range=90d', + $this->getConsoleHeaders() + ); - $this->assertEquals('90d', $response['body']['range']); - $this->assertEquals(90, count($response['body']['users'])); - $this->assertEquals(90, count($response['body']['sessions'])); - $this->assertEquals((self::CREATE / 2), $response['body']['users'][array_key_last($response['body']['users'])]['value']); + $this->assertEquals('90d', $response['body']['range']); + $this->assertEquals(90, count($response['body']['users'])); + $this->assertEquals(90, count($response['body']['sessions'])); + $this->assertEquals((self::CREATE / 2), $response['body']['users'][array_key_last($response['body']['users'])]['value']); + }); return array_merge($data, [ 'requestsTotal' => $requestsTotal @@ -361,55 +361,58 @@ class UsageTest extends Scope /** * @depends testPrepareStorageStats */ - #[Retry(count: 10)] public function testStorageStats(array $data): array { - \sleep(1); // To prevent all 10 retries from running instantly - $bucketId = $data['bucketId']; $bucketsTotal = $data['bucketsTotal']; $requestsTotal = $data['requestsTotal']; $storageTotal = $data['storageTotal']; $filesTotal = $data['filesTotal']; - $response = $this->client->call( - Client::METHOD_GET, - '/project/usage', - $this->getConsoleHeaders(), - [ - 'period' => '1d', - 'startDate' => self::getToday(), - 'endDate' => self::getTomorrow(), - ] - ); + $this->assertEventually(function () use ($requestsTotal, $storageTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1d', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); - $this->assertGreaterThanOrEqual(31, count($response['body'])); - $this->assertEquals(1, count($response['body']['requests'])); - $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']); - $this->validateDates($response['body']['requests']); - $this->assertEquals($storageTotal, $response['body']['filesStorageTotal']); + $this->assertGreaterThanOrEqual(31, count($response['body'])); + $this->assertEquals(1, count($response['body']['requests'])); + $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']); + $this->validateDates($response['body']['requests']); + $this->assertEquals($storageTotal, $response['body']['filesStorageTotal']); + }); - $response = $this->client->call( - Client::METHOD_GET, - '/storage/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () use ($bucketsTotal, $filesTotal, $storageTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/storage/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']); - $this->validateDates($response['body']['storage']); - $this->assertEquals($bucketsTotal, $response['body']['buckets'][array_key_last($response['body']['buckets'])]['value']); - $this->validateDates($response['body']['buckets']); - $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']); - $this->validateDates($response['body']['files']); + $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']); + $this->validateDates($response['body']['storage']); + $this->assertEquals($bucketsTotal, $response['body']['buckets'][array_key_last($response['body']['buckets'])]['value']); + $this->validateDates($response['body']['buckets']); + $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']); + $this->validateDates($response['body']['files']); + }); - $response = $this->client->call( - Client::METHOD_GET, - '/storage/' . $bucketId . '/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () use ($bucketId, $storageTotal, $filesTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/storage/' . $bucketId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']); - $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']); + $this->assertEquals($storageTotal, $response['body']['storage'][array_key_last($response['body']['storage'])]['value']); + $this->assertEquals($filesTotal, $response['body']['files'][array_key_last($response['body']['files'])]['value']); + }); return $data; } @@ -581,11 +584,9 @@ class UsageTest extends Scope } /** @depends testPrepareDatabaseStats */ - #[Retry(count: 10)] + public function testDatabaseStats(array $data): array { - \sleep(1); // To prevent all 10 retries from running instantly - $databaseId = $data['databaseId']; $collectionId = $data['collectionId']; $requestsTotal = $data['requestsTotal']; @@ -593,60 +594,66 @@ class UsageTest extends Scope $collectionsTotal = $data['collectionsTotal']; $documentsTotal = $data['documentsTotal']; - sleep(self::WAIT); + $this->assertEventually(function () use ($requestsTotal, $databasesTotal, $documentsTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1d', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); - $response = $this->client->call( - Client::METHOD_GET, - '/project/usage', - $this->getConsoleHeaders(), - [ - 'period' => '1d', - 'startDate' => self::getToday(), - 'endDate' => self::getTomorrow(), - ] - ); + $this->assertGreaterThanOrEqual(31, count($response['body'])); + $this->assertEquals(1, count($response['body']['requests'])); + $this->assertEquals(1, count($response['body']['network'])); + $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']); + $this->validateDates($response['body']['requests']); + $this->assertEquals($databasesTotal, $response['body']['databasesTotal']); + $this->assertEquals($documentsTotal, $response['body']['documentsTotal']); + }); - $this->assertGreaterThanOrEqual(31, count($response['body'])); - $this->assertEquals(1, count($response['body']['requests'])); - $this->assertEquals(1, count($response['body']['network'])); - $this->assertEquals($requestsTotal, $response['body']['requests'][array_key_last($response['body']['requests'])]['value']); - $this->validateDates($response['body']['requests']); - $this->assertEquals($databasesTotal, $response['body']['databasesTotal']); - $this->assertEquals($documentsTotal, $response['body']['documentsTotal']); + $this->assertEventually(function () use ($collectionsTotal, $databasesTotal, $documentsTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/databases/usage?range=30d', + $this->getConsoleHeaders() + ); - $response = $this->client->call( - Client::METHOD_GET, - '/databases/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']); + $this->validateDates($response['body']['databases']); + $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']); + $this->validateDates($response['body']['collections']); + $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); + $this->validateDates($response['body']['documents']); + }); - $this->assertEquals($databasesTotal, $response['body']['databases'][array_key_last($response['body']['databases'])]['value']); - $this->validateDates($response['body']['databases']); - $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']); - $this->validateDates($response['body']['collections']); - $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); - $this->validateDates($response['body']['documents']); + $this->assertEventually(function () use ($databaseId, $collectionsTotal, $documentsTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/databases/' . $databaseId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $response = $this->client->call( - Client::METHOD_GET, - '/databases/' . $databaseId . '/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']); + $this->validateDates($response['body']['collections']); - $this->assertEquals($collectionsTotal, $response['body']['collections'][array_key_last($response['body']['collections'])]['value']); - $this->validateDates($response['body']['collections']); + $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); + $this->validateDates($response['body']['documents']); + }); - $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); - $this->validateDates($response['body']['documents']); + $this->assertEventually(function () use ($databaseId, $collectionId, $documentsTotal) { + $response = $this->client->call( + Client::METHOD_GET, + '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $response = $this->client->call( - Client::METHOD_GET, - '/databases/' . $databaseId . '/collections/' . $collectionId . '/usage?range=30d', - $this->getConsoleHeaders() - ); - - $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); - $this->validateDates($response['body']['documents']); + $this->assertEquals($documentsTotal, $response['body']['documents'][array_key_last($response['body']['documents'])]['value']); + $this->validateDates($response['body']['documents']); + }); return $data; } @@ -805,69 +812,69 @@ class UsageTest extends Scope } /** @depends testPrepareFunctionsStats */ - #[Retry(count: 10)] public function testFunctionsStats(array $data): array { - \sleep(1); // To prevent all 10 retries from running instantly - $functionId = $data['functionId']; $executionTime = $data['executionTime']; $executions = $data['executions']; - $response = $this->client->call( - Client::METHOD_GET, - '/functions/' . $functionId . '/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () use ($functionId, $executions, $executionTime) { + $response = $this->client->call( + Client::METHOD_GET, + '/functions/' . $functionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(24, count($response['body'])); - $this->assertEquals('30d', $response['body']['range']); - $this->assertIsArray($response['body']['deployments']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsNumeric($response['body']['deploymentsStorageTotal']); - $this->assertIsNumeric($response['body']['buildsMbSecondsTotal']); - $this->assertIsNumeric($response['body']['executionsMbSecondsTotal']); - $this->assertIsArray($response['body']['builds']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['buildsMbSeconds']); - $this->assertIsArray($response['body']['executions']); - $this->assertIsArray($response['body']['executionsTime']); - $this->assertIsArray($response['body']['executionsMbSeconds']); - $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); - $this->validateDates($response['body']['executions']); - $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); - $this->validateDates($response['body']['executionsTime']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(24, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + $this->assertIsArray($response['body']['deployments']); + $this->assertIsArray($response['body']['deploymentsStorage']); + $this->assertIsNumeric($response['body']['deploymentsStorageTotal']); + $this->assertIsNumeric($response['body']['buildsMbSecondsTotal']); + $this->assertIsNumeric($response['body']['executionsMbSecondsTotal']); + $this->assertIsArray($response['body']['builds']); + $this->assertIsArray($response['body']['buildsTime']); + $this->assertIsArray($response['body']['buildsMbSeconds']); + $this->assertIsArray($response['body']['executions']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['executionsMbSeconds']); + $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); + $this->validateDates($response['body']['executions']); + $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); + $this->validateDates($response['body']['executionsTime']); + }); - $response = $this->client->call( - Client::METHOD_GET, - '/functions/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () use ($executions, $executionTime) { + $response = $this->client->call( + Client::METHOD_GET, + '/functions/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(25, count($response['body'])); - $this->assertEquals($response['body']['range'], '30d'); - $this->assertIsArray($response['body']['functions']); - $this->assertIsArray($response['body']['deployments']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsArray($response['body']['builds']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['buildsMbSeconds']); - $this->assertIsArray($response['body']['executions']); - $this->assertIsArray($response['body']['executionsTime']); - $this->assertIsArray($response['body']['executionsMbSeconds']); - $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); - $this->validateDates($response['body']['executions']); - $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); - $this->validateDates($response['body']['executionsTime']); - $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']); - $this->validateDates($response['body']['buildsTime']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(25, count($response['body'])); + $this->assertEquals($response['body']['range'], '30d'); + $this->assertIsArray($response['body']['functions']); + $this->assertIsArray($response['body']['deployments']); + $this->assertIsArray($response['body']['deploymentsStorage']); + $this->assertIsArray($response['body']['builds']); + $this->assertIsArray($response['body']['buildsTime']); + $this->assertIsArray($response['body']['buildsMbSeconds']); + $this->assertIsArray($response['body']['executions']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['executionsMbSeconds']); + $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); + $this->validateDates($response['body']['executions']); + $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); + $this->validateDates($response['body']['executionsTime']); + $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']); + $this->validateDates($response['body']['buildsTime']); + }); return $data; } - public function testPrepareSitesStats(): array { $siteId = $this->setupSite([ @@ -935,77 +942,79 @@ class UsageTest extends Scope } /** @depends testPrepareSitesStats */ - #[Retry(count: 10)] public function testSitesStats(array $data) { - \sleep(1); // To prevent all 10 retries from running instantly - $siteId = $data['siteId']; $executionTime = $data['executionTime'] ?? 0; $executions = $data['executions'] ?? 0; $deploymentsSuccess = $data['deploymentsSuccess']; $deploymentsFailed = $data['deploymentsFailed']; - $response = $this->client->call( - Client::METHOD_GET, - '/sites/' . $siteId . '/usage?range=30d', - $this->getConsoleHeaders() - ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(30, count($response['body'])); - $this->assertEquals('30d', $response['body']['range']); - $this->assertIsArray($response['body']['deployments']); - $this->assertEquals($deploymentsSuccess, $response['body']['buildsSuccessTotal']); - $this->assertEquals($deploymentsFailed, $response['body']['buildsFailedTotal']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsNumeric($response['body']['deploymentsStorageTotal']); - $this->assertIsNumeric($response['body']['buildsMbSecondsTotal']); - $this->assertIsNumeric($response['body']['executionsMbSecondsTotal']); - $this->assertIsArray($response['body']['builds']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['buildsMbSeconds']); - $this->assertIsArray($response['body']['executions']); - $this->assertIsArray($response['body']['executionsTime']); - $this->assertIsArray($response['body']['executionsMbSeconds']); - $this->assertIsArray($response['body']['buildsSuccess']); - $this->assertIsArray($response['body']['buildsFailed']); - $this->assertIsArray($response['body']['requests']); - $this->assertIsArray($response['body']['inbound']); - $this->assertIsArray($response['body']['outbound']); - $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); - $this->validateDates($response['body']['executions']); - $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); - $this->validateDates($response['body']['executionsTime']); + $this->assertEventually(function () use ($siteId, $deploymentsSuccess, $deploymentsFailed, $executions, $executionTime) { + $response = $this->client->call( + Client::METHOD_GET, + '/sites/' . $siteId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $response = $this->client->call( - Client::METHOD_GET, - '/sites/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(30, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + $this->assertIsArray($response['body']['deployments']); + $this->assertEquals($deploymentsSuccess, $response['body']['buildsSuccessTotal']); + $this->assertEquals($deploymentsFailed, $response['body']['buildsFailedTotal']); + $this->assertIsArray($response['body']['deploymentsStorage']); + $this->assertIsNumeric($response['body']['deploymentsStorageTotal']); + $this->assertIsNumeric($response['body']['buildsMbSecondsTotal']); + $this->assertIsNumeric($response['body']['executionsMbSecondsTotal']); + $this->assertIsArray($response['body']['builds']); + $this->assertIsArray($response['body']['buildsTime']); + $this->assertIsArray($response['body']['buildsMbSeconds']); + $this->assertIsArray($response['body']['executions']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['executionsMbSeconds']); + $this->assertIsArray($response['body']['buildsSuccess']); + $this->assertIsArray($response['body']['buildsFailed']); + $this->assertIsArray($response['body']['requests']); + $this->assertIsArray($response['body']['inbound']); + $this->assertIsArray($response['body']['outbound']); + $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); + $this->validateDates($response['body']['executions']); + $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); + $this->validateDates($response['body']['executionsTime']); + }); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(31, count($response['body'])); - $this->assertEquals($response['body']['range'], '30d'); - $this->assertIsArray($response['body']['sites']); - $this->assertIsArray($response['body']['deployments']); - $this->assertIsArray($response['body']['deploymentsStorage']); - $this->assertIsArray($response['body']['builds']); - $this->assertIsArray($response['body']['buildsTime']); - $this->assertIsArray($response['body']['buildsMbSeconds']); - $this->assertIsArray($response['body']['executions']); - $this->assertIsArray($response['body']['executionsTime']); - $this->assertIsArray($response['body']['executionsMbSeconds']); - $this->assertIsArray($response['body']['buildsSuccess']); - $this->assertIsArray($response['body']['buildsFailed']); - $this->assertIsArray($response['body']['requests']); - $this->assertIsArray($response['body']['inbound']); - $this->assertIsArray($response['body']['outbound']); - $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); - $this->validateDates($response['body']['executions']); - $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); - $this->validateDates($response['body']['executionsTime']); - $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']); - $this->validateDates($response['body']['buildsTime']); + $this->assertEventually(function () use ($executions, $executionTime) { + $response = $this->client->call( + Client::METHOD_GET, + '/sites/usage?range=30d', + $this->getConsoleHeaders() + ); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(31, count($response['body'])); + $this->assertEquals($response['body']['range'], '30d'); + $this->assertIsArray($response['body']['sites']); + $this->assertIsArray($response['body']['deployments']); + $this->assertIsArray($response['body']['deploymentsStorage']); + $this->assertIsArray($response['body']['builds']); + $this->assertIsArray($response['body']['buildsTime']); + $this->assertIsArray($response['body']['buildsMbSeconds']); + $this->assertIsArray($response['body']['executions']); + $this->assertIsArray($response['body']['executionsTime']); + $this->assertIsArray($response['body']['executionsMbSeconds']); + $this->assertIsArray($response['body']['buildsSuccess']); + $this->assertIsArray($response['body']['buildsFailed']); + $this->assertIsArray($response['body']['requests']); + $this->assertIsArray($response['body']['inbound']); + $this->assertIsArray($response['body']['outbound']); + $this->assertEquals($executions, $response['body']['executions'][array_key_last($response['body']['executions'])]['value']); + $this->validateDates($response['body']['executions']); + $this->assertEquals($executionTime, $response['body']['executionsTime'][array_key_last($response['body']['executionsTime'])]['value']); + $this->validateDates($response['body']['executionsTime']); + $this->assertGreaterThan(0, $response['body']['buildsTime'][array_key_last($response['body']['buildsTime'])]['value']); + $this->validateDates($response['body']['buildsTime']); + }); } /** @depends testFunctionsStats */ @@ -1042,30 +1051,33 @@ class UsageTest extends Scope $domain = $rule['body']['domain']; - $response = $this->client->call( - Client::METHOD_GET, - '/functions/' . $functionId . '/usage?range=30d', - $this->getConsoleHeaders() - ); + $this->assertEventually(function () use (&$response, $functionId) { + $response = $this->client->call( + Client::METHOD_GET, + '/functions/' . $functionId . '/usage?range=30d', + $this->getConsoleHeaders() + ); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(24, count($response['body'])); - $this->assertEquals('30d', $response['body']['range']); + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(24, count($response['body'])); + $this->assertEquals('30d', $response['body']['range']); + }); $functionsMetrics = $response['body']; - $response = $this->client->call( - Client::METHOD_GET, - '/project/usage', - $this->getConsoleHeaders(), - [ - 'period' => '1h', - 'startDate' => self::getToday(), - 'endDate' => self::getTomorrow(), - ] - ); - - $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEventually(function () use (&$response) { + $response = $this->client->call( + Client::METHOD_GET, + '/project/usage', + $this->getConsoleHeaders(), + [ + 'period' => '1h', + 'startDate' => self::getToday(), + 'endDate' => self::getTomorrow(), + ] + ); + $this->assertEquals(200, $response['headers']['status-code']); + }); $projectMetrics = $response['body']; @@ -1080,8 +1092,6 @@ class UsageTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); - $tries = 0; - $this->assertEventually(function () use ($functionId, $functionsMetrics, $projectMetrics) { // Compare new values with old values $response = $this->client->call( From 71c54f5742196dd55aaa925ab6598fe34013dc14 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 2 Jun 2025 17:15:01 +0100 Subject: [PATCH 75/75] tests: increase deployment timeouts commit-id:7d7dffac --- tests/e2e/Services/Functions/FunctionsBase.php | 2 +- tests/e2e/Services/Migrations/MigrationsBase.php | 2 +- tests/e2e/Services/Sites/SitesBase.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index 475eb9b9b4..27b67d851d 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -49,7 +49,7 @@ trait FunctionsBase 'x-appwrite-key' => $this->getProject()['apiKey'], ])); $this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT)); - }, 50000, 500); + }, 100000, 500); // Not === so multipart/form-data works fine too if (($params['activate'] ?? false) == true) { diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index c241b38e3d..b8b9439e64 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -871,7 +871,7 @@ trait MigrationsBase $this->assertEquals(1, $deployments['body']['total']); $this->assertEquals('ready', $deployments['body']['deployments'][0]['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployments['body']['deployments'][0], JSON_PRETTY_PRINT)); - }, 50000, 500); + }, 100000, 500); // Attempt execution $execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', [ diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index 00edcc1b72..2054744863 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -265,7 +265,7 @@ trait SitesBase $this->assertEventually(function () use ($siteId, $deploymentId) { $deployment = $this->getDeployment($siteId, $deploymentId); $this->assertEquals('ready', $deployment['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployment['body'], JSON_PRETTY_PRINT)); - }, 100000, 500); + }, 150000, 500); $this->assertEventually(function () use ($siteId, $deploymentId) { $site = $this->getSite($siteId);