From 7c2ab4fcf652b2823a42c04daf8ce4c0233eb609 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sat, 22 Mar 2025 13:47:09 +0530 Subject: [PATCH 01/29] update: change sample rate for 4xx via env. --- app/controllers/general.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index a374aa3c39..1423763cec 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -871,17 +871,18 @@ App::error() if (!empty($providerConfig) && $error->getCode() >= 400 && $error->getCode() < 500) { // Register error logger try { - $loggingProvider = new DSN($providerConfig ?? ''); + $loggingProvider = new DSN($providerConfig); $providerName = $loggingProvider->getScheme(); if (!empty($providerName) && $providerName === 'sentry') { $key = $loggingProvider->getPassword(); $projectId = $loggingProvider->getUser() ?? ''; $host = 'https://' . $loggingProvider->getHost(); + $sampleRate = $loggingProvider->getParam('sample', 0.01); $adapter = new Sentry($projectId, $key, $host); $logger = new Logger($adapter); - $logger->setSample(0.01); + $logger->setSample($sampleRate); $publish = true; } else { throw new \Exception('Invalid experimental logging provider'); From 86856bf87d1afa58543411eda105fb975009e5db Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sat, 22 Mar 2025 13:55:23 +0000 Subject: [PATCH 02/29] chore: update gitpod.yml config --- .gitpod.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.gitpod.yml b/.gitpod.yml index 478b62fc8d..e9c0928229 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,6 +1,7 @@ tasks: - name: Run Appwrite Docker Stack init: | + git config --global --add safe.directory /app git submodule update --init docker compose build docker compose pull @@ -23,11 +24,3 @@ vscode: extensions: - ms-azuretools.vscode-docker - zobo.php-intellisense - -github: - # https://www.gitpod.io/docs/prebuilds#github-specific-configuration - prebuilds: - # enable for pull requests coming from forks (defaults to false) - pullRequestsFromForks: true - # add a check to pull requests (defaults to true) - addCheck: false From 6195674611b22d8d65c83a038f2d28cdc662ba36 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 25 Mar 2025 21:20:26 +1300 Subject: [PATCH 03/29] Update database --- composer.json | 2 +- composer.lock | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index b1b6aed539..5b0f26b883 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.62.*", + "utopia-php/database": "dev-feat-multi-tenant-insert as 0.62.1", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", diff --git a/composer.lock b/composer.lock index 1ea887fdbc..09b8250af6 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": "d2bec8137dcd84994121f89a29932d31", + "content-hash": "640d2a8be42ae521ea12d8a908873f2b", "packages": [ { "name": "adhocore/jwt", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "0.62.1", + "version": "dev-feat-multi-tenant-insert", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "65dc51466c12552add10395900cdbb4728da4068" + "reference": "2e01c999153a202a8bae9c21e4302e7a674442d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/65dc51466c12552add10395900cdbb4728da4068", - "reference": "65dc51466c12552add10395900cdbb4728da4068", + "url": "https://api.github.com/repos/utopia-php/database/zipball/2e01c999153a202a8bae9c21e4302e7a674442d0", + "reference": "2e01c999153a202a8bae9c21e4302e7a674442d0", "shasum": "" }, "require": { @@ -3546,9 +3546,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.62.1" + "source": "https://github.com/utopia-php/database/tree/feat-multi-tenant-insert" }, - "time": "2025-03-24T08:27:18+00:00" + "time": "2025-03-25T04:45:25+00:00" }, { "name": "utopia-php/domains", @@ -8132,9 +8132,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-feat-multi-tenant-insert", + "alias": "0.62.1", + "alias_normalized": "0.62.1.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From d9d38197ddcd91c6429843ba5878b9a9a4e3bef7 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 26 Mar 2025 23:47:59 +1300 Subject: [PATCH 04/29] Update libs --- composer.json | 2 +- composer.lock | 65 ++++++++++++++++++++++----------------------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/composer.json b/composer.json index 5b0f26b883..b8c5afa109 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-feat-multi-tenant-insert as 0.62.1", + "utopia-php/database": "0.63.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", diff --git a/composer.lock b/composer.lock index 09b8250af6..d4956aeba0 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": "640d2a8be42ae521ea12d8a908873f2b", + "content-hash": "5b3c46863e4571c838c30090ad96436c", "packages": [ { "name": "adhocore/jwt", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "dev-feat-multi-tenant-insert", + "version": "0.63.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "2e01c999153a202a8bae9c21e4302e7a674442d0" + "reference": "51ff0a6514e6eda44a6da016d838e7e55282e01a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/2e01c999153a202a8bae9c21e4302e7a674442d0", - "reference": "2e01c999153a202a8bae9c21e4302e7a674442d0", + "url": "https://api.github.com/repos/utopia-php/database/zipball/51ff0a6514e6eda44a6da016d838e7e55282e01a", + "reference": "51ff0a6514e6eda44a6da016d838e7e55282e01a", "shasum": "" }, "require": { @@ -3546,9 +3546,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/feat-multi-tenant-insert" + "source": "https://github.com/utopia-php/database/tree/0.63.0" }, - "time": "2025-03-25T04:45:25+00:00" + "time": "2025-03-26T10:35:37+00:00" }, { "name": "utopia-php/domains", @@ -3950,16 +3950,16 @@ }, { "name": "utopia-php/migration", - "version": "0.8.2", + "version": "0.8.3", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1" + "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1", - "reference": "aa3b7a508feb7090f487e7bf9cd71f5c92fbc7c1", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/85c2e14647b240b75be6b6b762e5b30e48fb8d8a", + "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a", "shasum": "" }, "require": { @@ -3967,7 +3967,7 @@ "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", - "utopia-php/database": "0.62.*", + "utopia-php/database": "0.63.*", "utopia-php/dsn": "0.2.*", "utopia-php/framework": "0.33.*", "utopia-php/storage": "0.18.*" @@ -4000,9 +4000,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.8.2" + "source": "https://github.com/utopia-php/migration/tree/0.8.3" }, - "time": "2025-03-24T09:05:31+00:00" + "time": "2025-03-26T10:45:51+00:00" }, { "name": "utopia-php/orchestration", @@ -4385,16 +4385,16 @@ }, { "name": "utopia-php/swoole", - "version": "0.8.2", + "version": "0.8.3", "source": { "type": "git", "url": "https://github.com/utopia-php/swoole.git", - "reference": "5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4" + "reference": "1af73dd3e73987cf729c7db399054e4a70befd99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/swoole/zipball/5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4", - "reference": "5fa9d42c608ad46a4ce42a6d2b2eae00592fccd4", + "url": "https://api.github.com/repos/utopia-php/swoole/zipball/1af73dd3e73987cf729c7db399054e4a70befd99", + "reference": "1af73dd3e73987cf729c7db399054e4a70befd99", "shasum": "" }, "require": { @@ -4430,9 +4430,9 @@ ], "support": { "issues": "https://github.com/utopia-php/swoole/issues", - "source": "https://github.com/utopia-php/swoole/tree/0.8.2" + "source": "https://github.com/utopia-php/swoole/tree/0.8.3" }, - "time": "2024-02-01T14:54:12+00:00" + "time": "2025-03-26T10:09:05+00:00" }, { "name": "utopia-php/system", @@ -4775,16 +4775,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.9", + "version": "0.40.10", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4" + "reference": "054ac96285caf4f77879087b2416a5ddb8263051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/dbb45a5db22cdc3368fe2573c07ba6088f188fa4", - "reference": "dbb45a5db22cdc3368fe2573c07ba6088f188fa4", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/054ac96285caf4f77879087b2416a5ddb8263051", + "reference": "054ac96285caf4f77879087b2416a5ddb8263051", "shasum": "" }, "require": { @@ -4820,9 +4820,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.9" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.10" }, - "time": "2025-03-17T18:39:14+00:00" + "time": "2025-03-25T13:44:16+00:00" }, { "name": "doctrine/annotations", @@ -8132,18 +8132,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-feat-multi-tenant-insert", - "alias": "0.62.1", - "alias_normalized": "0.62.1.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From c79e8e5b954ce3e61c39bcd01413d05f7905b2dd Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Thu, 27 Mar 2025 18:04:17 +1300 Subject: [PATCH 05/29] Update database --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index d4956aeba0..eb29c765a0 100644 --- a/composer.lock +++ b/composer.lock @@ -709,16 +709,16 @@ }, { "name": "google/protobuf", - "version": "v4.30.1", + "version": "v4.30.2", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24" + "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/f29ba8a30dfd940efb3a8a75dc44446539101f24", - "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/a4c4d8565b40b9f76debc9dfeb221412eacb8ced", + "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced", "shasum": "" }, "require": { @@ -747,9 +747,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.1" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.2" }, - "time": "2025-03-13T21:08:17+00:00" + "time": "2025-03-26T18:01:50+00:00" }, { "name": "league/csv", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "0.63.0", + "version": "0.63.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "51ff0a6514e6eda44a6da016d838e7e55282e01a" + "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/51ff0a6514e6eda44a6da016d838e7e55282e01a", - "reference": "51ff0a6514e6eda44a6da016d838e7e55282e01a", + "url": "https://api.github.com/repos/utopia-php/database/zipball/ad191bf34151815f716f553796a363ff2b6ef7d3", + "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3", "shasum": "" }, "require": { @@ -3546,9 +3546,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.63.0" + "source": "https://github.com/utopia-php/database/tree/0.63.1" }, - "time": "2025-03-26T10:35:37+00:00" + "time": "2025-03-27T04:58:07+00:00" }, { "name": "utopia-php/domains", From cba700402bb79598a526f0e6d026060cf0cd3e50 Mon Sep 17 00:00:00 2001 From: fogelito Date: Fri, 28 Mar 2025 09:04:50 +0300 Subject: [PATCH 06/29] Add order by for cursor --- src/Appwrite/Platform/Workers/Deletes.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 5033822241..5674448c18 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -405,7 +405,7 @@ class Deletes extends Action ); $queries = [ - Query::select($this->selects), + Query::select(array_merge($this->selects, ['accessedAt'])), Query::lessThan('accessedAt', $datetime), Query::orderDesc('accessedAt'), Query::orderDesc(), @@ -439,9 +439,11 @@ class Deletes extends Action /** @var Database $dbForProject*/ $dbForProject = $getProjectDB($project); + $select = array_merge($this->selects, ['time']); + // Delete Usage stats from projectDB $this->deleteByGroup('stats', [ - Query::select($this->selects), + Query::select($select), Query::equal('period', ['1h']), Query::lessThan('time', $hourlyUsageRetentionDatetime), Query::orderDesc('time'), @@ -454,7 +456,7 @@ class Deletes extends Action // Delete Usage stats from logsDB $this->deleteByGroup('stats', [ - Query::select($this->selects), + Query::select($select), Query::equal('period', ['1h']), Query::lessThan('time', $hourlyUsageRetentionDatetime), Query::orderDesc('time'), @@ -751,7 +753,7 @@ class Deletes extends Action // Delete Executions $this->deleteByGroup('executions', [ - Query::select($this->selects), + Query::select(array_merge($this->selects, ['$createdAt'])), Query::lessThan('$createdAt', $datetime), Query::orderDesc('$createdAt'), Query::orderDesc(), @@ -772,7 +774,7 @@ class Deletes extends Action // Delete Sessions $this->deleteByGroup('sessions', [ - Query::select($this->selects), + Query::select(array_merge($this->selects, ['$createdAt'])), Query::lessThan('$createdAt', $expired), Query::orderDesc('$createdAt'), Query::orderDesc(), @@ -809,7 +811,7 @@ class Deletes extends Action try { $this->deleteByGroup(Audit::COLLECTION, [ - Query::select($this->selects), + Query::select(array_merge($this->selects, ['time'])), Query::lessThan('time', $auditRetention), Query::orderDesc('time'), Query::orderAsc(), From a4c18c4b774eefa25af547b31929986d953a2552 Mon Sep 17 00:00:00 2001 From: fogelito Date: Fri, 28 Mar 2025 09:16:25 +0300 Subject: [PATCH 07/29] Remove array merge --- src/Appwrite/Platform/Workers/Deletes.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 5674448c18..a9b83976a4 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -405,7 +405,7 @@ class Deletes extends Action ); $queries = [ - Query::select(array_merge($this->selects, ['accessedAt'])), + Query::select([...$this->selects, 'accessedAt']), Query::lessThan('accessedAt', $datetime), Query::orderDesc('accessedAt'), Query::orderDesc(), @@ -439,11 +439,11 @@ class Deletes extends Action /** @var Database $dbForProject*/ $dbForProject = $getProjectDB($project); - $select = array_merge($this->selects, ['time']); + $selects = [...$this->selects, 'time']; // Delete Usage stats from projectDB $this->deleteByGroup('stats', [ - Query::select($select), + Query::select($selects), Query::equal('period', ['1h']), Query::lessThan('time', $hourlyUsageRetentionDatetime), Query::orderDesc('time'), @@ -456,7 +456,7 @@ class Deletes extends Action // Delete Usage stats from logsDB $this->deleteByGroup('stats', [ - Query::select($select), + Query::select($selects), Query::equal('period', ['1h']), Query::lessThan('time', $hourlyUsageRetentionDatetime), Query::orderDesc('time'), @@ -753,7 +753,7 @@ class Deletes extends Action // Delete Executions $this->deleteByGroup('executions', [ - Query::select(array_merge($this->selects, ['$createdAt'])), + Query::select([...$this->selects, '$createdAt']), Query::lessThan('$createdAt', $datetime), Query::orderDesc('$createdAt'), Query::orderDesc(), @@ -774,7 +774,7 @@ class Deletes extends Action // Delete Sessions $this->deleteByGroup('sessions', [ - Query::select(array_merge($this->selects, ['$createdAt'])), + Query::select([...$this->selects, '$createdAt']), Query::lessThan('$createdAt', $expired), Query::orderDesc('$createdAt'), Query::orderDesc(), @@ -811,7 +811,7 @@ class Deletes extends Action try { $this->deleteByGroup(Audit::COLLECTION, [ - Query::select(array_merge($this->selects, ['time'])), + Query::select([...$this->selects, 'time']), Query::lessThan('time', $auditRetention), Query::orderDesc('time'), Query::orderAsc(), From 22939831f2d759f26bc5912b2b3e7a9cdceadc62 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 28 Mar 2025 20:58:25 +0100 Subject: [PATCH 08/29] Updated fetch version --- composer.json | 2 +- composer.lock | 78 +++++++++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/composer.json b/composer.json index b8c5afa109..176b5889fc 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", - "utopia-php/fetch": "0.3.*", + "utopia-php/fetch": "0.4.*", "utopia-php/image": "0.8.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", diff --git a/composer.lock b/composer.lock index eb29c765a0..3772b25707 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": "5b3c46863e4571c838c30090ad96436c", + "content-hash": "c99b4733669c17013e211c7dc54a86f6", "packages": [ { "name": "adhocore/jwt", @@ -3659,16 +3659,16 @@ }, { "name": "utopia-php/fetch", - "version": "0.3.1", + "version": "0.4.0", "source": { "type": "git", "url": "https://github.com/utopia-php/fetch.git", - "reference": "524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0" + "reference": "46e791ff6a95864517750b9df6bbf4a17e3c9c4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/fetch/zipball/524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0", - "reference": "524dd50afa8c64670c4fb18f1df4db9b5bb4b3d0", + "url": "https://api.github.com/repos/utopia-php/fetch/zipball/46e791ff6a95864517750b9df6bbf4a17e3c9c4e", + "reference": "46e791ff6a95864517750b9df6bbf4a17e3c9c4e", "shasum": "" }, "require": { @@ -3692,9 +3692,9 @@ "description": "A simple library that provides an interface for making HTTP Requests.", "support": { "issues": "https://github.com/utopia-php/fetch/issues", - "source": "https://github.com/utopia-php/fetch/tree/0.3.1" + "source": "https://github.com/utopia-php/fetch/tree/0.4.0" }, - "time": "2025-03-05T18:08:55+00:00" + "time": "2025-03-11T21:06:56+00:00" }, { "name": "utopia-php/framework", @@ -3950,16 +3950,16 @@ }, { "name": "utopia-php/migration", - "version": "0.8.3", + "version": "0.8.4", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a" + "reference": "845fd04ccf5e0edb03c184b864e0596080a432b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/85c2e14647b240b75be6b6b762e5b30e48fb8d8a", - "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/845fd04ccf5e0edb03c184b864e0596080a432b8", + "reference": "845fd04ccf5e0edb03c184b864e0596080a432b8", "shasum": "" }, "require": { @@ -3967,7 +3967,7 @@ "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", - "utopia-php/database": "0.63.*", + "utopia-php/database": "0.*.*", "utopia-php/dsn": "0.2.*", "utopia-php/framework": "0.33.*", "utopia-php/storage": "0.18.*" @@ -4000,9 +4000,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.8.3" + "source": "https://github.com/utopia-php/migration/tree/0.8.4" }, - "time": "2025-03-26T10:45:51+00:00" + "time": "2025-03-28T02:08:22+00:00" }, { "name": "utopia-php/orchestration", @@ -4211,23 +4211,23 @@ }, { "name": "utopia-php/queue", - "version": "0.9.0", + "version": "0.9.1", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7" + "reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/077075f1d57afa430f76c35ed3bf4616e0eee8e7", - "reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32", + "reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32", "shasum": "" }, "require": { "php": ">=8.3", "php-amqplib/php-amqplib": "^3.7", "utopia-php/cli": "0.15.*", - "utopia-php/fetch": "^0.3.0", + "utopia-php/fetch": "0.4.*", "utopia-php/framework": "0.33.*", "utopia-php/telemetry": "0.1.*" }, @@ -4270,9 +4270,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.9.0" + "source": "https://github.com/utopia-php/queue/tree/0.9.1" }, - "time": "2025-03-13T12:22:41+00:00" + "time": "2025-03-28T19:49:36+00:00" }, { "name": "utopia-php/registry", @@ -4775,16 +4775,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.10", + "version": "0.40.11", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "054ac96285caf4f77879087b2416a5ddb8263051" + "reference": "0ec5f4a60c15e33e208bc3444ba6148b1d0f0027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/054ac96285caf4f77879087b2416a5ddb8263051", - "reference": "054ac96285caf4f77879087b2416a5ddb8263051", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0ec5f4a60c15e33e208bc3444ba6148b1d0f0027", + "reference": "0ec5f4a60c15e33e208bc3444ba6148b1d0f0027", "shasum": "" }, "require": { @@ -4820,9 +4820,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.10" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.11" }, - "time": "2025-03-25T13:44:16+00:00" + "time": "2025-03-26T10:53:16+00:00" }, { "name": "doctrine/annotations", @@ -7154,16 +7154,16 @@ }, { "name": "symfony/console", - "version": "v7.2.1", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + "reference": "e51498ea18570c062e7df29d05a7003585b19b88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88", + "reference": "e51498ea18570c062e7df29d05a7003585b19b88", "shasum": "" }, "require": { @@ -7227,7 +7227,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.2.1" + "source": "https://github.com/symfony/console/tree/v7.2.5" }, "funding": [ { @@ -7243,7 +7243,7 @@ "type": "tidelift" } ], - "time": "2024-12-11T03:49:26+00:00" + "time": "2025-03-12T08:11:12+00:00" }, { "name": "symfony/filesystem", @@ -7758,16 +7758,16 @@ }, { "name": "symfony/process", - "version": "v7.2.4", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", "shasum": "" }, "require": { @@ -7799,7 +7799,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.4" + "source": "https://github.com/symfony/process/tree/v7.2.5" }, "funding": [ { @@ -7815,7 +7815,7 @@ "type": "tidelift" } ], - "time": "2025-02-05T08:33:46+00:00" + "time": "2025-03-13T12:21:46+00:00" }, { "name": "symfony/string", From 612b064d2a9121949030fe7459ad43732a36e15c Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 31 Mar 2025 15:16:59 +0300 Subject: [PATCH 09/29] 0.63.2 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 176b5889fc..2e25ca3748 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.63.*", + "utopia-php/database": "dev-0.63.2-fix as 0.63.2", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", From 4698323f38cfd0f49040eac13da1c63b8cca6003 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 31 Mar 2025 16:19:17 +0300 Subject: [PATCH 10/29] lock --- composer.lock | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/composer.lock b/composer.lock index 3772b25707..a25995668e 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": "c99b4733669c17013e211c7dc54a86f6", + "content-hash": "796b9a9952aac4604cf2acfd0ce455c6", "packages": [ { "name": "adhocore/jwt", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "0.63.1", + "version": "dev-0.63.2-fix", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3" + "reference": "f32c48a8b94aa2e4b543947046daf59e7cbd49d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/ad191bf34151815f716f553796a363ff2b6ef7d3", - "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f32c48a8b94aa2e4b543947046daf59e7cbd49d4", + "reference": "f32c48a8b94aa2e4b543947046daf59e7cbd49d4", "shasum": "" }, "require": { @@ -3546,9 +3546,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.63.1" + "source": "https://github.com/utopia-php/database/tree/0.63.2-fix" }, - "time": "2025-03-27T04:58:07+00:00" + "time": "2025-03-31T11:53:46+00:00" }, { "name": "utopia-php/domains", @@ -8132,9 +8132,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-0.63.2-fix", + "alias": "0.63.2", + "alias_normalized": "0.63.2.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From d92413fd6ba46eb79f548aa957e4258a8d14f7f7 Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 1 Apr 2025 08:13:56 +0300 Subject: [PATCH 11/29] Revert database lib --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2e25ca3748..176b5889fc 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-0.63.2-fix as 0.63.2", + "utopia-php/database": "0.63.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", From b46de29735db1de51981aff820440eddad4bbbfe Mon Sep 17 00:00:00 2001 From: fogelito Date: Tue, 1 Apr 2025 08:15:03 +0300 Subject: [PATCH 12/29] database 0.63.2 --- composer.lock | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index a25995668e..06aea5ed69 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": "796b9a9952aac4604cf2acfd0ce455c6", + "content-hash": "c99b4733669c17013e211c7dc54a86f6", "packages": [ { "name": "adhocore/jwt", @@ -3497,7 +3497,7 @@ }, { "name": "utopia-php/database", - "version": "dev-0.63.2-fix", + "version": "0.63.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", @@ -3546,7 +3546,7 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.63.2-fix" + "source": "https://github.com/utopia-php/database/tree/0.63.2" }, "time": "2025-03-31T11:53:46+00:00" }, @@ -8132,18 +8132,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-0.63.2-fix", - "alias": "0.63.2", - "alias_normalized": "0.63.2.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 938505da5121dc08c84db9ee39b36d332133fe62 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 1 Apr 2025 21:23:23 +0200 Subject: [PATCH 13/29] Updated websocket version --- composer.json | 2 +- composer.lock | 33 ++++++++++++--------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 176b5889fc..39ac2f6574 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "utopia-php/system": "0.9.*", "utopia-php/telemetry": "0.1.*", "utopia-php/vcs": "0.9.*", - "utopia-php/websocket": "0.1.*", + "utopia-php/websocket": "0.3.*", "matomo/device-detector": "6.1.*", "dragonmantank/cron-expression": "3.3.2", "phpmailer/phpmailer": "6.9.1", diff --git a/composer.lock b/composer.lock index 06aea5ed69..8ee7cd75f0 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": "c99b4733669c17013e211c7dc54a86f6", + "content-hash": "d393dfb19f208bab8b2f165071915fc9", "packages": [ { "name": "adhocore/jwt", @@ -4592,27 +4592,28 @@ }, { "name": "utopia-php/websocket", - "version": "0.1.0", + "version": "0.3.0", "source": { "type": "git", "url": "https://github.com/utopia-php/websocket.git", - "reference": "51fcb86171400d8aa40d76c54593481fd273dab5" + "reference": "629e53640b108eab43c7cc9ab375efade8622d43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/websocket/zipball/51fcb86171400d8aa40d76c54593481fd273dab5", - "reference": "51fcb86171400d8aa40d76c54593481fd273dab5", + "url": "https://api.github.com/repos/utopia-php/websocket/zipball/629e53640b108eab43c7cc9ab375efade8622d43", + "reference": "629e53640b108eab43c7cc9ab375efade8622d43", "shasum": "" }, "require": { "php": ">=8.0" }, "require-dev": { + "laravel/pint": "^1.15", + "phpstan/phpstan": "^1.12", "phpunit/phpunit": "^9.5.5", - "swoole/ide-helper": "4.6.6", + "swoole/ide-helper": "5.1.2", "textalk/websocket": "1.5.2", - "vimeo/psalm": "^4.8.1", - "workerman/workerman": "^4.0" + "workerman/workerman": "4.1.*" }, "type": "library", "autoload": { @@ -4624,16 +4625,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - }, - { - "name": "Torsten Dittmann", - "email": "torsten@appwrite.io" - } - ], "description": "A simple abstraction for WebSocket servers.", "keywords": [ "framework", @@ -4644,9 +4635,9 @@ ], "support": { "issues": "https://github.com/utopia-php/websocket/issues", - "source": "https://github.com/utopia-php/websocket/tree/0.1.0" + "source": "https://github.com/utopia-php/websocket/tree/0.3.0" }, - "time": "2021-12-20T10:50:09+00:00" + "time": "2025-03-28T01:11:13+00:00" }, { "name": "webmozart/assert", @@ -8134,7 +8125,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From c152d8e001a4b44e9c4069e6fdfb99f96a9a7077 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 2 Apr 2025 13:02:35 +1300 Subject: [PATCH 14/29] Update database --- composer.json | 4 +-- composer.lock | 92 ++++++++++++++++++++++++++++----------------------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/composer.json b/composer.json index b8c5afa109..2d13ef244f 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.63.*", + "utopia-php/database": "dev-fix-tenant as 0.64.0", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", @@ -63,7 +63,7 @@ "utopia-php/migration": "0.8.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", - "utopia-php/pools": "0.7.*", + "utopia-php/pools": "0.8.*", "utopia-php/preloader": "0.2.*", "utopia-php/queue": "0.9.*", "utopia-php/registry": "0.5.*", diff --git a/composer.lock b/composer.lock index eb29c765a0..43fb23d14f 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": "5b3c46863e4571c838c30090ad96436c", + "content-hash": "0f7e98ef962fcce12b0ea435188504aa", "packages": [ { "name": "adhocore/jwt", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "0.63.1", + "version": "dev-fix-tenant", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3" + "reference": "1b7d8b774ae28d98de82a86e4fef262514e8fc40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/ad191bf34151815f716f553796a363ff2b6ef7d3", - "reference": "ad191bf34151815f716f553796a363ff2b6ef7d3", + "url": "https://api.github.com/repos/utopia-php/database/zipball/1b7d8b774ae28d98de82a86e4fef262514e8fc40", + "reference": "1b7d8b774ae28d98de82a86e4fef262514e8fc40", "shasum": "" }, "require": { @@ -3514,7 +3514,8 @@ "ext-pdo": "*", "php": ">=8.1", "utopia-php/cache": "0.12.*", - "utopia-php/framework": "0.33.*" + "utopia-php/framework": "0.33.*", + "utopia-php/pools": "0.8.*" }, "require-dev": { "fakerphp/faker": "1.23.*", @@ -3546,9 +3547,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.63.1" + "source": "https://github.com/utopia-php/database/tree/fix-tenant" }, - "time": "2025-03-27T04:58:07+00:00" + "time": "2025-04-02T00:00:03+00:00" }, { "name": "utopia-php/domains", @@ -3950,16 +3951,16 @@ }, { "name": "utopia-php/migration", - "version": "0.8.3", + "version": "0.8.4", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a" + "reference": "845fd04ccf5e0edb03c184b864e0596080a432b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/85c2e14647b240b75be6b6b762e5b30e48fb8d8a", - "reference": "85c2e14647b240b75be6b6b762e5b30e48fb8d8a", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/845fd04ccf5e0edb03c184b864e0596080a432b8", + "reference": "845fd04ccf5e0edb03c184b864e0596080a432b8", "shasum": "" }, "require": { @@ -3967,7 +3968,7 @@ "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", - "utopia-php/database": "0.63.*", + "utopia-php/database": "0.*.*", "utopia-php/dsn": "0.2.*", "utopia-php/framework": "0.33.*", "utopia-php/storage": "0.18.*" @@ -4000,9 +4001,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.8.3" + "source": "https://github.com/utopia-php/migration/tree/0.8.4" }, - "time": "2025-03-26T10:45:51+00:00" + "time": "2025-03-28T02:08:22+00:00" }, { "name": "utopia-php/orchestration", @@ -4106,16 +4107,16 @@ }, { "name": "utopia-php/pools", - "version": "0.7.0", + "version": "0.8.0", "source": { "type": "git", "url": "https://github.com/utopia-php/pools.git", - "reference": "ad64d45afda08ec8b29e2642a8d18075964d40bf" + "reference": "60733929dc328e7ea47e800579c8bbf0d49df5ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/pools/zipball/ad64d45afda08ec8b29e2642a8d18075964d40bf", - "reference": "ad64d45afda08ec8b29e2642a8d18075964d40bf", + "url": "https://api.github.com/repos/utopia-php/pools/zipball/60733929dc328e7ea47e800579c8bbf0d49df5ba", + "reference": "60733929dc328e7ea47e800579c8bbf0d49df5ba", "shasum": "" }, "require": { @@ -4152,9 +4153,9 @@ ], "support": { "issues": "https://github.com/utopia-php/pools/issues", - "source": "https://github.com/utopia-php/pools/tree/0.7.0" + "source": "https://github.com/utopia-php/pools/tree/0.8.0" }, - "time": "2025-03-18T03:55:33+00:00" + "time": "2025-03-19T10:22:03+00:00" }, { "name": "utopia-php/preloader", @@ -4775,16 +4776,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.10", + "version": "0.40.11", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "054ac96285caf4f77879087b2416a5ddb8263051" + "reference": "0ec5f4a60c15e33e208bc3444ba6148b1d0f0027" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/054ac96285caf4f77879087b2416a5ddb8263051", - "reference": "054ac96285caf4f77879087b2416a5ddb8263051", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/0ec5f4a60c15e33e208bc3444ba6148b1d0f0027", + "reference": "0ec5f4a60c15e33e208bc3444ba6148b1d0f0027", "shasum": "" }, "require": { @@ -4820,9 +4821,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.10" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.11" }, - "time": "2025-03-25T13:44:16+00:00" + "time": "2025-03-26T10:53:16+00:00" }, { "name": "doctrine/annotations", @@ -7154,16 +7155,16 @@ }, { "name": "symfony/console", - "version": "v7.2.1", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + "reference": "e51498ea18570c062e7df29d05a7003585b19b88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", - "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88", + "reference": "e51498ea18570c062e7df29d05a7003585b19b88", "shasum": "" }, "require": { @@ -7227,7 +7228,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.2.1" + "source": "https://github.com/symfony/console/tree/v7.2.5" }, "funding": [ { @@ -7243,7 +7244,7 @@ "type": "tidelift" } ], - "time": "2024-12-11T03:49:26+00:00" + "time": "2025-03-12T08:11:12+00:00" }, { "name": "symfony/filesystem", @@ -7758,16 +7759,16 @@ }, { "name": "symfony/process", - "version": "v7.2.4", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", - "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", "shasum": "" }, "require": { @@ -7799,7 +7800,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.4" + "source": "https://github.com/symfony/process/tree/v7.2.5" }, "funding": [ { @@ -7815,7 +7816,7 @@ "type": "tidelift" } ], - "time": "2025-02-05T08:33:46+00:00" + "time": "2025-03-13T12:21:46+00:00" }, { "name": "symfony/string", @@ -8132,9 +8133,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-fix-tenant", + "alias": "0.64.0", + "alias_normalized": "0.64.0.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From 32a5ff4c8c5e42c9ad0652f20cb91764089e31e8 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 2 Apr 2025 13:37:26 +1300 Subject: [PATCH 15/29] Update release --- composer.json | 2 +- composer.lock | 27 +++++++++------------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 0eb0f58f04..3920351c06 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-fix-tenant as 0.64.0", + "utopia-php/database": "0.64.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", diff --git a/composer.lock b/composer.lock index 80d9c144f5..270fbca6a4 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": "d9bc106a753e57907134bb717d486310", + "content-hash": "6a54c8bc4f9f14cd3883f55880864630", "packages": [ { "name": "adhocore/jwt", @@ -3497,16 +3497,16 @@ }, { "name": "utopia-php/database", - "version": "dev-fix-tenant", + "version": "0.64.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "1b7d8b774ae28d98de82a86e4fef262514e8fc40" + "reference": "6530a8a6d3c1fe92d0f9a92f0f05eda698d92e0b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/1b7d8b774ae28d98de82a86e4fef262514e8fc40", - "reference": "1b7d8b774ae28d98de82a86e4fef262514e8fc40", + "url": "https://api.github.com/repos/utopia-php/database/zipball/6530a8a6d3c1fe92d0f9a92f0f05eda698d92e0b", + "reference": "6530a8a6d3c1fe92d0f9a92f0f05eda698d92e0b", "shasum": "" }, "require": { @@ -3547,9 +3547,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/fix-tenant" + "source": "https://github.com/utopia-php/database/tree/0.64.1" }, - "time": "2025-04-02T00:00:03+00:00" + "time": "2025-04-02T00:35:29+00:00" }, { "name": "utopia-php/domains", @@ -8124,18 +8124,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-fix-tenant", - "alias": "0.64.0", - "alias_normalized": "0.64.0.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From 1660c0b00c15c216d1f422719217893fc92349cd Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Thu, 3 Apr 2025 02:44:29 +0000 Subject: [PATCH 16/29] Fix: image transformation cache --- app/controllers/shared/api.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 1015400a12..87382bbfe2 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -390,7 +390,8 @@ App::init() ->inject('timelimit') ->inject('mode') ->inject('apiKey') - ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, string $mode, ?Key $apiKey) use ($usageDatabaseListener, $eventDatabaseListener) { + ->inject('plan') + ->action(function (App $utopia, Request $request, Response $response, Document $project, Document $user, Publisher $publisher, Event $queueForEvents, Messaging $queueForMessaging, Audit $queueForAudits, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, StatsUsage $queueForStatsUsage, Database $dbForProject, callable $timelimit, string $mode, ?Key $apiKey, array $plan) use ($usageDatabaseListener, $eventDatabaseListener) { $route = $utopia->getRoute(); @@ -520,6 +521,10 @@ App::init() $useCache = $route->getLabel('cache', false); if ($useCache) { + $route = $utopia->match($request); + $isImageTransformation = $route->getPath() === '/v1/storage/buckets/:bucketId/files/:fileId/preview'; + $isDisabled = isset($plan['imageTransformations']) && $plan['imageTransformations'] === -1 && !Auth::isPrivilegedUser(Authorization::getRoles()); + $key = md5($request->getURI() . '*' . implode('*', $request->getParams()) . '*' . APP_CACHE_BUSTER); $cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key)); $cache = new Cache( @@ -532,7 +537,7 @@ App::init() $parts = explode('/', $cacheLog->getAttribute('resourceType')); $type = $parts[0] ?? null; - if ($type === 'bucket') { + if ($type === 'bucket' && (!$isImageTransformation || !$isDisabled)) { $bucketId = $parts[1] ?? null; $bucket = Authorization::skip(fn () => $dbForProject->getDocument('buckets', $bucketId)); @@ -573,8 +578,10 @@ App::init() $response ->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp)) ->addHeader('X-Appwrite-Cache', 'hit') - ->setContentType($cacheLog->getAttribute('mimeType')) - ->send($data); + ->setContentType($cacheLog->getAttribute('mimeType')); + if (!$isImageTransformation || !$isDisabled) { + $response->send($data); + } } else { $response ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') From bd87672607cbeb8c3152e8f3878d059bafb1daa9 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 3 Apr 2025 18:31:50 +0300 Subject: [PATCH 17/29] Remove audit payload --- src/Appwrite/Platform/Workers/Audits.php | 6 +++++- src/Appwrite/Platform/Workers/Databases.php | 3 ++- src/Appwrite/Platform/Workers/Deletes.php | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Audits.php b/src/Appwrite/Platform/Workers/Audits.php index ed5ff8010a..76309145b8 100644 --- a/src/Appwrite/Platform/Workers/Audits.php +++ b/src/Appwrite/Platform/Workers/Audits.php @@ -74,7 +74,11 @@ class Audits extends Action Console::info('Aggregating audit logs'); $event = $payload['event'] ?? ''; - $auditPayload = $payload['payload'] ?? ''; + + $auditPayload = ''; + if ($project->getId() === 'console') { + $auditPayload = $payload['payload'] ?? ''; + } $mode = $payload['mode'] ?? ''; $resource = $payload['resource'] ?? ''; $userAgent = $payload['userAgent'] ?? ''; diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 4abd035599..44738b557c 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -565,7 +565,8 @@ class Databases extends Action try { $documents = $database->deleteDocuments($collectionId, $queries); } catch (\Throwable $th) { - Console::error('Failed to delete documents for collection ' . $collectionId . ': ' . $th->getMessage()); + $tenant = $database->getSharedTables() ? 'Tenant:'.$database->getTenant() : ''; + Console::error("Failed to delete documents for collection:{$database->getNamespace()}_{$collectionId} {$tenant} :{$th->getMessage()}"); return; } diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index a9b83976a4..09c60c7740 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -1050,7 +1050,8 @@ class Deletes extends Action try { $documents = $database->deleteDocuments($collection, $queries); } catch (Throwable $th) { - Console::error('Failed to delete documents for collection ' . $collection . ': ' . $th->getMessage()); + $tenant = $database->getSharedTables() ? 'Tenant:'.$database->getTenant() : ''; + Console::error("Failed to delete documents for collection:{$database->getNamespace()}_{$collection} {$tenant} :{$th->getMessage()}"); return; } From 2a672f5a633b98f1bcecc73d3addbfc78eecc4b5 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sat, 5 Apr 2025 19:20:24 +0530 Subject: [PATCH 18/29] fix: don't allow the only owner in an org to change their role to anything else. --- app/controllers/api/teams.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index dfdccf5e99..d4db6a4a52 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1034,7 +1034,6 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->param('membershipId', '', new UID(), 'Membership ID.') ->param('roles', [], function (Document $project) { if ($project->getId() === 'console') { - ; $roles = array_keys(Config::getParam('roles', [])); array_filter($roles, function ($role) { return !in_array($role, [Auth::USER_ROLE_APPS, Auth::USER_ROLE_GUESTS, Auth::USER_ROLE_USERS]); @@ -1046,9 +1045,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') ->inject('request') ->inject('response') ->inject('user') + ->inject('project') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $teamId, string $membershipId, array $roles, Request $request, Response $response, Document $user, Document $project, Database $dbForProject, Event $queueForEvents) { $team = $dbForProject->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -1069,6 +1069,21 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') $isAppUser = Auth::isAppUser(Authorization::getRoles()); $isOwner = Authorization::isRole('team:' . $team->getId() . '/owner'); + 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'])], + max: 2 + ); + + // If there's only one owner, + // and the requester is that owner, prevent role change + if ($ownersCount === 1 && $isOwner) { + throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.'); + } + } + if (!$isOwner && !$isPrivilegedUser && !$isAppUser) { // Not owner, not admin, not app (server) throw new Exception(Exception::USER_UNAUTHORIZED, 'User is not allowed to modify roles'); } From 7297188c1bf0dd67229afc2ef30ad527cc76fecc Mon Sep 17 00:00:00 2001 From: Darshan Date: Sat, 5 Apr 2025 19:42:20 +0530 Subject: [PATCH 19/29] update: roles check. --- app/controllers/api/teams.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index d4db6a4a52..3e0e366b6b 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1077,9 +1077,9 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') max: 2 ); - // If there's only one owner, - // and the requester is that owner, prevent role change - if ($ownersCount === 1 && $isOwner) { + // 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)) { throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'There must be at least one owner in the organization.'); } } From abd953974d4dec5af095ced36dec79ab0904df5f Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sat, 5 Apr 2025 14:43:07 +0000 Subject: [PATCH 20/29] chore: give read write permission to vendor for gitpod config --- .gitpod.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index e9c0928229..c103d81900 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,13 +1,14 @@ tasks: - name: Run Appwrite Docker Stack init: | - git config --global --add safe.directory /app git submodule update --init docker compose build docker compose pull docker pull composer command: | + sudo chown -R $(id -u):$(id -g) vendor/ docker run --rm --interactive --tty \ + --user "$(id -u):$(id -g)" \ --volume $PWD:/app \ composer install \ --ignore-platform-reqs \ From e5ef825ac41fd63fad3983115730c48a3725fd14 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sat, 5 Apr 2025 15:47:22 +0000 Subject: [PATCH 21/29] chore: update php image to 0.8.1 --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 270fbca6a4..8db4706bb5 100644 --- a/composer.lock +++ b/composer.lock @@ -2965,16 +2965,16 @@ }, { "name": "tbachert/spi", - "version": "v1.0.2", + "version": "v1.0.3", "source": { "type": "git", "url": "https://github.com/Nevay/spi.git", - "reference": "2ddfaf815dafb45791a61b08170de8d583c16062" + "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Nevay/spi/zipball/2ddfaf815dafb45791a61b08170de8d583c16062", - "reference": "2ddfaf815dafb45791a61b08170de8d583c16062", + "url": "https://api.github.com/repos/Nevay/spi/zipball/506a79c98e1a51522e76ee921ccb6c62d52faf3a", + "reference": "506a79c98e1a51522e76ee921ccb6c62d52faf3a", "shasum": "" }, "require": { @@ -3011,9 +3011,9 @@ ], "support": { "issues": "https://github.com/Nevay/spi/issues", - "source": "https://github.com/Nevay/spi/tree/v1.0.2" + "source": "https://github.com/Nevay/spi/tree/v1.0.3" }, - "time": "2024-10-04T16:36:12+00:00" + "time": "2025-04-02T19:38:14+00:00" }, { "name": "thecodingmachine/safe", @@ -3746,16 +3746,16 @@ }, { "name": "utopia-php/image", - "version": "0.8.0", + "version": "0.8.1", "source": { "type": "git", "url": "https://github.com/utopia-php/image.git", - "reference": "dcae5b1c6deb3ff6865f4e68f012b3709c289bca" + "reference": "e8cc7dd14f423270a1b7570ec0dae88a66195b63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/image/zipball/dcae5b1c6deb3ff6865f4e68f012b3709c289bca", - "reference": "dcae5b1c6deb3ff6865f4e68f012b3709c289bca", + "url": "https://api.github.com/repos/utopia-php/image/zipball/e8cc7dd14f423270a1b7570ec0dae88a66195b63", + "reference": "e8cc7dd14f423270a1b7570ec0dae88a66195b63", "shasum": "" }, "require": { @@ -3789,9 +3789,9 @@ ], "support": { "issues": "https://github.com/utopia-php/image/issues", - "source": "https://github.com/utopia-php/image/tree/0.8.0" + "source": "https://github.com/utopia-php/image/tree/0.8.1" }, - "time": "2025-02-20T11:49:03+00:00" + "time": "2025-04-04T18:55:20+00:00" }, { "name": "utopia-php/locale", From 403083b0cef7053588474b98587b036790fdc01c Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sun, 6 Apr 2025 08:31:46 +0530 Subject: [PATCH 22/29] Update .gitpod.yml --- .gitpod.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index c103d81900..78375bb1f0 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -6,7 +6,6 @@ tasks: docker compose pull docker pull composer command: | - sudo chown -R $(id -u):$(id -g) vendor/ docker run --rm --interactive --tty \ --user "$(id -u):$(id -g)" \ --volume $PWD:/app \ From c3c568653fd9f4a5693e5b06a8c4d6c342e30fc6 Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 6 Apr 2025 10:21:55 +0530 Subject: [PATCH 23/29] add: roles check test. --- tests/e2e/Services/Teams/TeamsBase.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 2328e4cdbf..87486696d2 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -37,6 +37,31 @@ trait TeamsBase $teamUid = $response1['body']['$id']; $teamName = $response1['body']['name']; + /** + * Test: Attempt to downgrade the only OWNER in a team (should fail) + */ + // Step 1: Fetch all team memberships — only one exists at this point + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + // Step 2: Extract the membership ID of the only member (also the only OWNER) + $membershipID = $response['body']['memberships'][0]['$id']; + + // Step 3: Attempt to downgrade the member's role to 'developer' + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipID, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'roles' => ['developer'] + ]); + + // 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('There must be at least one owner in the organization.', $response['body']['message']); + $teamId = ID::unique(); $response2 = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ 'content-type' => 'application/json', From 2243f0c72e45e5a8abfe716bb2b8470375a07f6b Mon Sep 17 00:00:00 2001 From: Darshan Date: Sun, 6 Apr 2025 10:29:18 +0530 Subject: [PATCH 24/29] fix: test for only console db <> orgs. --- tests/e2e/Services/Teams/TeamsBase.php | 44 +++++++++++++++----------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 87486696d2..80ac1621ee 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -38,29 +38,35 @@ trait TeamsBase $teamName = $response1['body']['name']; /** - * Test: Attempt to downgrade the only OWNER in a team (should fail) + * Test: Attempt to downgrade the only OWNER in an organization (should fail) */ - // Step 1: Fetch all team memberships — only one exists at this point - $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + if ($this->getProject()['$id'] === 'console') { + // Step 1: Fetch all team memberships — only one exists at this point + $response = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::limit(1)->toString(), + ], + ]); - // Step 2: Extract the membership ID of the only member (also the only OWNER) - $membershipID = $response['body']['memberships'][0]['$id']; + // Step 2: Extract the membership ID of the only member (also the only OWNER) + $membershipID = $response['body']['memberships'][0]['$id']; - // Step 3: Attempt to downgrade the member's role to 'developer' - $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipID, array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'roles' => ['developer'] - ]); + // Step 3: Attempt to downgrade the member's role to 'developer' + $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipID, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'roles' => ['developer'] + ]); - // 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('There must be at least one owner in the organization.', $response['body']['message']); + // 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('There must be at least one owner in the organization.', $response['body']['message']); + } $teamId = ID::unique(); $response2 = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ From 954ed45a36ff821125cbfa63c75f16aebc7fb8f1 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Fri, 28 Feb 2025 13:52:34 +0100 Subject: [PATCH 25/29] feat: update appwrite to use generic S3 adapter --- app/init/resources.php | 15 +++++++++++++-- docker-compose.yml | 6 +++++- src/Executor/Executor.php | 6 +++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/init/resources.php b/app/init/resources.php index 4e53b24c06..0011a8c677 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -38,6 +38,7 @@ use Utopia\Logger\Log; use Utopia\Pools\Group; use Utopia\Queue\Publisher; use Utopia\Storage\Device; +use Utopia\Storage\Device\AWS; use Utopia\Storage\Device\Backblaze; use Utopia\Storage\Device\DOSpaces; use Utopia\Storage\Device\Linode; @@ -540,7 +541,12 @@ function getDevice(string $root, string $connection = ''): Device switch ($device) { case Storage::DEVICE_S3: - return new S3($root, $accessKey, $accessSecret, $bucket, $region, $acl, $url); + if (!empty($url)) { + return new S3($root, $accessKey, $accessSecret, $url, $region, $acl); + } else { + return new AWS($root, $accessKey, $accessSecret, $bucket, $region, $acl); + } + // no break case STORAGE::DEVICE_DO_SPACES: $device = new DOSpaces($root, $accessKey, $accessSecret, $bucket, $region, $acl); $device->setHttpVersion(S3::HTTP_VERSION_1_1); @@ -567,7 +573,12 @@ function getDevice(string $root, string $connection = ''): Device $s3Bucket = System::getEnv('_APP_STORAGE_S3_BUCKET', ''); $s3Acl = 'private'; $s3EndpointUrl = System::getEnv('_APP_STORAGE_S3_ENDPOINT', ''); - return new S3($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl, $s3EndpointUrl); + if (!empty($s3EndpointUrl)) { + return new S3($root, $s3AccessKey, $s3SecretKey, $s3EndpointUrl, $s3Region, $s3Acl); + } else { + return new AWS($root, $s3AccessKey, $s3SecretKey, $s3Bucket, $s3Region, $s3Acl); + } + // no break case Storage::DEVICE_DO_SPACES: $doSpacesAccessKey = System::getEnv('_APP_STORAGE_DO_SPACES_ACCESS_KEY', ''); $doSpacesSecretKey = System::getEnv('_APP_STORAGE_DO_SPACES_SECRET', ''); diff --git a/docker-compose.yml b/docker-compose.yml index 05ddba967a..8c8a364f30 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -198,6 +198,8 @@ services: - _APP_DATABASE_SHARED_TABLES_V1 - _APP_DATABASE_SHARED_NAMESPACE - _APP_FUNCTIONS_CREATION_ABUSE_LIMIT + extra_hosts: + - "host.docker.internal:host-gateway" appwrite-console: <<: *x-logging @@ -489,6 +491,8 @@ services: - _APP_STORAGE_WASABI_REGION - _APP_STORAGE_WASABI_BUCKET - _APP_DATABASE_SHARED_TABLES + extra_hosts: + - "host.docker.internal:host-gateway" appwrite-worker-certificates: entrypoint: worker-certificates @@ -1131,4 +1135,4 @@ volumes: appwrite-certificates: appwrite-functions: appwrite-builds: - appwrite-config: \ No newline at end of file + appwrite-config: diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index c230cfb664..936fba5b24 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -235,7 +235,11 @@ class Executor throw new \Exception($message, $status); } - $response['body']['headers'] = \json_decode($response['body']['headers'] ?? '{}', true); + $headers = $response['body']['headers'] ?? []; + if (is_string($headers)) { + $headers = \json_decode($headers, true); + } + $response['body']['headers'] = $headers; $response['body']['statusCode'] = \intval($response['body']['statusCode'] ?? 500); $response['body']['duration'] = \floatval($response['body']['duration'] ?? 0); $response['body']['startTime'] = \floatval($response['body']['startTime'] ?? \microtime(true)); From 0ae70f8321e1916eaad4f6afa1cd430e55f7b3b9 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Tue, 25 Mar 2025 12:33:03 +0100 Subject: [PATCH 26/29] feat: inject executor instead of creating a new instance --- app/cli.php | 3 ++ app/controllers/api/functions.php | 12 +++---- app/controllers/general.php | 23 +++++++------ app/init/resources.php | 3 ++ app/worker.php | 3 ++ src/Appwrite/Platform/Workers/Builds.php | 15 +++++---- src/Appwrite/Platform/Workers/Deletes.php | 26 ++++++++------- src/Appwrite/Platform/Workers/Functions.php | 11 ++++-- src/Executor/Executor.php | 37 +++++++++++++-------- 9 files changed, 82 insertions(+), 51 deletions(-) diff --git a/app/cli.php b/app/cli.php index f080217365..82f229673e 100644 --- a/app/cli.php +++ b/app/cli.php @@ -9,6 +9,7 @@ use Appwrite\Event\StatsResources; use Appwrite\Event\StatsUsage; use Appwrite\Platform\Appwrite; use Appwrite\Runtimes\Runtimes; +use Executor\Executor; use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; use Utopia\CLI\CLI; @@ -255,6 +256,8 @@ CLI::setResource('logError', function (Registry $register) { }; }, ['register']); +CLI::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST'))); + $platform = new Appwrite(); $platform->init(Service::TYPE_TASK); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 37932e4165..c7f24f984a 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -869,7 +869,8 @@ App::put('/v1/functions/:functionId') ->inject('queueForBuilds') ->inject('dbForPlatform') ->inject('gitHub') - ->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, ?string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Database $dbForPlatform, GitHub $github) use ($redeployVcs) { + ->inject('executor') + ->action(function (string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, ?string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Database $dbForPlatform, GitHub $github, Executor $executor) use ($redeployVcs) { // TODO: If only branch changes, re-deploy $function = $dbForProject->getDocument('functions', $functionId); @@ -972,7 +973,6 @@ App::put('/v1/functions/:functionId') // Enforce Cold Start if spec limits change. if ($function->getAttribute('specification') !== $specification && !empty($function->getAttribute('deployment'))) { - $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); try { $executor->deleteRuntime($project->getId(), $function->getAttribute('deployment')); } catch (\Throwable $th) { @@ -1779,7 +1779,8 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId/build') ->inject('dbForProject') ->inject('project') ->inject('queueForEvents') - ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $queueForEvents) { + ->inject('executor') + ->action(function (string $functionId, string $deploymentId, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Executor $executor) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -1834,7 +1835,6 @@ App::patch('/v1/functions/:functionId/deployments/:deploymentId/build') $dbForProject->purgeCachedDocument('deployments', $deployment->getId()); try { - $executor = new Executor(App::getEnv('_APP_EXECUTOR_HOST')); $executor->deleteRuntime($project->getId(), $deploymentId . "-build"); } catch (\Throwable $th) { // Don't throw if the deployment doesn't exist @@ -1886,8 +1886,9 @@ App::post('/v1/functions/:functionId/executions') ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('queueForFunctions') + ->inject('executor') ->inject('geodb') - ->action(function (string $functionId, string $body, mixed $async, string $path, string $method, mixed $headers, ?string $scheduledAt, Response $response, Request $request, Document $project, Database $dbForProject, Database $dbForPlatform, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb) { + ->action(function (string $functionId, string $body, mixed $async, string $path, string $method, mixed $headers, ?string $scheduledAt, Response $response, Request $request, Document $project, Database $dbForProject, Database $dbForPlatform, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb) { $async = \strval($async) === 'true' || \strval($async) === '1'; if (!$async && !is_null($scheduledAt)) { @@ -2160,7 +2161,6 @@ App::post('/v1/functions/:functionId/executions') ]); /** Execute function */ - $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); try { $version = $function->getAttribute('version', 'v2'); $command = $runtime['startCommand']; diff --git a/app/controllers/general.php b/app/controllers/general.php index 1423763cec..6c1167cf76 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -50,7 +50,7 @@ Config::setParam('domainVerification', false); Config::setParam('cookieDomain', 'localhost'); Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE); -function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) +function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, SwooleRequest $swooleRequest, Request $request, Response $response, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname) { $utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml'); @@ -339,7 +339,6 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw ]); /** Execute function */ - $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); try { $version = $function->getAttribute('version', 'v2'); $command = $runtime['startCommand']; @@ -503,9 +502,10 @@ App::init() ->inject('queueForEvents') ->inject('queueForCertificates') ->inject('queueForFunctions') + ->inject('executor') ->inject('isResourceBlocked') ->inject('previewHostname') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, callable $isResourceBlocked, string $previewHostname) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForPlatform, callable $getProjectDB, Locale $locale, array $localeCodes, array $clients, Reader $geodb, StatsUsage $queueForStatsUsage, Event $queueForEvents, Certificate $queueForCertificates, Func $queueForFunctions, Executor $executor, callable $isResourceBlocked, string $previewHostname) { /* * Appwrite Router */ @@ -513,7 +513,7 @@ App::init() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname)) { return; } } @@ -742,11 +742,12 @@ App::options() ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('queueForFunctions') + ->inject('executor') ->inject('geodb') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('project') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, Document $project) { /* * Appwrite Router */ @@ -754,7 +755,7 @@ App::options() $mainDomain = System::getEnv('_APP_DOMAIN', ''); // Only run Router when external domain if ($host !== $mainDomain || !empty($previewHostname)) { - if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname)) { + if (router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname)) { return; } } @@ -1062,10 +1063,11 @@ App::get('/robots.txt') ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('queueForFunctions') + ->inject('executor') ->inject('geodb') ->inject('isResourceBlocked') ->inject('previewHostname') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname) { $host = $request->getHostname() ?? ''; $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1073,7 +1075,7 @@ App::get('/robots.txt') $template = new View(__DIR__ . '/../views/general/robots.phtml'); $response->text($template->render(false)); } else { - router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname); + router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname); } }); @@ -1090,10 +1092,11 @@ App::get('/humans.txt') ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('queueForFunctions') + ->inject('executor') ->inject('geodb') ->inject('isResourceBlocked') ->inject('previewHostname') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Reader $geodb, callable $isResourceBlocked, string $previewHostname) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname) { $host = $request->getHostname() ?? ''; $mainDomain = System::getEnv('_APP_DOMAIN', ''); @@ -1101,7 +1104,7 @@ App::get('/humans.txt') $template = new View(__DIR__ . '/../views/general/humans.phtml'); $response->text($template->render(false)); } else { - router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $geodb, $isResourceBlocked, $previewHostname); + router($utopia, $dbForPlatform, $getProjectDB, $swooleRequest, $request, $response, $queueForEvents, $queueForStatsUsage, $queueForFunctions, $executor, $geodb, $isResourceBlocked, $previewHostname); } }); diff --git a/app/init/resources.php b/app/init/resources.php index 0011a8c677..2360179913 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -21,6 +21,7 @@ use Appwrite\Extend\Exception; use Appwrite\GraphQL\Schema; use Appwrite\Network\Validator\Origin; use Appwrite\Utopia\Request; +use Executor\Executor; use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis; use Utopia\App; use Utopia\Cache\Adapter\Sharding; @@ -833,3 +834,5 @@ App::setResource('apiKey', function (Request $request, Document $project): ?Key return Key::decode($project, $key); }, ['request', 'project']); + +App::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST'))); diff --git a/app/worker.php b/app/worker.php index 90496c0430..6a51ee55be 100644 --- a/app/worker.php +++ b/app/worker.php @@ -18,6 +18,7 @@ use Appwrite\Event\StatsUsage; use Appwrite\Event\StatsUsageDump; use Appwrite\Event\Webhook; use Appwrite\Platform\Appwrite; +use Executor\Executor; use Swoole\Runtime; use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis; use Utopia\Cache\Adapter\Sharding; @@ -413,6 +414,8 @@ Server::setResource('logError', function (Registry $register, Document $project) }; }, ['register', 'project']); +Server::setResource('executor', fn () => new Executor(fn (string $projectId, string $deploymentId) => System::getEnv('_APP_EXECUTOR_HOST'))); + $pools = $register->get('pools'); $platform = new Appwrite(); $args = $platform->getEnv('argv'); diff --git a/src/Appwrite/Platform/Workers/Builds.php b/src/Appwrite/Platform/Workers/Builds.php index 6f26e9a80c..4057d4b190 100644 --- a/src/Appwrite/Platform/Workers/Builds.php +++ b/src/Appwrite/Platform/Workers/Builds.php @@ -59,8 +59,9 @@ class Builds extends Action ->inject('deviceForFunctions') ->inject('isResourceBlocked') ->inject('log') - ->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log) => - $this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $usage, $cache, $dbForProject, $deviceForFunctions, $isResourceBlocked, $log)); + ->inject('executor') + ->callback(fn ($message, Document $project, Database $dbForPlatform, Event $queueForEvents, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $usage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log, Executor $executor) => + $this->action($message, $project, $dbForPlatform, $queueForEvents, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $usage, $cache, $dbForProject, $deviceForFunctions, $isResourceBlocked, $log, $executor)); } /** @@ -76,10 +77,11 @@ class Builds extends Action * @param Database $dbForProject * @param Device $deviceForFunctions * @param Log $log + * @param Executor $executor * @return void * @throws \Utopia\Database\Exception */ - public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log): void + public function action(Message $message, Document $project, Database $dbForPlatform, Event $queueForEvents, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, StatsUsage $queueForStatsUsage, Cache $cache, Database $dbForProject, Device $deviceForFunctions, callable $isResourceBlocked, Log $log, Executor $executor): void { $payload = $message->getPayload() ?? []; @@ -100,7 +102,7 @@ class Builds extends Action case BUILD_TYPE_RETRY: Console::info('Creating build for deployment: ' . $deployment->getId()); $github = new GitHub($cache); - $this->buildDeployment($deviceForFunctions, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $isResourceBlocked, $log); + $this->buildDeployment($deviceForFunctions, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $dbForPlatform, $dbForProject, $github, $project, $resource, $deployment, $template, $isResourceBlocked, $log, $executor); break; default: @@ -123,14 +125,13 @@ class Builds extends Action * @param Document $deployment * @param Document $template * @param Log $log + * @param Executor $executor * @return void * @throws \Utopia\Database\Exception * @throws Exception */ - protected function buildDeployment(Device $deviceForFunctions, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, callable $isResourceBlocked, Log $log): void + protected function buildDeployment(Device $deviceForFunctions, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Database $dbForPlatform, Database $dbForProject, GitHub $github, Document $project, Document $function, Document $deployment, Document $template, callable $isResourceBlocked, Log $log, Executor $executor): void { - $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); - $functionId = $function->getId(); $log->addTag('functionId', $function->getId()); diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 09c60c7740..5092599d67 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -55,12 +55,13 @@ class Deletes extends Action ->inject('deviceForBuilds') ->inject('deviceForCache') ->inject('certificates') + ->inject('executor') ->inject('executionRetention') ->inject('auditRetention') ->inject('log') ->callback( - fn ($message, Document $project, Database $dbForPlatform, callable $getProjectDB, callable $getLogsDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, string $executionRetention, string $auditRetention, Log $log) => - $this->action($message, $project, $dbForPlatform, $getProjectDB, $getLogsDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $certificates, $executionRetention, $auditRetention, $log) + fn ($message, Document $project, Database $dbForPlatform, callable $getProjectDB, callable $getLogsDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, Executor $executor, string $executionRetention, string $auditRetention, Log $log) => + $this->action($message, $project, $dbForPlatform, $getProjectDB, $getLogsDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $certificates, $executor, $executionRetention, $auditRetention, $log) ); } @@ -68,7 +69,7 @@ class Deletes extends Action * @throws Exception * @throws Throwable */ - public function action(Message $message, Document $project, Database $dbForPlatform, callable $getProjectDB, callable $getLogsDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, string $executionRetention, string $auditRetention, Log $log): void + public function action(Message $message, Document $project, Database $dbForPlatform, callable $getProjectDB, callable $getLogsDB, Device $deviceForFiles, Device $deviceForFunctions, Device $deviceForBuilds, Device $deviceForCache, CertificatesAdapter $certificates, Executor $executor, string $executionRetention, string $auditRetention, Log $log): void { $payload = $message->getPayload() ?? []; @@ -93,10 +94,10 @@ class Deletes extends Action $this->deleteProject($dbForPlatform, $getProjectDB, $deviceForFiles, $deviceForFunctions, $deviceForBuilds, $deviceForCache, $certificates, $document); break; case DELETE_TYPE_FUNCTIONS: - $this->deleteFunction($dbForPlatform, $getProjectDB, $deviceForFunctions, $deviceForBuilds, $certificates, $document, $project); + $this->deleteFunction($dbForPlatform, $getProjectDB, $deviceForFunctions, $deviceForBuilds, $certificates, $document, $project, $executor); break; case DELETE_TYPE_DEPLOYMENTS: - $this->deleteDeployment($getProjectDB, $deviceForFunctions, $deviceForBuilds, $document, $project); + $this->deleteDeployment($getProjectDB, $deviceForFunctions, $deviceForBuilds, $document, $project, $executor); break; case DELETE_TYPE_USERS: $this->deleteUser($getProjectDB, $document, $project); @@ -827,10 +828,11 @@ class Deletes extends Action * @param Device $deviceForBuilds * @param Document $document function document * @param Document $project + * @param Executor $executor * @return void * @throws Exception */ - private function deleteFunction(Database $dbForPlatform, callable $getProjectDB, Device $deviceForFunctions, Device $deviceForBuilds, CertificatesAdapter $certificates, Document $document, Document $project): void + private function deleteFunction(Database $dbForPlatform, callable $getProjectDB, Device $deviceForFunctions, Device $deviceForBuilds, CertificatesAdapter $certificates, Document $document, Document $project, Executor $executor): void { $projectId = $project->getId(); $dbForProject = $getProjectDB($project); @@ -922,7 +924,7 @@ class Deletes extends Action * Request executor to delete all deployment containers */ Console::info("Requesting executor to delete all deployment containers for function " . $functionId); - $this->deleteRuntimes($getProjectDB, $document, $project); + $this->deleteRuntimes($getProjectDB, $document, $project, $executor); } /** @@ -993,10 +995,11 @@ class Deletes extends Action * @param Device $deviceForBuilds * @param Document $document * @param Document $project + * @param Executor $executor * @return void * @throws Exception */ - private function deleteDeployment(callable $getProjectDB, Device $deviceForFunctions, Device $deviceForBuilds, Document $document, Document $project): void + private function deleteDeployment(callable $getProjectDB, Device $deviceForFunctions, Device $deviceForBuilds, Document $document, Document $project, Executor $executor): void { $projectId = $project->getId(); $dbForProject = $getProjectDB($project); @@ -1024,7 +1027,7 @@ class Deletes extends Action * Request executor to delete all deployment containers */ Console::info("Requesting executor to delete deployment container for deployment " . $deploymentId); - $this->deleteRuntimes($getProjectDB, $document, $project); + $this->deleteRuntimes($getProjectDB, $document, $project, $executor); } /** @@ -1180,13 +1183,12 @@ class Deletes extends Action * @param callable $getProjectDB * @param ?Document $function * @param Document $project + * @param Executor $executor * @return void * @throws Exception */ - private function deleteRuntimes(callable $getProjectDB, ?Document $function, Document $project): void + private function deleteRuntimes(callable $getProjectDB, ?Document $function, Document $project, Executor $executor): void { - $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); - $deleteByFunction = function (Document $function) use ($getProjectDB, $project, $executor) { $this->listByGroup( 'deployments', diff --git a/src/Appwrite/Platform/Workers/Functions.php b/src/Appwrite/Platform/Workers/Functions.php index a7caa3207f..4e1794c085 100644 --- a/src/Appwrite/Platform/Workers/Functions.php +++ b/src/Appwrite/Platform/Workers/Functions.php @@ -51,11 +51,12 @@ class Functions extends Action ->inject('queueForEvents') ->inject('queueForStatsUsage') ->inject('log') + ->inject('executor') ->inject('isResourceBlocked') - ->callback(fn (Document $project, Message $message, Database $dbForProject, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Log $log, callable $isResourceBlocked) => $this->action($project, $message, $dbForProject, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $log, $isResourceBlocked)); + ->callback(fn (Document $project, Message $message, Database $dbForProject, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Log $log, Executor $executor, callable $isResourceBlocked) => $this->action($project, $message, $dbForProject, $queueForWebhooks, $queueForFunctions, $queueForRealtime, $queueForEvents, $queueForStatsUsage, $log, $executor, $isResourceBlocked)); } - public function action(Document $project, Message $message, Database $dbForProject, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Log $log, callable $isResourceBlocked): void + public function action(Document $project, Message $message, Database $dbForProject, Webhook $queueForWebhooks, Func $queueForFunctions, Realtime $queueForRealtime, Event $queueForEvents, StatsUsage $queueForStatsUsage, Log $log, Executor $executor, callable $isResourceBlocked): void { $payload = $message->getPayload() ?? []; @@ -146,6 +147,7 @@ class Functions extends Action queueForEvents: $queueForEvents, project: $project, function: $function, + executor: $executor, trigger: 'event', path: '/', method: 'POST', @@ -188,6 +190,7 @@ class Functions extends Action queueForEvents: $queueForEvents, project: $project, function: $function, + executor: $executor, trigger: 'http', path: $path, method: $method, @@ -212,6 +215,7 @@ class Functions extends Action queueForEvents: $queueForEvents, project: $project, function: $function, + executor: $executor, trigger: 'schedule', path: $path, method: $method, @@ -298,6 +302,7 @@ class Functions extends Action * @param Event $queueForEvents * @param Document $project * @param Document $function + * @param Executor $executor * @param string $trigger * @param string $path * @param string $method @@ -324,6 +329,7 @@ class Functions extends Action Event $queueForEvents, Document $project, Document $function, + Executor $executor, string $trigger, string $path, string $method, @@ -514,7 +520,6 @@ class Functions extends Action try { $version = $function->getAttribute('version', 'v2'); $command = $runtime['startCommand']; - $executor = new Executor(System::getEnv('_APP_EXECUTOR_HOST')); $command = $version === 'v2' ? '' : 'cp /tmp/code.tar.gz /mnt/code/code.tar.gz && nohup helpers/start.sh "' . $command . '"'; $executionResponse = $executor->createExecution( projectId: $project->getId(), diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 936fba5b24..6bc2fe7aab 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -21,17 +21,19 @@ class Executor private bool $selfSigned = false; - private string $endpoint; + /** + * @var callable(string, string): string $endpoint + */ + private $endpointSelector; protected array $headers; - public function __construct(string $endpoint) + /** + * @param callable(string, string): string $endpointSelector + */ + public function __construct(callable $endpointSelector) { - if (!filter_var($endpoint, FILTER_VALIDATE_URL)) { - throw new Exception('Unsupported endpoint'); - } - - $this->endpoint = $endpoint; + $this->endpointSelector = $endpointSelector; $this->headers = [ 'content-type' => 'application/json', 'authorization' => 'Bearer ' . System::getEnv('_APP_EXECUTOR_SECRET', ''), @@ -92,7 +94,8 @@ class Executor 'timeout' => $timeout, ]; - $response = $this->call(self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout); + $endpoint = $this->selectEndpoint($projectId, $deploymentId); + $response = $this->call($endpoint, self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout); $status = $response['headers']['status-code']; if ($status >= 400) { @@ -123,7 +126,8 @@ class Executor 'timeout' => $timeout ]; - $this->call(self::METHOD_GET, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout, $callback); + $endpoint = $this->selectEndpoint($projectId, $deploymentId); + $this->call($endpoint, self::METHOD_GET, $route, [ 'x-opr-runtime-id' => $runtimeId ], $params, true, $timeout, $callback); } /** @@ -139,7 +143,8 @@ class Executor $runtimeId = "$projectId-$deploymentId"; $route = "/runtimes/$runtimeId"; - $response = $this->call(self::METHOD_DELETE, $route, [ + $endpoint = $this->selectEndpoint($projectId, $deploymentId); + $response = $this->call($endpoint, self::METHOD_DELETE, $route, [ 'x-opr-addressing-method' => 'broadcast' ], [], true, 30); @@ -227,7 +232,8 @@ class Executor $requestTimeout = $timeout + 15; } - $response = $this->call(self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId, 'content-type' => 'multipart/form-data', 'accept' => 'multipart/form-data' ], $params, true, $requestTimeout); + $endpoint = $this->selectEndpoint($projectId, $deploymentId); + $response = $this->call($endpoint, self::METHOD_POST, $route, [ 'x-opr-runtime-id' => $runtimeId, 'content-type' => 'multipart/form-data', 'accept' => 'multipart/form-data' ], $params, true, $requestTimeout); $status = $response['headers']['status-code']; if ($status >= 400) { @@ -260,10 +266,10 @@ class Executor * @return array|string * @throws Exception */ - public function call(string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15, callable $callback = null) + private function call(string $endpoint, string $method, string $path = '', array $headers = [], array $params = [], bool $decode = true, int $timeout = 15, callable $callback = null) { $headers = array_merge($this->headers, $headers); - $ch = curl_init($this->endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); + $ch = curl_init($endpoint . $path . (($method == self::METHOD_GET && !empty($params)) ? '?' . http_build_query($params) : '')); $responseHeaders = []; $responseStatus = -1; $responseType = ''; @@ -426,4 +432,9 @@ class Executor return $output; } + + private function selectEndpoint(string $projectId, string $deploymentId): string + { + return call_user_func($this->endpointSelector, $projectId, $deploymentId); + } } From 3bd8405deba92ca781ec42b211e97bc2e837dd6b Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 8 Apr 2025 07:56:35 +0000 Subject: [PATCH 27/29] feat: add figma oauth provider --- app/config/oAuthProviders.php | 10 + app/config/specs/open-api3-latest-client.json | 8 +- .../specs/open-api3-latest-console.json | 12 +- app/config/specs/open-api3-latest-server.json | 5 +- app/config/specs/swagger2-latest-client.json | 8 +- app/config/specs/swagger2-latest-console.json | 12 +- app/config/specs/swagger2-latest-server.json | 5 +- src/Appwrite/Auth/OAuth2/Figma.php | 176 ++++++++++++++++++ 8 files changed, 216 insertions(+), 20 deletions(-) create mode 100644 src/Appwrite/Auth/OAuth2/Figma.php diff --git a/app/config/oAuthProviders.php b/app/config/oAuthProviders.php index 9d7efc2f1e..261df5c07e 100644 --- a/app/config/oAuthProviders.php +++ b/app/config/oAuthProviders.php @@ -142,6 +142,16 @@ return [ 'beta' => false, 'mock' => false, ], + 'figma' => [ + 'name' => 'Figma', + 'developers' => 'https://www.figma.com/developers/api#oauth2', + 'icon' => 'icon-figma', + 'enabled' => true, + 'sandbox' => false, + 'form' => false, + 'beta' => false, + 'mock' => false, + ], 'github' => [ 'name' => 'GitHub', 'developers' => 'https://developer.github.com/', diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 316fe13116..082d342c49 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.6.1", + "version": "1.6.2", "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", @@ -1902,7 +1902,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "schema": { "type": "string", @@ -1922,6 +1922,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -2778,7 +2779,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "schema": { "type": "string", @@ -2798,6 +2799,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 54161c4262..9d488351bc 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.6.1", + "version": "1.6.2", "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", @@ -1917,7 +1917,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "schema": { "type": "string", @@ -1937,6 +1937,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -2786,7 +2787,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "schema": { "type": "string", @@ -2806,6 +2807,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -19056,8 +19058,7 @@ "description": "Project Region.", "x-example": "default", "enum": [ - "default", - "fra" + "default" ], "x-enum-name": null, "x-enum-keys": [] @@ -20880,6 +20881,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 3d32d3e978..991a380c92 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.6.1", + "version": "1.6.2", "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", @@ -2464,7 +2464,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "schema": { "type": "string", @@ -2484,6 +2484,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 8960bfaa5c..d0f23092bb 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.6.1", + "version": "1.6.2", "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", @@ -2028,7 +2028,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "type": "string", "x-example": "amazon", @@ -2047,6 +2047,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -2932,7 +2933,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "type": "string", "x-example": "amazon", @@ -2951,6 +2952,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 8fc7e7daf3..634eeb344e 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.6.1", + "version": "1.6.2", "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", @@ -2059,7 +2059,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "type": "string", "x-example": "amazon", @@ -2078,6 +2078,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -2956,7 +2957,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "type": "string", "x-example": "amazon", @@ -2975,6 +2976,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", @@ -19522,8 +19524,7 @@ "default": "default", "x-example": "default", "enum": [ - "default", - "fra" + "default" ], "x-enum-name": null, "x-enum-keys": [] @@ -21351,6 +21352,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 83757c94f4..0c6e48523a 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.6.1", + "version": "1.6.2", "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", @@ -2628,7 +2628,7 @@ "parameters": [ { "name": "provider", - "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", + "description": "OAuth2 Provider. Currently, supported providers are: amazon, apple, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, github, gitlab, google, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, yahoo, yammer, yandex, zoho, zoom.", "required": true, "type": "string", "x-example": "amazon", @@ -2647,6 +2647,7 @@ "dropbox", "etsy", "facebook", + "figma", "github", "gitlab", "google", diff --git a/src/Appwrite/Auth/OAuth2/Figma.php b/src/Appwrite/Auth/OAuth2/Figma.php new file mode 100644 index 0000000000..d6294afd33 --- /dev/null +++ b/src/Appwrite/Auth/OAuth2/Figma.php @@ -0,0 +1,176 @@ + 'code', + 'client_id' => $this->appID, + 'redirect_uri' => $this->callback, + 'scope' => \implode(',', $this->getScopes()), + 'state' => \json_encode($this->state) + ]); + } + + /** + * @param string $code + * + * @return array + */ + protected function getTokens(string $code): array + { + if (empty($this->tokens)) { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://www.figma.com/api/oauth/token', + $headers, + \http_build_query([ + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'redirect_uri' => $this->callback, + 'code' => $code, + 'grant_type' => 'authorization_code' + ]) + ), true); + } + + return $this->tokens; + } + + /** + * @param string $refreshToken + * + * @return array + */ + public function refreshTokens(string $refreshToken): array + { + $headers = ['Content-Type: application/x-www-form-urlencoded']; + $this->tokens = \json_decode($this->request( + 'POST', + 'https://www.figma.com/api/oauth/refresh', + $headers, + \http_build_query([ + 'client_id' => $this->appID, + 'client_secret' => $this->appSecret, + 'refresh_token' => $refreshToken + ]) + ), true); + + if (empty($this->tokens['refresh_token'])) { + $this->tokens['refresh_token'] = $refreshToken; + } + + return $this->tokens; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserID(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['id'] ?? ''; + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserEmail(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['email'] ?? ''; + } + + /** + * Check if the OAuth email is verified + * + * Figma requires email verification during signup, + * so if we have an email, it's verified + * + * @param string $accessToken + * + * @return bool + */ + public function isEmailVerified(string $accessToken): bool + { + $email = $this->getUserEmail($accessToken); + + return !empty($email); + } + + /** + * @param string $accessToken + * + * @return string + */ + public function getUserName(string $accessToken): string + { + $user = $this->getUser($accessToken); + + return $user['handle'] ?? ''; + } + + /** + * @param string $accessToken + * + * @return array + */ + protected function getUser(string $accessToken): array + { + if (empty($this->user)) { + $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $user = $this->request( + 'GET', + 'https://api.figma.com/v1/me', + $headers + ); + $this->user = \json_decode($user, true); + } + + return $this->user; + } +} From 2c453d5fd9156bb3d655de3eca9d1c00a19aed08 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 8 Apr 2025 08:51:04 +0000 Subject: [PATCH 28/29] fix: request issues and permissions --- src/Appwrite/Auth/OAuth2.php | 2 +- src/Appwrite/Auth/OAuth2/Figma.php | 24 +++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/Appwrite/Auth/OAuth2.php b/src/Appwrite/Auth/OAuth2.php index f7dc1d50a1..9358c89547 100644 --- a/src/Appwrite/Auth/OAuth2.php +++ b/src/Appwrite/Auth/OAuth2.php @@ -196,9 +196,9 @@ abstract class OAuth2 if (!empty($payload)) { \curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + $headers[] = 'Content-length: ' . \strlen($payload); } - $headers[] = 'Content-length: ' . \strlen($payload); \curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // Send the request & save response to $response diff --git a/src/Appwrite/Auth/OAuth2/Figma.php b/src/Appwrite/Auth/OAuth2/Figma.php index d6294afd33..b5e53cbed4 100644 --- a/src/Appwrite/Auth/OAuth2/Figma.php +++ b/src/Appwrite/Auth/OAuth2/Figma.php @@ -24,7 +24,7 @@ class Figma extends OAuth2 * @var array */ protected array $scopes = [ - 'file_read' + 'current_user:read' ]; /** @@ -44,7 +44,7 @@ class Figma extends OAuth2 'response_type' => 'code', 'client_id' => $this->appID, 'redirect_uri' => $this->callback, - 'scope' => \implode(',', $this->getScopes()), + 'scope' => \implode(' ', $this->getScopes()), 'state' => \json_encode($this->state) ]); } @@ -57,14 +57,15 @@ class Figma extends OAuth2 protected function getTokens(string $code): array { if (empty($this->tokens)) { - $headers = ['Content-Type: application/x-www-form-urlencoded']; + $headers = [ + 'Content-Type: application/x-www-form-urlencoded', + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret) + ]; $this->tokens = \json_decode($this->request( 'POST', - 'https://www.figma.com/api/oauth/token', + 'https://api.figma.com/v1/oauth/token', $headers, \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, 'redirect_uri' => $this->callback, 'code' => $code, 'grant_type' => 'authorization_code' @@ -82,14 +83,15 @@ class Figma extends OAuth2 */ public function refreshTokens(string $refreshToken): array { - $headers = ['Content-Type: application/x-www-form-urlencoded']; + $headers = [ + 'Content-Type: application/x-www-form-urlencoded', + 'Authorization: Basic ' . \base64_encode($this->appID . ':' . $this->appSecret) + ]; $this->tokens = \json_decode($this->request( 'POST', - 'https://www.figma.com/api/oauth/refresh', + 'https://api.figma.com/v1/oauth/refresh', $headers, \http_build_query([ - 'client_id' => $this->appID, - 'client_secret' => $this->appSecret, 'refresh_token' => $refreshToken ]) ), true); @@ -162,7 +164,7 @@ class Figma extends OAuth2 protected function getUser(string $accessToken): array { if (empty($this->user)) { - $headers = ['Authorization: Bearer ' . \urlencode($accessToken)]; + $headers = ['Authorization: Bearer ' . $accessToken]; $user = $this->request( 'GET', 'https://api.figma.com/v1/me', From badbcaf1a847db4c9c03cd1114716fc6b3e2359a Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Tue, 8 Apr 2025 11:33:38 +0000 Subject: [PATCH 29/29] chore: update dependencies --- composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index 8db4706bb5..68c0c34f1a 100644 --- a/composer.lock +++ b/composer.lock @@ -1365,16 +1365,16 @@ }, { "name": "open-telemetry/sdk", - "version": "1.2.2", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/sdk.git", - "reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0" + "reference": "0e7804c176c4b09d95b7985400aa38ce544cb7fc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/37eec0fe47ddd627911f318f29b6cd48196be0c0", - "reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0", + "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/0e7804c176c4b09d95b7985400aa38ce544cb7fc", + "reference": "0e7804c176c4b09d95b7985400aa38ce544cb7fc", "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-01-29T21:40:28+00:00" + "time": "2025-04-08T09:55:41+00:00" }, { "name": "open-telemetry/sem-conv", @@ -3746,16 +3746,16 @@ }, { "name": "utopia-php/image", - "version": "0.8.1", + "version": "0.8.2", "source": { "type": "git", "url": "https://github.com/utopia-php/image.git", - "reference": "e8cc7dd14f423270a1b7570ec0dae88a66195b63" + "reference": "6c736965177f9a9e71311e22b80cfa88511768e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/image/zipball/e8cc7dd14f423270a1b7570ec0dae88a66195b63", - "reference": "e8cc7dd14f423270a1b7570ec0dae88a66195b63", + "url": "https://api.github.com/repos/utopia-php/image/zipball/6c736965177f9a9e71311e22b80cfa88511768e9", + "reference": "6c736965177f9a9e71311e22b80cfa88511768e9", "shasum": "" }, "require": { @@ -3789,9 +3789,9 @@ ], "support": { "issues": "https://github.com/utopia-php/image/issues", - "source": "https://github.com/utopia-php/image/tree/0.8.1" + "source": "https://github.com/utopia-php/image/tree/0.8.2" }, - "time": "2025-04-04T18:55:20+00:00" + "time": "2025-04-08T11:31:45+00:00" }, { "name": "utopia-php/locale",