From 0e90f64ea6fec58afc8c0adbf79dbe68a563c185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 18 May 2025 22:07:52 +0200 Subject: [PATCH 1/3] Fix backwards compatibility for function reation --- .../Functions/Http/Functions/Create.php | 159 +++++++++++++++++- .../SDK/Specification/Format/OpenAPI3.php | 4 + .../SDK/Specification/Format/Swagger2.php | 4 + 3 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index bc0f1b2dab..fd8da657eb 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -2,8 +2,12 @@ namespace Appwrite\Platform\Modules\Functions\Http\Functions; +use Appwrite\Event\Build; use Appwrite\Event\Event; +use Appwrite\Event\Func; +use Appwrite\Event\Realtime; use Appwrite\Event\Validator\FunctionEvent; +use Appwrite\Event\Webhook; use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Compute\Base; use Appwrite\Platform\Modules\Compute\Validator\Specification; @@ -13,6 +17,7 @@ use Appwrite\SDK\Response as SDKResponse; use Appwrite\Task\Validator\Cron; use Appwrite\Utopia\Database\Validator\CustomId; use Appwrite\Utopia\Response; +use Appwrite\Utopia\Response\Model\Rule; use Utopia\Abuse\Abuse; use Utopia\Config\Config; use Utopia\Database\Database; @@ -25,12 +30,14 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; +use Utopia\Request; use Utopia\System\System; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; +use Utopia\VCS\Adapter\Git\GitHub; class Create extends Base { @@ -91,12 +98,22 @@ class Create extends Base System::getEnv('_APP_COMPUTE_CPUS', 0), System::getEnv('_APP_COMPUTE_MEMORY', 0) ), 'Runtime specification for the function and builds.', true, ['plan']) + ->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true, deprecated: true) + ->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true, deprecated: true) + ->param('templateRootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.', true, deprecated: true) + ->param('templateVersion', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true, deprecated: true) ->inject('response') ->inject('dbForProject') ->inject('timelimit') ->inject('project') ->inject('queueForEvents') + ->inject('queueForBuilds') + ->inject('queueForRealtime') + ->inject('queueForWebhooks') + ->inject('queueForFunctions') ->inject('dbForPlatform') + ->inject('request') + ->inject('gitHub') ->callback([$this, 'action']); } @@ -119,12 +136,22 @@ class Create extends Base bool $providerSilentMode, string $providerRootDirectory, string $specification, + string $templateRepository, + string $templateOwner, + string $templateRootDirectory, + string $templateVersion, Response $response, Database $dbForProject, callable $timelimit, Document $project, Event $queueForEvents, - Database $dbForPlatform + Build $queueForBuilds, + Realtime $queueForRealtime, + Webhook $queueForWebhooks, + Func $queueForFunctions, + Database $dbForPlatform, + Request $request, + GitHub $github ) { // Temporary abuse check @@ -251,6 +278,136 @@ class Create extends Base $function = $dbForProject->updateDocument('functions', $function->getId(), $function); + // Backwards compatibility with 1.6 behaviour + $requestFormat = $request->getHeader('x-appwrite-response-format', System::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); + if ($requestFormat && version_compare($requestFormat, '1.7.0', '<')) { + // build from template + $template = new Document([]); + if ( + !empty($templateRepository) + && !empty($templateOwner) + && !empty($templateRootDirectory) + && !empty($templateVersion) + ) { + $template->setAttribute('repositoryName', $templateRepository) + ->setAttribute('ownerName', $templateOwner) + ->setAttribute('rootDirectory', $templateRootDirectory) + ->setAttribute('version', $templateVersion); + } + + if (!empty($providerRepositoryId)) { + // Deploy VCS + $template = new Document(); + + $installation = $dbForPlatform->getDocument('installations', $function->getAttribute('installationId')); + $deployment = $this->redeployVcsFunction( + request: $request, + function: $function, + project: $project, + installation: $installation, + dbForProject: $dbForProject, + queueForBuilds: $queueForBuilds, + template: $template, + github: $github, + activate: true, + reference: $providerBranch, + referenceType: 'branch' + ); + + $function = $function + ->setAttribute('latestDeploymentId', $deployment->getId()) + ->setAttribute('latestDeploymentInternalId', $deployment->getInternalId()) + ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) + ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); + $dbForProject->updateDocument('functions', $function->getId(), $function); + } elseif (!$template->isEmpty()) { + // Deploy non-VCS from template + $deploymentId = ID::unique(); + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'resourceType' => 'functions', + 'entrypoint' => $function->getAttribute('entrypoint', ''), + 'buildCommands' => $function->getAttribute('commands', ''), + 'type' => 'manual', + 'activate' => true, + ])); + + $function = $function + ->setAttribute('latestDeploymentId', $deployment->getId()) + ->setAttribute('latestDeploymentInternalId', $deployment->getInternalId()) + ->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt()) + ->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', '')); + $dbForProject->updateDocument('functions', $function->getId(), $function); + + $queueForBuilds + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($function) + ->setDeployment($deployment) + ->setTemplate($template); + } + + $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', ''); + if (!empty($functionsDomain)) { + $routeSubdomain = ID::unique(); + $domain = "{$routeSubdomain}.{$functionsDomain}"; + // TODO: @christyjacob remove once we migrate the rules in 1.7.x + $ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique(); + + $rule = Authorization::skip( + fn () => $dbForPlatform->createDocument('rules', new Document([ + '$id' => $ruleId, + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'domain' => $domain, + 'status' => 'verified', + 'type' => 'deployment', + 'trigger' => 'manual', + 'deploymentId' => !isset($deployment) || $deployment->isEmpty() ? '' : $deployment->getId(), + 'deploymentInternalId' => !isset($deployment) || $deployment->isEmpty() ? '' : $deployment->getInternalId(), + 'deploymentResourceType' => 'function', + 'deploymentResourceId' => $function->getId(), + 'deploymentResourceInternalId' => $function->getInternalId(), + 'deploymentVcsProviderBranch' => '', + 'certificateId' => '', + 'search' => implode(' ', [$ruleId, $domain]), + 'owner' => 'Appwrite', + 'region' => $project->getAttribute('region') + ])) + ); + + $ruleModel = new Rule(); + $ruleCreate = + $queueForEvents + ->setProject($project) + ->setEvent('rules.[ruleId].create') + ->setParam('ruleId', $rule->getId()) + ->setPayload($rule->getArrayCopy(array_keys($ruleModel->getRules()))); + + /** Trigger Webhook */ + $queueForWebhooks + ->from($ruleCreate) + ->trigger(); + + /** Trigger Functions */ + $queueForFunctions + ->from($ruleCreate) + ->trigger(); + + /** Trigger Realtime Events */ + $queueForRealtime + ->from($ruleCreate) + ->setSubscribers(['console', $project->getId()]) + ->trigger(); + } + } + $queueForEvents->setParam('functionId', $function->getId()); $response diff --git a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php index f486a61ce5..31ed14b198 100644 --- a/src/Appwrite/SDK/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/SDK/Specification/Format/OpenAPI3.php @@ -309,6 +309,10 @@ class OpenAPI3 extends Format $bodyRequired = []; foreach ($route->getParams() as $name => $param) { // Set params + if ($param['deprecated']) { + continue; + } + /** * @var \Utopia\Validator $validator */ diff --git a/src/Appwrite/SDK/Specification/Format/Swagger2.php b/src/Appwrite/SDK/Specification/Format/Swagger2.php index 948798ef0b..86c9420739 100644 --- a/src/Appwrite/SDK/Specification/Format/Swagger2.php +++ b/src/Appwrite/SDK/Specification/Format/Swagger2.php @@ -314,6 +314,10 @@ class Swagger2 extends Format ); foreach ($parameters as $name => $param) { // Set params + if ($param['deprecated']) { + continue; + } + /** @var Validator $validator */ $validator = (\is_callable($param['validator'])) ? ($param['validator'])(...$this->app->getResources($param['injections'])) From e84ad1e83c95a45ba7a798248dd0b890a86bcf1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 18 May 2025 22:37:30 +0200 Subject: [PATCH 2/3] Upgrade libs --- composer.json | 2 +- composer.lock | 37 +++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index d9109f40f8..8ea8c8b34d 100644 --- a/composer.json +++ b/composer.json @@ -67,7 +67,7 @@ "utopia-php/platform": "0.7.*", "utopia-php/pools": "0.8.*", "utopia-php/preloader": "0.2.*", - "utopia-php/queue": "0.9.*", + "utopia-php/queue": "0.10.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", "utopia-php/swoole": "0.8.*", diff --git a/composer.lock b/composer.lock index a495c50034..f6c07c53e5 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": "735023e2b70ce47fe65985f195b257bd", + "content-hash": "b6f5295db11727cb4e88e702dc97809d", "packages": [ { "name": "adhocore/jwt", @@ -4104,16 +4104,16 @@ }, { "name": "utopia-php/platform", - "version": "0.7.4", + "version": "0.7.6", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "a5b93d8177702ec458c3af9137663133c012b71b" + "reference": "6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/a5b93d8177702ec458c3af9137663133c012b71b", - "reference": "a5b93d8177702ec458c3af9137663133c012b71b", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b", + "reference": "6bc7fbb43ec2b7f9ee5bdef5d4b5e4a81860950b", "shasum": "" }, "require": { @@ -4122,11 +4122,11 @@ "php": ">=8.0", "utopia-php/cli": "0.15.*", "utopia-php/framework": "0.33.*", - "utopia-php/queue": "0.9.*" + "utopia-php/queue": "0.10.*" }, "require-dev": { - "laravel/pint": "1.2.*", - "phpunit/phpunit": "^9.3" + "laravel/pint": "1.*", + "phpunit/phpunit": "9.*" }, "type": "library", "autoload": { @@ -4148,9 +4148,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.7.4" + "source": "https://github.com/utopia-php/platform/tree/0.7.6" }, - "time": "2025-03-13T13:00:12+00:00" + "time": "2025-05-18T20:31:24+00:00" }, { "name": "utopia-php/pools", @@ -4259,16 +4259,16 @@ }, { "name": "utopia-php/queue", - "version": "0.9.1", + "version": "0.10.0", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32" + "reference": "0eccc559168ea72241c39a4c482d868314666be1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32", - "reference": "32b6f84c55aae761db5a5ae76cc91ca8dbc8bc32", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/0eccc559168ea72241c39a4c482d868314666be1", + "reference": "0eccc559168ea72241c39a4c482d868314666be1", "shasum": "" }, "require": { @@ -4277,6 +4277,7 @@ "utopia-php/cli": "0.15.*", "utopia-php/fetch": "0.4.*", "utopia-php/framework": "0.33.*", + "utopia-php/pools": "0.8.*", "utopia-php/telemetry": "0.1.*" }, "require-dev": { @@ -4318,9 +4319,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.9.1" + "source": "https://github.com/utopia-php/queue/tree/0.10.0" }, - "time": "2025-03-28T19:49:36+00:00" + "time": "2025-04-17T12:15:52+00:00" }, { "name": "utopia-php/registry", @@ -8240,7 +8241,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8264,5 +8265,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } From 02b7e0df4dac7e319eb722cc5d082092279b0b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Sun, 18 May 2025 22:51:17 +0200 Subject: [PATCH 3/3] queries backwards compatibilit --- src/Appwrite/Utopia/Request/Filters/V19.php | 25 +++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Appwrite/Utopia/Request/Filters/V19.php b/src/Appwrite/Utopia/Request/Filters/V19.php index 27b854b46f..8680cd642c 100644 --- a/src/Appwrite/Utopia/Request/Filters/V19.php +++ b/src/Appwrite/Utopia/Request/Filters/V19.php @@ -10,6 +10,16 @@ class V19 extends Filter public function parse(array $content, string $model): array { switch ($model) { + case 'functions.list': + $content = $this->convertQueryAttribute($content, 'deployment', 'deploymentId'); + break; + case 'functions.listDeployments': + $content = $this->convertQueryAttribute($content, 'size', 'deploymentSize'); + break; + case 'proxy.listRules': + $content = $this->convertQueryAttribute($content, 'resourceType', 'deploymentResourceType'); + $content = $this->convertQueryAttribute($content, 'resourceId', 'deploymentResourceId'); + break; case 'functions.create': unset($content['templateRepository']); unset($content['templateOwner']); @@ -28,4 +38,19 @@ class V19 extends Filter } return $content; } + + public function convertQueryAttribute(array $content, string $old, string $new) + { + if (isset($content['queries']) && is_array($content['queries'])) { + foreach ($content['queries'] as $index => $query) { + $query = \json_decode($query, true); + if (($query['attribute'] ?? '') === $old) { + $query['attribute'] = $new; + } + $content['queries'][$index] = \json_encode($query); + } + } + + return $content; + } }