From 6996cc28a0a607a8bc8a47ef69bff915c83f4b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 24 Jun 2025 14:47:47 +0200 Subject: [PATCH 01/15] Fix logs order --- .../Modules/Functions/Workers/Builds.php | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 8ff1690da9..7fe5e77114 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -845,11 +845,6 @@ class Builds extends Action $logs = \substr($logs, 0, $separator); } - if ($resource->getCollection() === 'sites') { - $date = \date('H:i:s'); - $logs .= "[$date] [appwrite] Screenshot capturing started. \n"; - } - $deployment->setAttribute('buildLogs', $logs); if ($resource->getCollection() === 'sites' && !empty($detectionLogs)) { @@ -877,16 +872,24 @@ class Builds extends Action } } - $deployment->setAttribute('buildLogs', $logs); - - $this->afterBuildSuccess($dbForProject, $deployment); - $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); - $queueForRealtime ->setPayload($deployment->getArrayCopy()) ->trigger(); + + $this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment); + + if ($resource->getCollection() === 'sites') { + $date = \date('H:i:s'); + $logs .= "[$date] [appwrite] Screenshot capturing started. \n"; + $deployment->setAttribute('buildLogs', $logs); + $deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment); + $queueForRealtime + ->setPayload($deployment->getArrayCopy()) + ->trigger(); + } + /** Screenshot site */ if ($resource->getCollection() === 'sites') { try { @@ -1319,12 +1322,14 @@ class Builds extends Action /** * Hook to run after build success * + * @param Realtime $queueForRealtime * @param Database $dbForProject * @param Document $deployment * @return void */ - protected function afterBuildSuccess(Database $dbForProject, Document &$deployment): void + protected function afterBuildSuccess(Realtime $queueForRealtime, Database $dbForProject, Document &$deployment): void { + assert($queueForRealtime instanceof Realtime); assert($dbForProject instanceof Database); assert($deployment instanceof Document); } From 5dcc50887047a4e8a2723f77028a2bb8fdae45d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 24 Jun 2025 15:38:39 +0200 Subject: [PATCH 02/15] Fix logs parsing --- .../Platform/Modules/Functions/Workers/Builds.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 7fe5e77114..725cc89510 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -838,11 +838,9 @@ class Builds extends Action $detectionLogs = ''; $separator = \strpos($logs, '{APPWRITE_DETECTION_SEPARATOR_START}'); if ($separator !== false) { - $detectionLogs = \substr($logs, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR}')); - $separatorEnd = \strpos($detectionLogs, '{APPWRITE_DETECTION_SEPARATOR_END}'); - $logs .= \substr($detectionLogs, $separatorEnd + strlen('{APPWRITE_DETECTION_SEPARATOR_END}')); - $detectionLogs = \substr($detectionLogs, 0, $separatorEnd); - $logs = \substr($logs, 0, $separator); + [$logsBefore, $detectionLogsStart] = \explode('{APPWRITE_DETECTION_SEPARATOR_START}', $logs, 2); + [$detectionLogs, $logsAfter] = \explode('{APPWRITE_DETECTION_SEPARATOR_END}', $detectionLogsStart, 2); + $logs = $logsBefore . $logsAfter; } $deployment->setAttribute('buildLogs', $logs); @@ -877,7 +875,6 @@ class Builds extends Action ->setPayload($deployment->getArrayCopy()) ->trigger(); - $this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment); if ($resource->getCollection() === 'sites') { From b5bc240c0dc73a27d9b4e032ea362210bd733a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 24 Jun 2025 15:56:06 +0200 Subject: [PATCH 03/15] Fix ssr separation; add edge debugging logs --- .../Modules/Functions/Workers/Builds.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 725cc89510..1338ebdd73 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -747,6 +747,13 @@ class Builds extends Action if ($separator !== false) { $logs = \substr($logs, 0, $separator); $insideSeparation = true; + + $leftover = \substr($logs, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_START}')); + $separator = \strpos($leftover, '{APPWRITE_DETECTION_SEPARATOR_END}'); + if ($separator !== false) { + $logs .= \substr($leftover, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_END}')); + $insideSeparation = false; + } } } else { $separator = \strpos($logs, '{APPWRITE_DETECTION_SEPARATOR_END}'); @@ -836,11 +843,10 @@ class Builds extends Action // Separate logs for SSR detection $detectionLogs = ''; - $separator = \strpos($logs, '{APPWRITE_DETECTION_SEPARATOR_START}'); - if ($separator !== false) { + if (\str_contains($logs, '{APPWRITE_DETECTION_SEPARATOR_START}')) { [$logsBefore, $detectionLogsStart] = \explode('{APPWRITE_DETECTION_SEPARATOR_START}', $logs, 2); [$detectionLogs, $logsAfter] = \explode('{APPWRITE_DETECTION_SEPARATOR_END}', $detectionLogsStart, 2); - $logs = $logsBefore . $logsAfter; + $logs = ($logsBefore ?? '') . ($logsAfter ?? ''); } $deployment->setAttribute('buildLogs', $logs); @@ -877,6 +883,10 @@ class Builds extends Action $this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment); + \var_dump("After edge finish:"); + \var_dump($deployment); + \var_dump('---'); + if ($resource->getCollection() === 'sites') { $date = \date('H:i:s'); $logs .= "[$date] [appwrite] Screenshot capturing started. \n"; @@ -1225,12 +1235,8 @@ class Builds extends Action $message = "" . $message; } - $separator = \strpos($message, '{APPWRITE_DETECTION_SEPARATOR_START}'); - if ($separator !== false) { - $error = \substr($message, $separator + strlen('{APPWRITE_DETECTION_SEPARATOR_START}')); - $message = \substr($message, 0, $separator); - $message .= "\n" . $error; - } + $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_START}', '', $message, 1); + $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_END}', '', $message, 1); // Combine with previous logs if deployment got past build process $previousLogs = ''; From c04c2d271c1f2462e5207289afa52b36cf53b1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Tue, 24 Jun 2025 16:03:28 +0200 Subject: [PATCH 04/15] Remove logs, fix edge logs missing --- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 1338ebdd73..b086bd402e 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -882,10 +882,7 @@ class Builds extends Action ->trigger(); $this->afterBuildSuccess($queueForRealtime, $dbForProject, $deployment); - - \var_dump("After edge finish:"); - \var_dump($deployment); - \var_dump('---'); + $logs = $deployment->getAttribute('buildLogs', ''); if ($resource->getCollection() === 'sites') { $date = \date('H:i:s'); From 56347e42dfa210885c189e179f4f2c8ac98f917d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Wed, 25 Jun 2025 14:20:20 +0200 Subject: [PATCH 05/15] Fix syntax bug --- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index a7528634f0..105db89fe7 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1234,8 +1234,8 @@ class Builds extends Action $message = "" . $message; } - $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_START}', '', $message, 1); - $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_END}', '', $message, 1); + $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_START}', '', $message); + $message = \str_replace('{APPWRITE_DETECTION_SEPARATOR_END}', '', $message); // Combine with previous logs if deployment got past build process $previousLogs = ''; From 918ad8979d2770bcc9b8662d1cdfd6a47c83ddaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 18:07:59 +0200 Subject: [PATCH 06/15] Fix flakyness of account tests --- app/init/registers.php | 3 ++- docker-compose.yml | 16 +++++++++++--- tests/e2e/Scopes/ProjectCustom.php | 2 +- tests/e2e/Scopes/Scope.php | 22 +++++++++++++++---- .../Account/AccountCustomClientTest.php | 5 ++--- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/app/init/registers.php b/app/init/registers.php index 415730f936..3dc0e22dba 100644 --- a/app/init/registers.php +++ b/app/init/registers.php @@ -36,7 +36,8 @@ App::setMode(System::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION)); if (!App::isProduction()) { // Allow specific domains to skip public domain validation in dev environment // Useful for existing tests involving webhooks - PublicDomain::allow(['request-catcher']); + PublicDomain::allow(['request-catcher-sms']); + PublicDomain::allow(['request-catcher-webhook']); } $register->set('logger', function () { // Register error logger diff --git a/docker-compose.yml b/docker-compose.yml index ecb46de057..f5ac47a832 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -323,7 +323,8 @@ services: depends_on: - redis - mariadb - - request-catcher + - request-catcher-sms + - request-catcher-webhook environment: - _APP_ENV - _APP_WORKER_PER_CORE @@ -1075,15 +1076,24 @@ services: networks: - appwrite - request-catcher: # used mainly for dev tests + request-catcher-webhook: # used mainly for dev tests (mock HTTP webhook) image: appwrite/requestcatcher:1.0.0 - container_name: appwrite-requestcatcher + container_name: appwrite-requestcatcher-webhook <<: *x-logging ports: - "9504:5000" networks: - appwrite + request-catcher-sms: # used mainly for dev tests (mock SMS auth secret) + image: appwrite/requestcatcher:1.0.0 + container_name: appwrite-requestcatcher-sms + <<: *x-logging + ports: + - "9507:5000" + networks: + - appwrite + adminer: image: adminer container_name: appwrite-adminer diff --git a/tests/e2e/Scopes/ProjectCustom.php b/tests/e2e/Scopes/ProjectCustom.php index a354696f53..c5152adbcc 100644 --- a/tests/e2e/Scopes/ProjectCustom.php +++ b/tests/e2e/Scopes/ProjectCustom.php @@ -140,7 +140,7 @@ trait ProjectCustom 'teams.*', 'users.*' ], - 'url' => 'http://request-catcher:5000/webhook', + 'url' => 'http://request-catcher-webhook:5000/', 'security' => false, ]); diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index dddc97e3a0..b9792202e5 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -13,6 +13,9 @@ abstract class Scope extends TestCase use Retryable; use Async; + public const REQUEST_TYPE_WEBHOOK = 'webhook'; + public const REQUEST_TYPE_SMS = 'sms'; + protected ?Client $client = null; protected string $endpoint = 'http://localhost/v1'; @@ -76,10 +79,16 @@ abstract class Scope extends TestCase return []; } - protected function assertLastRequest(callable $probe, $timeoutMs = 20_000, $waitMs = 500): array + protected function assertLastRequest(callable $probe, string $type, $timeoutMs = 20_000, $waitMs = 500): array { - $this->assertEventually(function () use (&$request, $probe) { - $request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true); + $hostname = match ($type) { + 'webhook' => 'request-catcher-webhook', + 'api' => 'request-catcher-api', + default => throw new \Exception('Invalid request catcher type.'), + }; + + $this->assertEventually(function () use (&$request, $probe, $hostname) { + $request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true); $request['data'] = json_decode($request['data'], true); call_user_func($probe, $request); @@ -88,11 +97,16 @@ abstract class Scope extends TestCase return $request; } + /** + * @deprecated Use assertLastRequest instead. Used only historically in webhook tests + */ protected function getLastRequest(): array { + $hostname = 'request-catcher-webhook'; + sleep(2); - $request = json_decode(file_get_contents('http://request-catcher:5000/__last_request__'), true); + $request = json_decode(file_get_contents('http://' . $hostname . ':5000/__last_request__'), true); $request['data'] = json_decode($request['data'], true); return $request; diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 86c78d5d81..7072b122f4 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -2065,14 +2065,13 @@ class AccountCustomClientTest extends Scope $userId = $response['body']['userId']; $smsRequest = $this->assertLastRequest(function (array $request) use ($number) { - $this->assertEquals('http://request-catcher:5000/mock-sms', $request['url']); $this->assertEquals('Appwrite Mock Message Sender', $request['headers']['User-Agent']); $this->assertEquals('username', $request['headers']['X-Username']); $this->assertEquals('password', $request['headers']['X-Key']); $this->assertEquals('POST', $request['method']); $this->assertEquals('+123456789', $request['data']['from']); $this->assertEquals($number, $request['data']['to']); - }); + }, Scope::REQUEST_TYPE_SMS); $data['token'] = $smsRequest['data']['message']; $data['id'] = $userId; @@ -2422,7 +2421,7 @@ class AccountCustomClientTest extends Scope $smsRequest = $this->assertLastRequest(function ($request) { $this->assertArrayHasKey('data', $request); $this->assertArrayHasKey('message', $request['data'], "Last request missing message: " . \json_encode($request)); - }); + }, Scope::REQUEST_TYPE_SMS); /** * Test for FAILURE From 87c100db28608f0eac29032166baf52f15c7e247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 18:09:07 +0200 Subject: [PATCH 07/15] Improve General tests logging --- tests/e2e/General/HTTPTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 620409bb39..bce6e7206f 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -60,7 +60,7 @@ class HTTPTest extends Scope 'origin' => 'http://localhost', ])); - $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(200, $response['headers']['status-code'], "Simple GET /robots.txt HTTP request failed: " . \json_encode($response)); $this->assertStringContainsString('# robotstxt.org/', $response['body']); } From 572ff06f533c3a8651c3a7b861206aa7523d2680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 18:32:03 +0200 Subject: [PATCH 08/15] Fix robots.txt 5xx error --- app/controllers/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 44a9cff45b..c18f729c44 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -1408,7 +1408,7 @@ App::get('/robots.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Log $log, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { $host = $request->getHostname() ?? ''; $mainDomain = System::getEnv('_APP_DOMAIN', ''); From d4b53175dc0ca3e919170a2c0223371de80612a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 18:33:22 +0200 Subject: [PATCH 09/15] Update tests/e2e/Scopes/Scope.php --- tests/e2e/Scopes/Scope.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Scopes/Scope.php b/tests/e2e/Scopes/Scope.php index b9792202e5..2ee0d0198e 100644 --- a/tests/e2e/Scopes/Scope.php +++ b/tests/e2e/Scopes/Scope.php @@ -83,7 +83,7 @@ abstract class Scope extends TestCase { $hostname = match ($type) { 'webhook' => 'request-catcher-webhook', - 'api' => 'request-catcher-api', + 'sms' => 'request-catcher-sms', default => throw new \Exception('Invalid request catcher type.'), }; From ee2796f870d877054ea55a8d611798cdf01733f3 Mon Sep 17 00:00:00 2001 From: Christy Jacob Date: Thu, 26 Jun 2025 20:49:52 +0400 Subject: [PATCH 10/15] fix: correct parameter order in action function for robots.txt route --- app/controllers/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/general.php b/app/controllers/general.php index 44a9cff45b..c18f729c44 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -1408,7 +1408,7 @@ App::get('/robots.txt') ->inject('isResourceBlocked') ->inject('previewHostname') ->inject('apiKey') - ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Log $log, Response $response, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { + ->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Log $log, Database $dbForPlatform, callable $getProjectDB, Event $queueForEvents, StatsUsage $queueForStatsUsage, Func $queueForFunctions, Executor $executor, Reader $geodb, callable $isResourceBlocked, string $previewHostname, ?Key $apiKey) { $host = $request->getHostname() ?? ''; $mainDomain = System::getEnv('_APP_DOMAIN', ''); From bda9adc52eb9e04437fee564d44aac5a4f0105a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 20:04:56 +0200 Subject: [PATCH 11/15] Fix sms mock endpoint --- composer.json | 2 +- composer.lock | 64 ++++++++++++--------- src/Appwrite/Platform/Workers/Messaging.php | 2 +- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/composer.json b/composer.json index 4c36ab125d..0dd37d3747 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "utopia-php/image": "0.8.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", - "utopia-php/messaging": "0.18.*", + "utopia-php/messaging": "dev-feat-customizable-mock as 0.18.99", "utopia-php/migration": "0.10.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", diff --git a/composer.lock b/composer.lock index fd6a322076..63a03422c8 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": "55bc52686a08d64930e6af7411ac0654", + "content-hash": "8c1c38af4f7d733255bfdb8390fe6d65", "packages": [ { "name": "adhocore/jwt", @@ -1463,16 +1463,16 @@ }, { "name": "open-telemetry/sem-conv", - "version": "1.32.0", + "version": "1.32.1", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/sem-conv.git", - "reference": "16585cc0dbc3032a318e274043454679430d2ebf" + "reference": "94daa85ea61a8e2b7e1b0af6be0e875bedda7c22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/16585cc0dbc3032a318e274043454679430d2ebf", - "reference": "16585cc0dbc3032a318e274043454679430d2ebf", + "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/94daa85ea61a8e2b7e1b0af6be0e875bedda7c22", + "reference": "94daa85ea61a8e2b7e1b0af6be0e875bedda7c22", "shasum": "" }, "require": { @@ -1516,7 +1516,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-05T03:58:53+00:00" + "time": "2025-06-24T02:32:27+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -2327,21 +2327,20 @@ }, { "name": "ramsey/uuid", - "version": "4.8.1", + "version": "4.9.0", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28" + "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", - "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0", + "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0", "shasum": "" }, "require": { "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", - "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -2400,9 +2399,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.8.1" + "source": "https://github.com/ramsey/uuid/tree/4.9.0" }, - "time": "2025-06-01T06:28:46+00:00" + "time": "2025-06-25T14:20:11+00:00" }, { "name": "spomky-labs/otphp", @@ -3494,16 +3493,16 @@ }, { "name": "utopia-php/database", - "version": "0.71.7", + "version": "0.71.8", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "aa0116b2380125907fc18c82662be8e74c54091f" + "reference": "7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/aa0116b2380125907fc18c82662be8e74c54091f", - "reference": "aa0116b2380125907fc18c82662be8e74c54091f", + "url": "https://api.github.com/repos/utopia-php/database/zipball/7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e", + "reference": "7dff6b67a54f1a7f9d3f210db4c6e40d7052b79e", "shasum": "" }, "require": { @@ -3544,9 +3543,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.71.7" + "source": "https://github.com/utopia-php/database/tree/0.71.8" }, - "time": "2025-06-17T23:59:10+00:00" + "time": "2025-06-26T14:48:17+00:00" }, { "name": "utopia-php/detector", @@ -3943,16 +3942,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.18.0", + "version": "dev-feat-customizable-mock", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6" + "reference": "1f761b5f4103f372da3cb3f1141024cb1d0735da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c151aa5d4d475c788ca15c210b5b2017e21c41d6", - "reference": "c151aa5d4d475c788ca15c210b5b2017e21c41d6", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/1f761b5f4103f372da3cb3f1141024cb1d0735da", + "reference": "1f761b5f4103f372da3cb3f1141024cb1d0735da", "shasum": "" }, "require": { @@ -3988,9 +3987,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.18.0" + "source": "https://github.com/utopia-php/messaging/tree/feat-customizable-mock" }, - "time": "2025-05-15T05:00:03+00:00" + "time": "2025-06-26T18:01:16+00:00" }, { "name": "utopia-php/migration", @@ -8235,9 +8234,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/messaging", + "version": "dev-feat-customizable-mock", + "alias": "0.18.99", + "alias_normalized": "0.18.99.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/messaging": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8261,5 +8269,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index 35733200c7..668993fdae 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -426,7 +426,7 @@ class Messaging extends Action $credentials = $provider->getAttribute('credentials'); return match ($provider->getAttribute('provider')) { - 'mock' => new Mock('username', 'password'), + 'mock' => (new Mock('username', 'password'))->setEndpoint('http://request-catcher-sms:5000/'), 'twilio' => new Twilio( $credentials['accountSid'] ?? '', $credentials['authToken'] ?? '', From a356e86ced5cd1c52a258cf5a12845b59c5ccee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 20:17:26 +0200 Subject: [PATCH 12/15] Add previe wendpoint logging --- app/controllers/api/storage.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 26c789ce27..98a5b105a3 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -18,6 +18,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Buckets; use Appwrite\Utopia\Database\Validator\Queries\Files; use Appwrite\Utopia\Response; use Utopia\App; +use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\DateTime; @@ -953,12 +954,14 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->param('output', '', new WhiteList(\array_keys(Config::getParam('storage-outputs')), true), 'Output format type (jpeg, jpg, png, gif and webp).', true) // NOTE: this is only for the sdk generator and is not used in the action below and is utilised in `resources.php` for `resourceToken`. ->param('token', '', new Text(512), 'File token for accessing this file.', true) + ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('resourceToken') ->inject('deviceForFiles') ->inject('deviceForLocal') - ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal) { + ->inject('project') + ->action(function (string $bucketId, string $fileId, int $width, int $height, string $gravity, int $quality, int $borderWidth, string $borderColor, int $borderRadius, float $opacity, int $rotation, string $background, string $output, ?string $token, Request $request, Response $response, Database $dbForProject, Document $resourceToken, Device $deviceForFiles, Device $deviceForLocal, Document $project) { if (!\extension_loaded('imagick')) { throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Imagick extension is missing'); @@ -1035,8 +1038,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $output = empty($type) ? (array_search($mime, $outputs) ?? 'jpg') : $type; } + $startTime = \microtime(true); + $source = $deviceForFiles->read($path); + $downloadTime = \microtime(true) - $startTime; + if (!empty($cipher)) { // Decrypt $source = OpenSSL::decrypt( $source, @@ -1048,6 +1055,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ); } + $decryptionTime = \microtime(true) - $startTime - $downloadTime; + switch ($algorithm) { case Compression::ZSTD: $compressor = new Zstd(); @@ -1059,6 +1068,8 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') break; } + $decompressionTime = \microtime(true) - $startTime - $downloadTime - $decryptionTime; + try { $image = new Image($source); } catch (ImagickException $e) { @@ -1089,6 +1100,12 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') $data = $image->output($output, $quality); + $renderingTime = \microtime(true) - $startTime - $downloadTime - $decryptionTime - $decompressionTime; + + $totalTime = \microtime(true) - $startTime; + + Console::info("File preview rendered,project=" . $project->getId() . ",bucket=" . $bucketId . ",file=" . $file->getId() . ",uri=" . $request->getURI() . ",total=" . $totalTime . ",rendering=" . $renderingTime . ",decryption=" . $decryptionTime . ",decompression=" . $decompressionTime . ",download=" . $downloadTime); + $contentType = (\array_key_exists($output, $outputs)) ? $outputs[$output] : $outputs['jpg']; //Do not update transformedAt if it's a console user From df902d2624c2d1f7f9f880c421521f6159dd6692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 20:47:59 +0200 Subject: [PATCH 13/15] Fix account tests using old token --- composer.json | 2 +- composer.lock | 27 +++++++------------ src/Executor/Executor.php | 4 +-- .../Account/AccountCustomClientTest.php | 10 ++++++- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 0dd37d3747..4c36ab125d 100644 --- a/composer.json +++ b/composer.json @@ -61,7 +61,7 @@ "utopia-php/image": "0.8.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", - "utopia-php/messaging": "dev-feat-customizable-mock as 0.18.99", + "utopia-php/messaging": "0.18.*", "utopia-php/migration": "0.10.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", diff --git a/composer.lock b/composer.lock index 63a03422c8..bd6b0e959e 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": "8c1c38af4f7d733255bfdb8390fe6d65", + "content-hash": "55bc52686a08d64930e6af7411ac0654", "packages": [ { "name": "adhocore/jwt", @@ -3942,16 +3942,16 @@ }, { "name": "utopia-php/messaging", - "version": "dev-feat-customizable-mock", + "version": "0.18.1", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "1f761b5f4103f372da3cb3f1141024cb1d0735da" + "reference": "5d1245207a61d7ca065daddad7ac5f1d5640152f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/1f761b5f4103f372da3cb3f1141024cb1d0735da", - "reference": "1f761b5f4103f372da3cb3f1141024cb1d0735da", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/5d1245207a61d7ca065daddad7ac5f1d5640152f", + "reference": "5d1245207a61d7ca065daddad7ac5f1d5640152f", "shasum": "" }, "require": { @@ -3987,9 +3987,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/feat-customizable-mock" + "source": "https://github.com/utopia-php/messaging/tree/0.18.1" }, - "time": "2025-06-26T18:01:16+00:00" + "time": "2025-06-26T18:26:07+00:00" }, { "name": "utopia-php/migration", @@ -8234,18 +8234,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/messaging", - "version": "dev-feat-customizable-mock", - "alias": "0.18.99", - "alias_normalized": "0.18.99.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/messaging": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index e0e40f0169..fd1a8b494f 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -188,9 +188,9 @@ class Executor array $headers, float $cpus, int $memory, - string $runtimeEntrypoint = '', bool $logging, - int $requestTimeout = null + string $runtimeEntrypoint = '', + ?int $requestTimeout ) { if (empty($headers['host'])) { $headers['host'] = System::getEnv('_APP_DOMAIN', ''); diff --git a/tests/e2e/Services/Account/AccountCustomClientTest.php b/tests/e2e/Services/Account/AccountCustomClientTest.php index 7072b122f4..1b84ce7083 100644 --- a/tests/e2e/Services/Account/AccountCustomClientTest.php +++ b/tests/e2e/Services/Account/AccountCustomClientTest.php @@ -2415,12 +2415,20 @@ class AccountCustomClientTest extends Scope $this->assertEquals(201, $response['headers']['status-code']); $this->assertNotEmpty($response['body']['$id']); + $this->assertNotEmpty($response['body']['$createdAt']); $this->assertEmpty($response['body']['secret']); $this->assertTrue((new DatetimeValidator())->isValid($response['body']['expire'])); - $smsRequest = $this->assertLastRequest(function ($request) { + $tokenCreatedAt = $response['body']['$createdAt']; + + $smsRequest = $this->assertLastRequest(function ($request) use ($tokenCreatedAt) { $this->assertArrayHasKey('data', $request); + $this->assertArrayHasKey('time', $request); $this->assertArrayHasKey('message', $request['data'], "Last request missing message: " . \json_encode($request)); + + // Ensure we are not using token from last sms login + $tokenRecievedAt = $request['time']; + $this->assertGreaterThan($tokenCreatedAt, $tokenRecievedAt); }, Scope::REQUEST_TYPE_SMS); /** From b12ea0b3b149c67cd83ba137487f4b0d5964996a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 21:22:38 +0200 Subject: [PATCH 14/15] Fix merge conflict bug --- src/Appwrite/Platform/Modules/Compute/Base.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 71b932590d..e58f2b8664 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -235,15 +235,15 @@ class Base extends Action fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), - 'projectInternalId' => $project->getInternalId(), + 'projectInternalId' => $project->getSequence(), 'domain' => $domain, 'type' => 'deployment', 'trigger' => 'deployment', 'deploymentId' => $deployment->getId(), - 'deploymentInternalId' => $deployment->getInternalId(), + 'deploymentInternalId' => $deployment->getSequence(), 'deploymentResourceType' => 'site', 'deploymentResourceId' => $site->getId(), - 'deploymentResourceInternalId' => $site->getInternalId(), + 'deploymentResourceInternalId' => $site->getSequence(), 'deploymentVcsProviderBranch' => $providerBranch, 'status' => 'verified', 'certificateId' => '', @@ -272,15 +272,15 @@ class Base extends Action fn () => $dbForPlatform->createDocument('rules', new Document([ '$id' => $ruleId, 'projectId' => $project->getId(), - 'projectInternalId' => $project->getInternalId(), + 'projectInternalId' => $project->getSequence(), 'domain' => $domain, 'type' => 'deployment', 'trigger' => 'deployment', 'deploymentId' => $deployment->getId(), - 'deploymentInternalId' => $deployment->getInternalId(), + 'deploymentInternalId' => $deployment->getSequence(), 'deploymentResourceType' => 'site', 'deploymentResourceId' => $site->getId(), - 'deploymentResourceInternalId' => $site->getInternalId(), + 'deploymentResourceInternalId' => $site->getSequence(), 'deploymentVcsProviderBranch' => $providerBranch, 'status' => 'verified', 'certificateId' => '', From ee225834d92e2b42761154bb0d5fa6614c2e3f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 26 Jun 2025 21:39:00 +0200 Subject: [PATCH 15/15] Fix default param syntax --- src/Executor/Executor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index fd1a8b494f..df4c5fd8f5 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -190,7 +190,7 @@ class Executor int $memory, bool $logging, string $runtimeEntrypoint = '', - ?int $requestTimeout + ?int $requestTimeout = null ) { if (empty($headers['host'])) { $headers['host'] = System::getEnv('_APP_DOMAIN', '');