From f189c41421ece0f4ae20bfe082316bd2ea977013 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 18 Oct 2024 21:39:16 +0200 Subject: [PATCH 01/24] temp: custom cloudflare hostnames --- .../Platform/Workers/Certificates.php | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 58dc1dd28a..062e9a1bb9 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -22,6 +22,7 @@ use Utopia\Database\Exception\Structure; use Utopia\Database\Helpers\ID; use Utopia\Database\Query; use Utopia\Domains\Domain; +use Utopia\Fetch\Client; use Utopia\Locale\Locale; use Utopia\Logger\Log; use Utopia\Platform\Action; @@ -43,16 +44,18 @@ class Certificates extends Action $this ->desc('Certificates worker') ->inject('message') + ->inject('project') ->inject('dbForConsole') ->inject('queueForMails') ->inject('queueForEvents') ->inject('queueForFunctions') ->inject('log') - ->callback(fn (Message $message, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); + ->callback(fn (Message $message, Document $project, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); } /** * @param Message $message + * @param Document $project * @param Database $dbForConsole * @param Mail $queueForMails * @param Event $queueForEvents @@ -62,7 +65,7 @@ class Certificates extends Action * @throws Throwable * @throws \Utopia\Database\Exception */ - public function action(Message $message, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log): void + public function action(Message $message, Document $project, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log): void { $payload = $message->getPayload() ?? []; @@ -162,6 +165,8 @@ class Certificates extends Action $logs = 'Certificate successfully generated.'; $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB + // TEMP: add custom hostnames to cloudflare + $this->addCustomHostnameToRegistrar($project, $domain->get()); // Give certificates to Traefik $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); @@ -197,6 +202,34 @@ class Certificates extends Action } } + /** + * Add custom hostname to Cloudflare registrar + * + * @param Document $project + * @param string $hostname + * @return void + * @throws Exception + */ + private function addCustomHostnameToRegistrar(Document $project, string $hostname): void + { + $client = new Client(); + $client + ->addHeader('Content-Type', Client::CONTENT_TYPE_APPLICATION_JSON) + ->addHeader('Authorization', 'Bearer ' . System::getEnv('_APP_SYSTEM_CLOUDFLARE_TOKEN')); + + $response = $client->fetch("https://api.cloudflare.com/client/v4/zones/zone_id/custom_hostnames", Client::METHOD_POST, [ + 'custom_metadata' => [ + 'projectId' => $project->getId(), + 'organizationId' => $project->getAttribute('teamId') + ], + 'hostname' => $hostname + ]); + + if ($response->getStatusCode() !== 400) { + throw new Exception('Failed to add custom hostname to Cloudflare: ' . $response->getBody()); + } + } + /** * Save certificate data into database. * From ccbde6c470e9f909ee477eb031c05cf32e6a7350 Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Fri, 18 Oct 2024 21:44:36 +0200 Subject: [PATCH 02/24] fix zone id --- src/Appwrite/Platform/Workers/Certificates.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 062e9a1bb9..a182b37192 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -217,7 +217,7 @@ class Certificates extends Action ->addHeader('Content-Type', Client::CONTENT_TYPE_APPLICATION_JSON) ->addHeader('Authorization', 'Bearer ' . System::getEnv('_APP_SYSTEM_CLOUDFLARE_TOKEN')); - $response = $client->fetch("https://api.cloudflare.com/client/v4/zones/zone_id/custom_hostnames", Client::METHOD_POST, [ + $response = $client->fetch("https://api.cloudflare.com/client/v4/zones/b2d0e62383d3c0f6299efab107af2c7a/custom_hostnames", Client::METHOD_POST, [ 'custom_metadata' => [ 'projectId' => $project->getId(), 'organizationId' => $project->getAttribute('teamId') @@ -225,7 +225,7 @@ class Certificates extends Action 'hostname' => $hostname ]); - if ($response->getStatusCode() !== 400) { + if ($response->getStatusCode() !== 200) { throw new Exception('Failed to add custom hostname to Cloudflare: ' . $response->getBody()); } } From f21b1c87a6c9f8de0760f3e78008dac47a13ce3a Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Fri, 18 Oct 2024 22:07:36 +0200 Subject: [PATCH 03/24] fix missing ssl object --- src/Appwrite/Platform/Workers/Certificates.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index a182b37192..897de6c935 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -222,7 +222,12 @@ class Certificates extends Action 'projectId' => $project->getId(), 'organizationId' => $project->getAttribute('teamId') ], - 'hostname' => $hostname + 'hostname' => $hostname, + 'ssl' => [ + "method" => "http", + "type" => "dv", + "wildcard" => false + ] ]); if ($response->getStatusCode() !== 200) { From 687252b15b879d37e012558601a7c7c937144bcf Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Fri, 18 Oct 2024 22:21:53 +0200 Subject: [PATCH 04/24] fix adding custom hostname & error logging --- src/Appwrite/Platform/Workers/Certificates.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 897de6c935..03cdd596e1 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -50,7 +50,7 @@ class Certificates extends Action ->inject('queueForEvents') ->inject('queueForFunctions') ->inject('log') - ->callback(fn (Message $message, Document $project, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); + ->callback(fn (Message $message, Document $project, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log) => $this->action($message, $project, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log)); } /** @@ -79,7 +79,7 @@ class Certificates extends Action $log->addTag('domain', $domain->get()); - $this->execute($domain, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log, $skipRenewCheck); + $this->execute($domain, $project, $dbForConsole, $queueForMails, $queueForEvents, $queueForFunctions, $log, $skipRenewCheck); } /** @@ -93,7 +93,7 @@ class Certificates extends Action * @throws Throwable * @throws \Utopia\Database\Exception */ - private function execute(Domain $domain, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log, bool $skipRenewCheck = false): void + private function execute(Domain $domain, Document $project, Database $dbForConsole, Mail $queueForMails, Event $queueForEvents, Func $queueForFunctions, Log $log, bool $skipRenewCheck = false): void { /** * 1. Read arguments and validate domain @@ -165,8 +165,12 @@ class Certificates extends Action $logs = 'Certificate successfully generated.'; $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB - // TEMP: add custom hostnames to cloudflare - $this->addCustomHostnameToRegistrar($project, $domain->get()); + try { + // TEMP: add custom hostnames to cloudflare + $this->addCustomHostnameToRegistrar($project, $domain->get()); + } catch (Exception $e) { + Console::error('Failed to add custom hostname to registrar: ' . $e->getMessage()); + } // Give certificates to Traefik $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); From f4d456fa4cf0618765535996b35a6a6f57b649c3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Fri, 18 Oct 2024 20:52:29 +0000 Subject: [PATCH 05/24] chore: updat certs logic --- src/Appwrite/Platform/Workers/Certificates.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 03cdd596e1..1f57daaa42 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -158,9 +158,13 @@ class Certificates extends Action // Prepare folder name for certbot. Using this helps prevent miss-match in LetsEncrypt configuration when renewing certificate $folder = ID::unique(); - // Generate certificate files using Let's Encrypt - $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); - + try { + // Generate certificate files using Let's Encrypt + $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); + } catch (\Throwable $th) { + Console::error('Failed to generate Lets Encrypt certificate'); + } + // Command succeeded, store all data into document $logs = 'Certificate successfully generated.'; $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB @@ -168,8 +172,8 @@ class Certificates extends Action try { // TEMP: add custom hostnames to cloudflare $this->addCustomHostnameToRegistrar($project, $domain->get()); - } catch (Exception $e) { - Console::error('Failed to add custom hostname to registrar: ' . $e->getMessage()); + } catch (\Throwable $th) { + Console::error('Failed to add custom hostname to registrar: ' . $th->getMessage()); } // Give certificates to Traefik From 28b02a4ba863c6640b6f8379074181e693e5ad51 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Fri, 18 Oct 2024 21:18:20 +0000 Subject: [PATCH 06/24] chore: fix bug --- src/Appwrite/Platform/Workers/Certificates.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index 1f57daaa42..cec0706a79 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -160,7 +160,10 @@ class Certificates extends Action try { // Generate certificate files using Let's Encrypt - $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); + $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); + + // Give certificates to Traefik + $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); } catch (\Throwable $th) { Console::error('Failed to generate Lets Encrypt certificate'); } @@ -176,9 +179,6 @@ class Certificates extends Action Console::error('Failed to add custom hostname to registrar: ' . $th->getMessage()); } - // Give certificates to Traefik - $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); - // Update certificate info stored in database $certificate->setAttribute('renewDate', $this->getRenewDate($domain->get())); $certificate->setAttribute('attempts', 0); @@ -222,13 +222,13 @@ class Certificates extends Action { $client = new Client(); $client - ->addHeader('Content-Type', Client::CONTENT_TYPE_APPLICATION_JSON) + ->addHeader('content-type', Client::CONTENT_TYPE_APPLICATION_JSON) ->addHeader('Authorization', 'Bearer ' . System::getEnv('_APP_SYSTEM_CLOUDFLARE_TOKEN')); $response = $client->fetch("https://api.cloudflare.com/client/v4/zones/b2d0e62383d3c0f6299efab107af2c7a/custom_hostnames", Client::METHOD_POST, [ 'custom_metadata' => [ - 'projectId' => $project->getId(), - 'organizationId' => $project->getAttribute('teamId') + 'projectId' => $project->getId() ?? '', + 'organizationId' => $project->getAttribute('teamId', '') ], 'hostname' => $hostname, 'ssl' => [ From 6fe7d92feae728b89473a2af2b4fceddce8030ee Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Fri, 18 Oct 2024 22:32:03 +0000 Subject: [PATCH 07/24] chore: update cert generation --- src/Appwrite/Platform/Workers/Certificates.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index cec0706a79..cf38401351 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -226,10 +226,6 @@ class Certificates extends Action ->addHeader('Authorization', 'Bearer ' . System::getEnv('_APP_SYSTEM_CLOUDFLARE_TOKEN')); $response = $client->fetch("https://api.cloudflare.com/client/v4/zones/b2d0e62383d3c0f6299efab107af2c7a/custom_hostnames", Client::METHOD_POST, [ - 'custom_metadata' => [ - 'projectId' => $project->getId() ?? '', - 'organizationId' => $project->getAttribute('teamId', '') - ], 'hostname' => $hostname, 'ssl' => [ "method" => "http", From 5ea83b882788f9893039e4b9ea4f9b771d4b7892 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Fri, 18 Oct 2024 23:45:42 +0000 Subject: [PATCH 08/24] chore: update cert generation --- src/Appwrite/Platform/Workers/Certificates.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index cf38401351..ddb5130838 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -234,7 +234,7 @@ class Certificates extends Action ] ]); - if ($response->getStatusCode() !== 200) { + if ($response->getStatusCode() !== 201) { throw new Exception('Failed to add custom hostname to Cloudflare: ' . $response->getBody()); } } From a56293e01880c2c7142a63203830bef140e62f9a Mon Sep 17 00:00:00 2001 From: Fabian Gruber Date: Tue, 22 Oct 2024 11:38:05 +0200 Subject: [PATCH 09/24] chore: replace 'Expires' with 'Cache-Control: private' header to avoid CDN caching --- app/controllers/api/avatars.php | 18 +++++++++--------- app/controllers/api/functions.php | 2 +- app/controllers/api/locale.php | 2 +- app/controllers/api/storage.php | 8 ++++---- app/controllers/shared/api.php | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index fcff3e4179..dadd9da5e3 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -55,7 +55,7 @@ $avatarCallback = function (string $type, string $code, int $width, int $height, $output = (empty($output)) ? $type : $output; $data = $image->output($output, $quality); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days ->setContentType('image/png') ->file($data); unset($image); @@ -275,7 +275,7 @@ App::get('/v1/avatars/image') $data = $image->output($output, $quality); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days ->setContentType('image/png') ->file($data); unset($image); @@ -409,7 +409,7 @@ App::get('/v1/avatars/favicon') throw new Exception(Exception::AVATAR_ICON_NOT_FOUND, 'Favicon not found'); } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days ->setContentType('image/x-icon') ->file($data); } @@ -420,7 +420,7 @@ App::get('/v1/avatars/favicon') $data = $image->output($output, $quality); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days ->setContentType('image/png') ->file($data); unset($image); @@ -461,7 +461,7 @@ App::get('/v1/avatars/qr') $image->crop((int) $size, (int) $size); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->setContentType('image/png') ->send($image->output('png', 9)); }); @@ -544,7 +544,7 @@ App::get('/v1/avatars/initials') $image->compositeImage($punch, Imagick::COMPOSITE_COPYOPACITY, 0, 0); $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->setContentType('image/png') ->file($image->getImageBlob()); }); @@ -751,7 +751,7 @@ App::get('/v1/cards/cloud') } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -829,7 +829,7 @@ App::get('/v1/cards/cloud-back') } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); @@ -1219,7 +1219,7 @@ App::get('/v1/cards/cloud-og') } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->setContentType('image/png') ->file($baseImage->getImageBlob()); }); diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index c3051ef476..396d2048f2 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -994,7 +994,7 @@ App::get('/v1/functions/:functionId/deployments/:deploymentId/download') $response ->setContentType('application/gzip') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->addHeader('X-Peak', \memory_get_peak_usage()) ->addHeader('Content-Disposition', 'attachment; filename="' . $deploymentId . '.tar.gz"'); diff --git a/app/controllers/api/locale.php b/app/controllers/api/locale.php index 2917bc8416..1f042d2239 100644 --- a/app/controllers/api/locale.php +++ b/app/controllers/api/locale.php @@ -63,7 +63,7 @@ App::get('/v1/locale') $response ->addHeader('Cache-Control', 'public, max-age=' . $time) - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $time) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ; $response->dynamic(new Document($output), Response::MODEL_LOCALE); }); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index c3d57e5470..5261f9c89a 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -999,7 +999,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + 60 * 60 * 24 * 30) . ' GMT') + ->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days ->setContentType($contentType) ->file($data) ; @@ -1062,7 +1062,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/download') $response ->setContentType($file->getAttribute('mimeType')) - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->addHeader('X-Peak', \memory_get_peak_usage()) ->addHeader('Content-Disposition', 'attachment; filename="' . $file->getAttribute('name', '') . '"') ; @@ -1212,7 +1212,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/view') ->addHeader('Content-Security-Policy', 'script-src none;') ->addHeader('X-Content-Type-Options', 'nosniff') ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->addHeader('X-Peak', \memory_get_peak_usage()) ; @@ -1366,7 +1366,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/push') ->addHeader('Content-Security-Policy', 'script-src none;') ->addHeader('X-Content-Type-Options', 'nosniff') ->addHeader('Content-Disposition', 'inline; filename="' . $file->getAttribute('name', '') . '"') - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + (60 * 60 * 24 * 45)) . ' GMT') // 45 days cache + ->addHeader('Cache-Control', 'private, max-age=3888000') // 45 days ->addHeader('X-Peak', \memory_get_peak_usage()); $size = $file->getAttribute('sizeOriginal', 0); diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f0d896c95a..7a5de8af19 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -508,7 +508,7 @@ App::init() } $response - ->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT') + ->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp)) ->addHeader('X-Appwrite-Cache', 'hit') ->setContentType($cacheLog->getAttribute('mimeType')) ->send($data); @@ -516,7 +516,7 @@ App::init() $response ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate') ->addHeader('Pragma', 'no-cache') - ->addHeader('Expires', 0) + ->addHeader('Expires', '0') ->addHeader('X-Appwrite-Cache', 'miss') ; } From ae4edf119f4f5d12b1d07ed27002e6ced7d3a135 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Tue, 22 Oct 2024 19:49:10 +0000 Subject: [PATCH 10/24] chore: linter --- composer.lock | 24 +++++++++---------- .../Platform/Workers/Certificates.php | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/composer.lock b/composer.lock index 9079512e60..0b83648f74 100644 --- a/composer.lock +++ b/composer.lock @@ -2124,16 +2124,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.12.1", + "version": "0.12.2", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "b9dfafb5efc1d12cbee01d03dc98853ef026e35b" + "reference": "f6790fba1fcee12163d51c65d2c226a7856295d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/b9dfafb5efc1d12cbee01d03dc98853ef026e35b", - "reference": "b9dfafb5efc1d12cbee01d03dc98853ef026e35b", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/f6790fba1fcee12163d51c65d2c226a7856295d9", + "reference": "f6790fba1fcee12163d51c65d2c226a7856295d9", "shasum": "" }, "require": { @@ -2169,9 +2169,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.12.1" + "source": "https://github.com/utopia-php/messaging/tree/0.12.2" }, - "time": "2024-10-09T08:17:07+00:00" + "time": "2024-10-22T01:02:20+00:00" }, { "name": "utopia-php/migration", @@ -2341,16 +2341,16 @@ }, { "name": "utopia-php/platform", - "version": "0.7.0", + "version": "0.7.1", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "beeea0f2c9bce14a6869fc5c87a1047cdecb5c52" + "reference": "3433a0f1a54988f2a59c735f507745cb2c24638a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/beeea0f2c9bce14a6869fc5c87a1047cdecb5c52", - "reference": "beeea0f2c9bce14a6869fc5c87a1047cdecb5c52", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/3433a0f1a54988f2a59c735f507745cb2c24638a", + "reference": "3433a0f1a54988f2a59c735f507745cb2c24638a", "shasum": "" }, "require": { @@ -2385,9 +2385,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.7.0" + "source": "https://github.com/utopia-php/platform/tree/0.7.1" }, - "time": "2024-05-08T17:00:55+00:00" + "time": "2024-10-22T10:27:49+00:00" }, { "name": "utopia-php/pools", diff --git a/src/Appwrite/Platform/Workers/Certificates.php b/src/Appwrite/Platform/Workers/Certificates.php index ddb5130838..c7f72b3e3c 100644 --- a/src/Appwrite/Platform/Workers/Certificates.php +++ b/src/Appwrite/Platform/Workers/Certificates.php @@ -160,14 +160,14 @@ class Certificates extends Action try { // Generate certificate files using Let's Encrypt - $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); + $letsEncryptData = $this->issueCertificate($folder, $domain->get(), $email); // Give certificates to Traefik $this->applyCertificateFiles($folder, $domain->get(), $letsEncryptData); } catch (\Throwable $th) { Console::error('Failed to generate Lets Encrypt certificate'); } - + // Command succeeded, store all data into document $logs = 'Certificate successfully generated.'; $certificate->setAttribute('logs', \mb_strcut($logs, 0, 1000000));// Limit to 1MB From cca0c3ae45864421295b3b48d41998ff36e6680c Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 5 Nov 2024 12:59:11 +0545 Subject: [PATCH 11/24] Make compression param whitelist strict --- app/controllers/api/storage.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index dda39a0db0..ed10c84912 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -68,7 +68,7 @@ App::post('/v1/storage/buckets') ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) ->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan']) ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) - ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) + ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD], true), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') From 028c5366c20b9a88699f88cdf72d1f4627dd9d1e Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 5 Nov 2024 08:12:58 +0000 Subject: [PATCH 12/24] make compression nullable and assign default in action - also update the `update bucket` endpoint --- app/controllers/api/storage.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index ed10c84912..911481a1c0 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -74,13 +74,13 @@ App::post('/v1/storage/buckets') ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, int $maximumFileSize, array $allowedFileExtensions, ?string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { $bucketId = $bucketId === 'unique()' ? ID::unique() : $bucketId; // Map aggregate permissions into the multiple permissions they represent. $permissions = Permission::aggregate($permissions); - + $compression ??= Compression::NONE; try { $files = (Config::getParam('collections', [])['buckets'] ?? [])['files'] ?? []; if (empty($files)) { @@ -254,13 +254,13 @@ App::put('/v1/storage/buckets/:bucketId') ->param('enabled', true, new Boolean(true), 'Is bucket enabled? When set to \'disabled\', users cannot access the files in this bucket but Server SDKs with and API key can still access the bucket. No files are lost when this is toggled.', true) ->param('maximumFileSize', fn (array $plan) => empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000, fn (array $plan) => new Range(1, empty($plan['fileSize']) ? (int) System::getEnv('_APP_STORAGE_LIMIT', 0) : $plan['fileSize'] * 1000 * 1000), 'Maximum file size allowed in bytes. Maximum allowed value is ' . Storage::human(System::getEnv('_APP_STORAGE_LIMIT', 0), 0) . '.', true, ['plan']) ->param('allowedFileExtensions', [], new ArrayList(new Text(64), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Allowed file extensions. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' extensions are allowed, each 64 characters long.', true) - ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD]), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) + ->param('compression', Compression::NONE, new WhiteList([Compression::NONE, Compression::GZIP, Compression::ZSTD], true), 'Compression algorithm choosen for compression. Can be one of ' . Compression::NONE . ', [' . Compression::GZIP . '](https://en.wikipedia.org/wiki/Gzip), or [' . Compression::ZSTD . '](https://en.wikipedia.org/wiki/Zstd), For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' compression is skipped even if it\'s enabled', true) ->param('encryption', true, new Boolean(true), 'Is encryption enabled? For file size above ' . Storage::human(APP_STORAGE_READ_BUFFER, 0) . ' encryption is skipped even if it\'s enabled', true) ->param('antivirus', true, new Boolean(true), 'Is virus scanning enabled? For file size above ' . Storage::human(APP_LIMIT_ANTIVIRUS, 0) . ' AntiVirus scanning is skipped even if it\'s enabled', true) ->inject('response') ->inject('dbForProject') ->inject('queueForEvents') - ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { + ->action(function (string $bucketId, string $name, ?array $permissions, bool $fileSecurity, bool $enabled, ?int $maximumFileSize, array $allowedFileExtensions, ?string $compression, bool $encryption, bool $antivirus, Response $response, Database $dbForProject, Event $queueForEvents) { $bucket = $dbForProject->getDocument('buckets', $bucketId); if ($bucket->isEmpty()) { @@ -273,6 +273,7 @@ App::put('/v1/storage/buckets/:bucketId') $enabled ??= $bucket->getAttribute('enabled', true); $encryption ??= $bucket->getAttribute('encryption', true); $antivirus ??= $bucket->getAttribute('antivirus', true); + $compression ??= $bucket->getAttribute('compression', Compression::NONE); // Map aggregate permissions into the multiple permissions they represent. $permissions = Permission::aggregate($permissions); From e219ee2d842317fc6200a5556307eadcb5db6fdd Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 6 Nov 2024 10:02:11 +0000 Subject: [PATCH 13/24] upgrade utopia storage --- composer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index 6dce436601..39f5753510 100644 --- a/composer.lock +++ b/composer.lock @@ -2608,16 +2608,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.5", + "version": "0.18.6", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "7d355c5e3ccc8ecebc0266f8ddd30088a43be919" + "reference": "893ccf06e183f8ece2aed8dbf14d64d6ba036071" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/7d355c5e3ccc8ecebc0266f8ddd30088a43be919", - "reference": "7d355c5e3ccc8ecebc0266f8ddd30088a43be919", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/893ccf06e183f8ece2aed8dbf14d64d6ba036071", + "reference": "893ccf06e183f8ece2aed8dbf14d64d6ba036071", "shasum": "" }, "require": { @@ -2657,9 +2657,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.5" + "source": "https://github.com/utopia-php/storage/tree/0.18.6" }, - "time": "2024-09-04T08:57:27+00:00" + "time": "2024-11-06T09:58:50+00:00" }, { "name": "utopia-php/swoole", @@ -5875,16 +5875,16 @@ }, { "name": "symfony/console", - "version": "v7.1.6", + "version": "v7.1.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57" + "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/bb5192af6edc797cbab5c8e8ecfea2fe5f421e57", - "reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57", + "url": "https://api.github.com/repos/symfony/console/zipball/3284aafcac338b6e86fd955ee4d794cbe434151a", + "reference": "3284aafcac338b6e86fd955ee4d794cbe434151a", "shasum": "" }, "require": { @@ -5948,7 +5948,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.1.6" + "source": "https://github.com/symfony/console/tree/v7.1.7" }, "funding": [ { @@ -5964,7 +5964,7 @@ "type": "tidelift" } ], - "time": "2024-10-09T08:46:59+00:00" + "time": "2024-11-05T15:34:55+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6546,16 +6546,16 @@ }, { "name": "symfony/process", - "version": "v7.1.6", + "version": "v7.1.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e" + "reference": "9b8a40b7289767aa7117e957573c2a535efe6585" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e", - "reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e", + "url": "https://api.github.com/repos/symfony/process/zipball/9b8a40b7289767aa7117e957573c2a535efe6585", + "reference": "9b8a40b7289767aa7117e957573c2a535efe6585", "shasum": "" }, "require": { @@ -6587,7 +6587,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.1.6" + "source": "https://github.com/symfony/process/tree/v7.1.7" }, "funding": [ { @@ -6603,7 +6603,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:20:29+00:00" + "time": "2024-11-06T09:25:12+00:00" }, { "name": "symfony/service-contracts", From a6779caa5ebf0eca8a080061fca91931a1e9842b Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 7 Nov 2024 14:28:39 +0200 Subject: [PATCH 14/24] Trigger sentry --- src/Appwrite/Platform/Workers/Databases.php | 24 ++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index f697e7be13..1974a0b959 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -92,6 +92,7 @@ class Databases extends Action * @throws Authorization * @throws Conflict * @throws \Exception + * @throws \Throwable */ private function createAttribute(Document $database, Document $collection, Document $attribute, Document $project, Database $dbForConsole, Database $dbForProject): void { @@ -134,7 +135,6 @@ class Databases extends Action $options = $attribute->getAttribute('options', []); $project = $dbForConsole->getDocument('projects', $projectId); - try { switch ($type) { case Database::VAR_RELATIONSHIP: @@ -170,7 +170,6 @@ class Databases extends Action $dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available')); } catch (\Throwable $e) { - // TODO: Send non DatabaseExceptions to Sentry Console::error($e->getMessage()); if ($e instanceof DatabaseException) { @@ -193,6 +192,9 @@ class Databases extends Action $relatedAttribute->setAttribute('status', 'failed') ); } + + // TODO: Send non DatabaseExceptions to Sentry + throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); } @@ -215,6 +217,7 @@ class Databases extends Action * @throws Authorization * @throws Conflict * @throws \Exception + * @throws \Throwable **/ private function deleteAttribute(Document $database, Document $collection, Document $attribute, Document $project, Database $dbForConsole, Database $dbForProject): void { @@ -273,7 +276,6 @@ class Databases extends Action $dbForProject->deleteDocument('attributes', $relatedAttribute->getId()); } } catch (\Throwable $e) { - // TODO: Send non DatabaseExceptions to Sentry Console::error($e->getMessage()); if ($e instanceof DatabaseException) { @@ -294,6 +296,9 @@ class Databases extends Action $relatedAttribute->setAttribute('status', 'stuck') ); } + + // TODO: Send non DatabaseExceptions to Sentry + throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); } @@ -370,6 +375,7 @@ class Databases extends Action * @throws Conflict * @throws Structure * @throws DatabaseException + * @throws \Throwable */ private function createIndex(Document $database, Document $collection, Document $index, Document $project, Database $dbForConsole, Database $dbForProject): void { @@ -401,7 +407,7 @@ class Databases extends Action } $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available')); } catch (\Throwable $e) { - // TODO: Send non DatabaseExceptions to Sentry + Console::error($e->getMessage()); if ($e instanceof DatabaseException) { @@ -412,6 +418,9 @@ class Databases extends Action $index->getId(), $index->setAttribute('status', 'failed') ); + + // TODO: Send non DatabaseExceptions to Sentry + throw $e; } finally { $this->trigger($database, $collection, $index, $project, $projectId, $events); } @@ -431,6 +440,7 @@ class Databases extends Action * @throws Conflict * @throws Structure * @throws DatabaseException + * @throws \Throwable */ private function deleteIndex(Document $database, Document $collection, Document $index, Document $project, Database $dbForConsole, Database $dbForProject): void { @@ -459,7 +469,6 @@ class Databases extends Action $dbForProject->deleteDocument('indexes', $index->getId()); $index->setAttribute('status', 'deleted'); } catch (\Throwable $e) { - // TODO: Send non DatabaseExceptions to Sentry Console::error($e->getMessage()); if ($e instanceof DatabaseException) { @@ -470,10 +479,15 @@ class Databases extends Action $index->getId(), $index->setAttribute('status', 'stuck') ); + + // TODO: Send non DatabaseExceptions to Sentry ? + throw $e; + } finally { $this->trigger($database, $collection, $index, $project, $projectId, $events); } + // Do we want this in finally? $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collection->getId()); } From 19667f78a92e00fa203a7a35bd4f4f13e2175851 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 7 Nov 2024 17:23:46 +0200 Subject: [PATCH 15/24] Add try catch on delete Attribute --- src/Appwrite/Platform/Workers/Databases.php | 180 ++++++++++---------- 1 file changed, 90 insertions(+), 90 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 1974a0b959..388dd3b88c 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -251,115 +251,118 @@ class Databases extends Action // - stuck: attribute was available but cannot be removed try { - if ($status !== 'failed') { - if ($type === Database::VAR_RELATIONSHIP) { - if ($options['twoWay']) { - $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); - if ($relatedCollection->isEmpty()) { - throw new DatabaseException('Collection not found'); + try { + if ($status !== 'failed') { + if ($type === Database::VAR_RELATIONSHIP) { + if ($options['twoWay']) { + $relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']); + if ($relatedCollection->isEmpty()) { + throw new DatabaseException('Collection not found'); + } + $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); } - $relatedAttribute = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $relatedCollection->getInternalId() . '_' . $options['twoWayKey']); - } - if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { - $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck')); - throw new DatabaseException('Failed to delete Relationship'); + if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { + $dbForProject->updateDocument('attributes', $relatedAttribute->getId(), $relatedAttribute->setAttribute('status', 'stuck')); + throw new DatabaseException('Failed to delete Relationship'); + } + } elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { + throw new DatabaseException('Failed to delete Attribute'); } - } elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) { - throw new DatabaseException('Failed to delete Attribute'); } - } - $dbForProject->deleteDocument('attributes', $attribute->getId()); + $dbForProject->deleteDocument('attributes', $attribute->getId()); - if (!$relatedAttribute->isEmpty()) { - $dbForProject->deleteDocument('attributes', $relatedAttribute->getId()); - } - } catch (\Throwable $e) { - Console::error($e->getMessage()); - - if ($e instanceof DatabaseException) { - $attribute->setAttribute('error', $e->getMessage()); if (!$relatedAttribute->isEmpty()) { - $relatedAttribute->setAttribute('error', $e->getMessage()); + $dbForProject->deleteDocument('attributes', $relatedAttribute->getId()); + } + } catch (\Throwable $e) { + Console::error($e->getMessage()); + + if ($e instanceof DatabaseException) { + $attribute->setAttribute('error', $e->getMessage()); + if (!$relatedAttribute->isEmpty()) { + $relatedAttribute->setAttribute('error', $e->getMessage()); + } } - } - $dbForProject->updateDocument( - 'attributes', - $attribute->getId(), - $attribute->setAttribute('status', 'stuck') - ); - if (!$relatedAttribute->isEmpty()) { $dbForProject->updateDocument( 'attributes', - $relatedAttribute->getId(), - $relatedAttribute->setAttribute('status', 'stuck') + $attribute->getId(), + $attribute->setAttribute('status', 'stuck') ); + if (!$relatedAttribute->isEmpty()) { + $dbForProject->updateDocument( + 'attributes', + $relatedAttribute->getId(), + $relatedAttribute->setAttribute('status', 'stuck') + ); + } + + // TODO: Send non DatabaseExceptions to Sentry + throw $e; + } finally { + $this->trigger($database, $collection, $attribute, $project, $projectId, $events); } - // TODO: Send non DatabaseExceptions to Sentry - throw $e; - } finally { - $this->trigger($database, $collection, $attribute, $project, $projectId, $events); - } + // The underlying database removes/rebuilds indexes when attribute is removed + // Update indexes table with changes + /** @var Document[] $indexes */ + $indexes = $collection->getAttribute('indexes', []); - // The underlying database removes/rebuilds indexes when attribute is removed - // Update indexes table with changes - /** @var Document[] $indexes */ - $indexes = $collection->getAttribute('indexes', []); + foreach ($indexes as $index) { + /** @var string[] $attributes */ + $attributes = $index->getAttribute('attributes'); + $lengths = $index->getAttribute('lengths'); + $orders = $index->getAttribute('orders'); - foreach ($indexes as $index) { - /** @var string[] $attributes */ - $attributes = $index->getAttribute('attributes'); - $lengths = $index->getAttribute('lengths'); - $orders = $index->getAttribute('orders'); + $found = \array_search($key, $attributes); - $found = \array_search($key, $attributes); + if ($found !== false) { + // If found, remove entry from attributes, lengths, and orders + // array_values wraps array_diff to reindex array keys + // when found attribute is removed from array + $attributes = \array_values(\array_diff($attributes, [$attributes[$found]])); + $lengths = \array_values(\array_diff($lengths, isset($lengths[$found]) ? [$lengths[$found]] : [])); + $orders = \array_values(\array_diff($orders, isset($orders[$found]) ? [$orders[$found]] : [])); - if ($found !== false) { - // If found, remove entry from attributes, lengths, and orders - // array_values wraps array_diff to reindex array keys - // when found attribute is removed from array - $attributes = \array_values(\array_diff($attributes, [$attributes[$found]])); - $lengths = \array_values(\array_diff($lengths, isset($lengths[$found]) ? [$lengths[$found]] : [])); - $orders = \array_values(\array_diff($orders, isset($orders[$found]) ? [$orders[$found]] : [])); - - if (empty($attributes)) { - $dbForProject->deleteDocument('indexes', $index->getId()); - } else { - $index - ->setAttribute('attributes', $attributes, Document::SET_TYPE_ASSIGN) - ->setAttribute('lengths', $lengths, Document::SET_TYPE_ASSIGN) - ->setAttribute('orders', $orders, Document::SET_TYPE_ASSIGN); - - // Check if an index exists with the same attributes and orders - $exists = false; - foreach ($indexes as $existing) { - if ( - $existing->getAttribute('key') !== $index->getAttribute('key') // Ignore itself - && $existing->getAttribute('attributes') === $index->getAttribute('attributes') - && $existing->getAttribute('orders') === $index->getAttribute('orders') - ) { - $exists = true; - break; - } - } - - if ($exists) { // Delete the duplicate if created, else update in db - $this->deleteIndex($database, $collection, $index, $project, $dbForConsole, $dbForProject); + if (empty($attributes)) { + $dbForProject->deleteDocument('indexes', $index->getId()); } else { - $dbForProject->updateDocument('indexes', $index->getId(), $index); + $index + ->setAttribute('attributes', $attributes, Document::SET_TYPE_ASSIGN) + ->setAttribute('lengths', $lengths, Document::SET_TYPE_ASSIGN) + ->setAttribute('orders', $orders, Document::SET_TYPE_ASSIGN); + + // Check if an index exists with the same attributes and orders + $exists = false; + foreach ($indexes as $existing) { + if ( + $existing->getAttribute('key') !== $index->getAttribute('key') // Ignore itself + && $existing->getAttribute('attributes') === $index->getAttribute('attributes') + && $existing->getAttribute('orders') === $index->getAttribute('orders') + ) { + $exists = true; + break; + } + } + + if ($exists) { // Delete the duplicate if created, else update in db + $this->deleteIndex($database, $collection, $index, $project, $dbForConsole, $dbForProject); + } else { + $dbForProject->updateDocument('indexes', $index->getId(), $index); + } } } } - } - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); - $dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); + } finally { + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); + $dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); - if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) { - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); - $dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + if (!$relatedCollection->isEmpty() && !$relatedAttribute->isEmpty()) { + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + $dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); + } } } @@ -480,15 +483,12 @@ class Databases extends Action $index->setAttribute('status', 'stuck') ); - // TODO: Send non DatabaseExceptions to Sentry ? throw $e; } finally { $this->trigger($database, $collection, $index, $project, $projectId, $events); + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collection->getId()); } - - // Do we want this in finally? - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collection->getId()); } /** From cd0d1d94dbb56936091d07cd380180e4b857562d Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 7 Nov 2024 17:27:56 +0200 Subject: [PATCH 16/24] Add to finally --- src/Appwrite/Platform/Workers/Databases.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 388dd3b88c..8c26ca6cea 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -197,13 +197,12 @@ class Databases extends Action throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); - } + if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + } - if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); } - - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); } /** @@ -426,9 +425,9 @@ class Databases extends Action throw $e; } finally { $this->trigger($database, $collection, $index, $project, $projectId, $events); + $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); } - $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); } /** From fb40970eba10f55596db980d89f0e1598d71ab43 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 7 Nov 2024 17:35:03 +0200 Subject: [PATCH 17/24] line --- src/Appwrite/Platform/Workers/Databases.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 8c26ca6cea..01f73018f4 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -197,6 +197,7 @@ class Databases extends Action throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); + if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) { $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $relatedCollection->getId()); } From 06274764c645a7678e071fc17fa8512b4e206a75 Mon Sep 17 00:00:00 2001 From: fogelito Date: Fri, 8 Nov 2024 07:12:23 +0200 Subject: [PATCH 18/24] Remove extra lines --- src/Appwrite/Platform/Workers/Databases.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 01f73018f4..7cff9f264a 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -354,7 +354,6 @@ class Databases extends Action } } } - } finally { $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); $dbForProject->purgeCachedCollection('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId()); @@ -410,10 +409,14 @@ class Databases extends Action } $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available')); } catch (\Throwable $e) { - Console::error($e->getMessage()); - + Console::error('shmuel::createIndex'); if ($e instanceof DatabaseException) { + Console::error('shmuel::createIndex' . $e->getMessage()); + Console::error('shmuel::createIndex' . $e->getMessage()); + Console::error('shmuel::createIndex' . $e->getMessage()); + Console::error('shmuel::createIndex' . $e->getMessage()); + Console::error('shmuel::createIndex' . $e->getMessage()); $index->setAttribute('error', $e->getMessage()); } $dbForProject->updateDocument( @@ -428,7 +431,6 @@ class Databases extends Action $this->trigger($database, $collection, $index, $project, $projectId, $events); $dbForProject->purgeCachedDocument('database_' . $database->getInternalId(), $collectionId); } - } /** From 627df0d11fc403e2d084dd9746f24b6e4eb46edf Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 8 Nov 2024 20:24:55 +0100 Subject: [PATCH 19/24] chore: remove redundant compression --- app/http.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/http.php b/app/http.php index 641143694d..b9e3552efd 100644 --- a/app/http.php +++ b/app/http.php @@ -60,8 +60,6 @@ include __DIR__ . '/controllers/general.php'; $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $register) { $app = new App('UTC'); - $app->setCompression(true); - $app->setCompressionMinSize(intval(System::getEnv('_APP_COMPRESSION_MIN_SIZE_BYTES', '1024'))); // 1KB go(function () use ($register, $app) { $pools = $register->get('pools'); From 2f9b44930f7c8a7b1460ed7c9d304c625a77b0a1 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 8 Nov 2024 21:48:27 +0100 Subject: [PATCH 20/24] Revert "Merge pull request #8946 from appwrite/chore-update-database" This reverts commit c0bd1664be78456a57e766205c902d4f3740fe8a, reversing changes made to b42dd86451ac5bd23e46747fb158c990f4596b74. --- app/config/errors.php | 2 +- app/controllers/api/databases.php | 6 ++--- composer.json | 2 +- composer.lock | 26 +++++++++---------- .../Databases/DatabasesCustomServerTest.php | 2 +- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/config/errors.php b/app/config/errors.php index f09d1596eb..3afec4faaf 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -686,7 +686,7 @@ return [ ], Exception::ATTRIBUTE_LIMIT_EXCEEDED => [ 'name' => Exception::ATTRIBUTE_LIMIT_EXCEEDED, - 'description' => 'The maximum number or size of attributes for this collection has been reached.', + 'description' => 'The maximum number of attributes has been reached.', 'code' => 400, ], Exception::ATTRIBUTE_VALUE_INVALID => [ diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index dcf5bbffa5..0114fd343c 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -153,7 +153,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att } catch (DuplicateException) { throw new Exception(Exception::ATTRIBUTE_ALREADY_EXISTS); } catch (LimitException) { - throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED); + throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Throwable $e) { $dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $collectionId); $dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $collection->getInternalId()); @@ -197,7 +197,7 @@ function createAttribute(string $databaseId, string $collectionId, Document $att throw new Exception(Exception::ATTRIBUTE_ALREADY_EXISTS); } catch (LimitException) { $dbForProject->deleteDocument('attributes', $attribute->getId()); - throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED); + throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute limit exceeded'); } catch (\Throwable $e) { $dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedCollection->getId()); $dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedCollection->getInternalId()); @@ -393,8 +393,6 @@ function updateAttribute( throw new Exception(Exception::ATTRIBUTE_INVALID_RESIZE); } catch (NotFoundException) { throw new Exception(Exception::ATTRIBUTE_NOT_FOUND); - } catch (LimitException) { - throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED); } } diff --git a/composer.json b/composer.json index 5c2441fd1b..a04ca51d43 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.11.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.53.19", + "utopia-php/database": "0.53.16", "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 097cee9868..2724542a38 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": "5be1b916c221b97b77b0e7f14491aabf", + "content-hash": "b358198535c1867eabed7c0f99135a57", "packages": [ { "name": "adhocore/jwt", @@ -1770,16 +1770,16 @@ }, { "name": "utopia-php/database", - "version": "0.53.19", + "version": "0.53.16", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "48951885f2787df30ad8581a0e94423558619daa" + "reference": "6661edffeef05b59e16d102b989a72f7f78cf7de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/48951885f2787df30ad8581a0e94423558619daa", - "reference": "48951885f2787df30ad8581a0e94423558619daa", + "url": "https://api.github.com/repos/utopia-php/database/zipball/6661edffeef05b59e16d102b989a72f7f78cf7de", + "reference": "6661edffeef05b59e16d102b989a72f7f78cf7de", "shasum": "" }, "require": { @@ -1820,9 +1820,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.53.19" + "source": "https://github.com/utopia-php/database/tree/0.53.16" }, - "time": "2024-11-08T07:00:24+00:00" + "time": "2024-11-06T03:07:16+00:00" }, { "name": "utopia-php/domains", @@ -6923,16 +6923,16 @@ }, { "name": "twig/twig", - "version": "v3.14.2", + "version": "v3.14.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a" + "reference": "f405356d20fb43603bcadc8b09bfb676cb04a379" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", - "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/f405356d20fb43603bcadc8b09bfb676cb04a379", + "reference": "f405356d20fb43603bcadc8b09bfb676cb04a379", "shasum": "" }, "require": { @@ -6986,7 +6986,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.2" + "source": "https://github.com/twigphp/Twig/tree/v3.14.1" }, "funding": [ { @@ -6998,7 +6998,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T12:36:22+00:00" + "time": "2024-11-06T18:17:38+00:00" }, { "name": "webmozart/glob", diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index b501e2119e..7cb8adb815 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -1362,7 +1362,7 @@ class DatabasesCustomServerTest extends Scope ]); $this->assertEquals(400, $tooWide['headers']['status-code']); - $this->assertEquals('attribute_limit_exceeded', $tooWide['body']['type']); + $this->assertEquals('Attribute limit exceeded', $tooWide['body']['message']); } public function testIndexLimitException() From f6de25622008ad9510a553cfc8969f41b0ab39a3 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 8 Nov 2024 21:50:33 +0100 Subject: [PATCH 21/24] chore: composer update --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 2724542a38..828153a153 100644 --- a/composer.lock +++ b/composer.lock @@ -6923,16 +6923,16 @@ }, { "name": "twig/twig", - "version": "v3.14.1", + "version": "v3.14.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "f405356d20fb43603bcadc8b09bfb676cb04a379" + "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/f405356d20fb43603bcadc8b09bfb676cb04a379", - "reference": "f405356d20fb43603bcadc8b09bfb676cb04a379", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", + "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", "shasum": "" }, "require": { @@ -6986,7 +6986,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.1" + "source": "https://github.com/twigphp/Twig/tree/v3.14.2" }, "funding": [ { @@ -6998,7 +6998,7 @@ "type": "tidelift" } ], - "time": "2024-11-06T18:17:38+00:00" + "time": "2024-11-07T12:36:22+00:00" }, { "name": "webmozart/glob", From e5730506ebf5c8f8cda94434d89b3d9013c0b66d Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 10 Nov 2024 16:37:44 +0200 Subject: [PATCH 22/24] Remove var dumps --- src/Appwrite/Platform/Workers/Databases.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index 7cff9f264a..accc003976 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -410,13 +410,7 @@ class Databases extends Action $dbForProject->updateDocument('indexes', $index->getId(), $index->setAttribute('status', 'available')); } catch (\Throwable $e) { Console::error($e->getMessage()); - Console::error('shmuel::createIndex'); if ($e instanceof DatabaseException) { - Console::error('shmuel::createIndex' . $e->getMessage()); - Console::error('shmuel::createIndex' . $e->getMessage()); - Console::error('shmuel::createIndex' . $e->getMessage()); - Console::error('shmuel::createIndex' . $e->getMessage()); - Console::error('shmuel::createIndex' . $e->getMessage()); $index->setAttribute('error', $e->getMessage()); } $dbForProject->updateDocument( From d9e2ecff54fba52489e393ea5168a1d908d968f8 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Mon, 11 Nov 2024 16:45:17 +0900 Subject: [PATCH 23/24] Remove get document from worker --- src/Appwrite/Platform/Workers/Migrations.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index d430d0eb67..4b1926ed26 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -268,8 +268,6 @@ class Migrations extends Action $transfer = $source = $destination = null; try { - $migration = $this->dbForProject->getDocument('migrations', $migration->getId()); - if ( $migration->getAttribute('source') === SourceAppwrite::getName() && empty($migration->getAttribute('credentials', [])) From 8cca88f2b8180944e0fb2a8170d431047de0805c Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 11 Nov 2024 18:52:15 +0200 Subject: [PATCH 24/24] Remove Sentry comment --- src/Appwrite/Platform/Workers/Databases.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Appwrite/Platform/Workers/Databases.php b/src/Appwrite/Platform/Workers/Databases.php index accc003976..fe81114ea0 100644 --- a/src/Appwrite/Platform/Workers/Databases.php +++ b/src/Appwrite/Platform/Workers/Databases.php @@ -193,7 +193,6 @@ class Databases extends Action ); } - // TODO: Send non DatabaseExceptions to Sentry throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); @@ -298,7 +297,6 @@ class Databases extends Action ); } - // TODO: Send non DatabaseExceptions to Sentry throw $e; } finally { $this->trigger($database, $collection, $attribute, $project, $projectId, $events); @@ -419,7 +417,6 @@ class Databases extends Action $index->setAttribute('status', 'failed') ); - // TODO: Send non DatabaseExceptions to Sentry throw $e; } finally { $this->trigger($database, $collection, $index, $project, $projectId, $events);