mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 08:58:35 +00:00
Merge remote-tracking branch 'origin/1.8.x' into feat-multi-create
This commit is contained in:
commit
38af4b83c0
23 changed files with 237 additions and 340 deletions
|
|
@ -5,7 +5,6 @@ use Appwrite\Event\Build;
|
|||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Network\Validator\Redirect;
|
||||
use Appwrite\Platform\Modules\Compute\Base as ComputeBase;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
|
|
@ -32,7 +31,10 @@ use Utopia\Database\Helpers\Permission;
|
|||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
use Utopia\Detector\Detection\Framework\Analog;
|
||||
use Utopia\Detector\Detection\Framework\Angular;
|
||||
use Utopia\Detector\Detection\Framework\Astro;
|
||||
|
|
@ -434,8 +436,6 @@ $createGitDeployments = function (GitHub $github, string $providerInstallationId
|
|||
}
|
||||
}
|
||||
|
||||
ComputeBase::updateEmptyManualRule($project, $resource, $deployment, $dbForPlatform);
|
||||
|
||||
if ($resource->getCollection() === 'sites' && !empty($latestCommentId) && !empty($previewRuleId)) {
|
||||
$retries = 0;
|
||||
$lockAcquired = false;
|
||||
|
|
@ -1036,10 +1036,11 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
|||
->param('installationId', '', new Text(256), 'Installation Id')
|
||||
->param('type', '', new WhiteList(['runtime', 'framework']), 'Detector type. Must be one of the following: runtime, framework')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('queries', [], new Queries([new Limit(), new Offset()]), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit and offset', true)
|
||||
->inject('gitHub')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $installationId, string $type, string $search, GitHub $github, Response $response, Database $dbForPlatform) {
|
||||
->action(function (string $installationId, string $type, string $search, array $queries, GitHub $github, Response $response, Database $dbForPlatform) {
|
||||
if (empty($search)) {
|
||||
$search = "";
|
||||
}
|
||||
|
|
@ -1055,11 +1056,20 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
|||
$githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID');
|
||||
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
|
||||
|
||||
$page = 1;
|
||||
$perPage = 4;
|
||||
$queries = Query::parseQueries($queries);
|
||||
$limitQuery = current(array_filter($queries, fn ($query) => $query->getMethod() === Query::TYPE_LIMIT));
|
||||
$offsetQuery = current(array_filter($queries, fn ($query) => $query->getMethod() === Query::TYPE_OFFSET));
|
||||
|
||||
$limit = !empty($limitQuery) ? $limitQuery->getValue() : 4;
|
||||
$offset = !empty($offsetQuery) ? $offsetQuery->getValue() : 0;
|
||||
|
||||
if ($offset % $limit !== 0) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'offset must be a multiple of the limit');
|
||||
}
|
||||
|
||||
$page = ($offset / $limit) + 1;
|
||||
$owner = $github->getOwnerName($providerInstallationId);
|
||||
$repos = $github->searchRepositories($owner, $page, $perPage, $search);
|
||||
['items' => $repos, 'total' => $total] = $github->searchRepositories($owner, $page, $limit, $search);
|
||||
|
||||
$repos = \array_map(function ($repo) use ($installation) {
|
||||
$repo['id'] = \strval($repo['id'] ?? '');
|
||||
|
|
@ -1231,7 +1241,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
|
|||
|
||||
$response->dynamic(new Document([
|
||||
$type === 'framework' ? 'frameworkProviderRepositories' : 'runtimeProviderRepositories' => $repos,
|
||||
'total' => \count($repos),
|
||||
'total' => $total,
|
||||
]), ($type === 'framework') ? Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST : Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -856,7 +856,7 @@ App::shutdown()
|
|||
*
|
||||
* Therefore, we consider this an anonymous request and create a relevant user.
|
||||
*/
|
||||
$user = new Document([
|
||||
$user = new User([
|
||||
'$id' => '',
|
||||
'status' => true,
|
||||
'type' => ACTIVITY_TYPE_GUEST,
|
||||
|
|
|
|||
|
|
@ -93,6 +93,13 @@ const APP_VCS_GITHUB_EMAIL = 'team@appwrite.io';
|
|||
const APP_VCS_GITHUB_URL = 'https://github.com/TeamAppwrite';
|
||||
const APP_BRANDED_EMAIL_BASE_TEMPLATE = 'email-base-styled';
|
||||
|
||||
/**
|
||||
* JWT for Resource Tokens.
|
||||
*/
|
||||
const RESOURCE_TOKEN_ALGORITHM = 'HS256';
|
||||
const RESOURCE_TOKEN_MAX_AGE = 86400 * 365 * 10; /* 10 years */
|
||||
const RESOURCE_TOKEN_LEEWAY = 10; // 10 seconds
|
||||
|
||||
/**
|
||||
* Token Expiration times.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1003,7 +1003,8 @@ App::setResource('resourceToken', function ($project, $dbForProject, $request) {
|
|||
$tokenJWT = $request->getParam('token');
|
||||
|
||||
if (!empty($tokenJWT) && !$project->isEmpty()) { // JWT authentication
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 900, 10); // Instantiate with key, algo, maxAge and leeway.
|
||||
// Use a large but reasonable maxAge to avoid auto-exp when token has no expiry
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), RESOURCE_TOKEN_ALGORITHM, RESOURCE_TOKEN_MAX_AGE, RESOURCE_TOKEN_LEEWAY); // Instantiate with key, algo, maxAge and leeway.
|
||||
|
||||
try {
|
||||
$payload = $jwt->decode($tokenJWT);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
"utopia-php/swoole": "0.8.*",
|
||||
"utopia-php/system": "0.9.*",
|
||||
"utopia-php/telemetry": "0.1.*",
|
||||
"utopia-php/vcs": "0.12.*",
|
||||
"utopia-php/vcs": "0.13.*",
|
||||
"utopia-php/websocket": "0.3.*",
|
||||
"matomo/device-detector": "6.4.*",
|
||||
"dragonmantank/cron-expression": "3.4.*",
|
||||
|
|
|
|||
185
composer.lock
generated
185
composer.lock
generated
|
|
@ -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": "479b161d08b29d22267c4c7798751842",
|
||||
"content-hash": "0cad126c9b41c0d496462ba03ff36d7b",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
|
|
@ -891,16 +891,16 @@
|
|||
},
|
||||
{
|
||||
"name": "matomo/device-detector",
|
||||
"version": "6.4.7",
|
||||
"version": "6.4.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/matomo-org/device-detector.git",
|
||||
"reference": "e53eed31bb1530851feebe52bd64c3451da19e77"
|
||||
"reference": "56baf981af4f192e15a4f369d4975af847a81ccb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/e53eed31bb1530851feebe52bd64c3451da19e77",
|
||||
"reference": "e53eed31bb1530851feebe52bd64c3451da19e77",
|
||||
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/56baf981af4f192e15a4f369d4975af847a81ccb",
|
||||
"reference": "56baf981af4f192e15a4f369d4975af847a81ccb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -957,7 +957,7 @@
|
|||
"source": "https://github.com/matomo-org/matomo",
|
||||
"wiki": "https://dev.matomo.org/"
|
||||
},
|
||||
"time": "2025-08-20T17:20:16+00:00"
|
||||
"time": "2025-11-26T16:02:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mongodb/mongodb",
|
||||
|
|
@ -2673,16 +2673,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.3.6",
|
||||
"version": "v7.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de"
|
||||
"reference": "ee5e0e0139ab506f6063a230e631bed677c650a4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de",
|
||||
"reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/ee5e0e0139ab506f6063a230e631bed677c650a4",
|
||||
"reference": "ee5e0e0139ab506f6063a230e631bed677c650a4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -2713,12 +2713,13 @@
|
|||
"php-http/httplug": "^1.0|^2.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/amphp-http-client-meta": "^1.0|^2.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/messenger": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0",
|
||||
"symfony/stopwatch": "^6.4|^7.0"
|
||||
"symfony/cache": "^6.4|^7.0|^8.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0|^8.0",
|
||||
"symfony/messenger": "^6.4|^7.0|^8.0",
|
||||
"symfony/process": "^6.4|^7.0|^8.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0|^8.0",
|
||||
"symfony/stopwatch": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -2749,7 +2750,7 @@
|
|||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.3.6"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -2769,7 +2770,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-05T17:41:46+00:00"
|
||||
"time": "2025-11-20T12:32:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
|
|
@ -5211,16 +5212,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.12.0",
|
||||
"version": "0.13.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "28457cf347972c4ec95d3ca77776a4921364a665"
|
||||
"reference": "c59e21db5ca42014fe2071fec3c2f814efcc86dd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/28457cf347972c4ec95d3ca77776a4921364a665",
|
||||
"reference": "28457cf347972c4ec95d3ca77776a4921364a665",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/c59e21db5ca42014fe2071fec3c2f814efcc86dd",
|
||||
"reference": "c59e21db5ca42014fe2071fec3c2f814efcc86dd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -5254,9 +5255,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.12.0"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.13.0"
|
||||
},
|
||||
"time": "2025-10-22T12:58:29+00:00"
|
||||
"time": "2025-11-28T08:42:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
|
|
@ -7929,47 +7930,39 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.3.6",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
|
||||
"reference": "307d3cf852f5ead3618ac60ecbedbdd512c348b1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
|
||||
"reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/307d3cf852f5ead3618ac60ecbedbdd512c348b1",
|
||||
"reference": "307d3cf852f5ead3618ac60ecbedbdd512c348b1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-mbstring": "~1.0",
|
||||
"php": ">=8.4",
|
||||
"symfony/polyfill-mbstring": "^1.0",
|
||||
"symfony/service-contracts": "^2.5|^3",
|
||||
"symfony/string": "^7.2"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/dependency-injection": "<6.4",
|
||||
"symfony/dotenv": "<6.4",
|
||||
"symfony/event-dispatcher": "<6.4",
|
||||
"symfony/lock": "<6.4",
|
||||
"symfony/process": "<6.4"
|
||||
"symfony/string": "^7.4|^8.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/log-implementation": "1.0|2.0|3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/config": "^6.4|^7.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0",
|
||||
"symfony/event-dispatcher": "^6.4|^7.0",
|
||||
"symfony/http-foundation": "^6.4|^7.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0",
|
||||
"symfony/lock": "^6.4|^7.0",
|
||||
"symfony/messenger": "^6.4|^7.0",
|
||||
"symfony/process": "^6.4|^7.0",
|
||||
"symfony/stopwatch": "^6.4|^7.0",
|
||||
"symfony/var-dumper": "^6.4|^7.0"
|
||||
"symfony/config": "^7.4|^8.0",
|
||||
"symfony/dependency-injection": "^7.4|^8.0",
|
||||
"symfony/event-dispatcher": "^7.4|^8.0",
|
||||
"symfony/http-foundation": "^7.4|^8.0",
|
||||
"symfony/http-kernel": "^7.4|^8.0",
|
||||
"symfony/lock": "^7.4|^8.0",
|
||||
"symfony/messenger": "^7.4|^8.0",
|
||||
"symfony/process": "^7.4|^8.0",
|
||||
"symfony/stopwatch": "^7.4|^8.0",
|
||||
"symfony/var-dumper": "^7.4|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -8003,7 +7996,7 @@
|
|||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.3.6"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8023,29 +8016,29 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-04T01:21:42+00:00"
|
||||
"time": "2025-11-21T13:19:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v7.3.6",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "e9bcfd7837928ab656276fe00464092cc9e1826a"
|
||||
"reference": "7fc96ae83372620eaba3826874f46e26295768ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a",
|
||||
"reference": "e9bcfd7837928ab656276fe00464092cc9e1826a",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7fc96ae83372620eaba3826874f46e26295768ca",
|
||||
"reference": "7fc96ae83372620eaba3826874f46e26295768ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"php": ">=8.4",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-mbstring": "~1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/process": "^6.4|^7.0"
|
||||
"symfony/process": "^7.4|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -8073,7 +8066,7 @@
|
|||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.3.6"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8093,27 +8086,27 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-05T09:52:27+00:00"
|
||||
"time": "2025-11-05T14:36:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.3.5",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
|
||||
"reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
|
||||
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291",
|
||||
"reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
"php": ">=8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/filesystem": "^6.4|^7.0"
|
||||
"symfony/filesystem": "^7.4|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -8141,7 +8134,7 @@
|
|||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.3.5"
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8161,24 +8154,24 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-15T18:45:57+00:00"
|
||||
"time": "2025-11-05T14:36:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v7.3.3",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d"
|
||||
"reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
|
||||
"reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
|
||||
"reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"php": ">=8.4",
|
||||
"symfony/deprecation-contracts": "^2.5|^3"
|
||||
},
|
||||
"type": "library",
|
||||
|
|
@ -8212,7 +8205,7 @@
|
|||
"options"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8232,7 +8225,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-05T10:16:07+00:00"
|
||||
"time": "2025-11-12T15:55:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
|
@ -8566,20 +8559,20 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v7.3.4",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "f24f8f316367b30810810d4eb30c543d7003ff3b"
|
||||
"reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/f24f8f316367b30810810d4eb30c543d7003ff3b",
|
||||
"reference": "f24f8f316367b30810810d4eb30c543d7003ff3b",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149",
|
||||
"reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2"
|
||||
"php": ">=8.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -8607,7 +8600,7 @@
|
|||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v7.3.4"
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8627,38 +8620,38 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-09-11T10:12:26+00:00"
|
||||
"time": "2025-10-16T16:25:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.3.4",
|
||||
"version": "v8.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "f96476035142921000338bad71e5247fbc138872"
|
||||
"reference": "f929eccf09531078c243df72398560e32fa4cf4f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/f96476035142921000338bad71e5247fbc138872",
|
||||
"reference": "f96476035142921000338bad71e5247fbc138872",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/f929eccf09531078c243df72398560e32fa4cf4f",
|
||||
"reference": "f929eccf09531078c243df72398560e32fa4cf4f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"symfony/polyfill-ctype": "~1.8",
|
||||
"symfony/polyfill-intl-grapheme": "~1.0",
|
||||
"symfony/polyfill-intl-normalizer": "~1.0",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
"php": ">=8.4",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-intl-grapheme": "^1.33",
|
||||
"symfony/polyfill-intl-normalizer": "^1.0",
|
||||
"symfony/polyfill-mbstring": "^1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/translation-contracts": "<2.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/emoji": "^7.1",
|
||||
"symfony/http-client": "^6.4|^7.0",
|
||||
"symfony/intl": "^6.4|^7.0",
|
||||
"symfony/emoji": "^7.4|^8.0",
|
||||
"symfony/http-client": "^7.4|^8.0",
|
||||
"symfony/intl": "^7.4|^8.0",
|
||||
"symfony/translation-contracts": "^2.5|^3.0",
|
||||
"symfony/var-exporter": "^6.4|^7.0"
|
||||
"symfony/var-exporter": "^7.4|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
|
@ -8697,7 +8690,7 @@
|
|||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.3.4"
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -8717,7 +8710,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-09-11T14:36:48+00:00"
|
||||
"time": "2025-09-11T14:37:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
|
|
|
|||
|
|
@ -144,7 +144,8 @@ class Create extends Action
|
|||
|
||||
$challenge = $dbForProject->createDocument('challenges', $challenge);
|
||||
|
||||
$templatesPath = \dirname(__DIR__, 7) . '/app/config/locale/templates';
|
||||
// 9 levels up to project root
|
||||
$templatesPath = \dirname(__DIR__, 9) . '/app/config/locale/templates';
|
||||
|
||||
switch ($factor) {
|
||||
case Type::PHONE:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use Utopia\Database\Exception\Duplicate;
|
|||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\System\System;
|
||||
|
|
@ -53,7 +52,7 @@ class Base extends Action
|
|||
return $allowedSpecifications[0] ?? APP_COMPUTE_SPECIFICATION_DEFAULT;
|
||||
}
|
||||
|
||||
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
|
||||
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
|
||||
{
|
||||
$deploymentId = ID::unique();
|
||||
$entrypoint = $function->getAttribute('entrypoint', '');
|
||||
|
|
@ -134,8 +133,6 @@ class Base extends Action
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function);
|
||||
|
||||
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
|
|
@ -330,8 +327,6 @@ class Base extends Action
|
|||
}
|
||||
}
|
||||
|
||||
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
|
|
@ -340,34 +335,4 @@ class Base extends Action
|
|||
|
||||
return $deployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update empty manual rule for deployment.
|
||||
* In case of first deployment, deployment ID will be empty in the rules, so we need to update it here.
|
||||
*
|
||||
* @param \Utopia\Database\Document $project
|
||||
* @param \Utopia\Database\Document $resource
|
||||
* @param \Utopia\Database\Document $deployment
|
||||
* @param \Utopia\Database\Database $dbForPlatform
|
||||
* @return void
|
||||
*/
|
||||
public static function updateEmptyManualRule(Document $project, Document $resource, Document $deployment, Database $dbForPlatform)
|
||||
{
|
||||
$resourceType = $resource->getCollection() === 'sites' ? 'site' : 'function';
|
||||
|
||||
$queries = [
|
||||
Query::equal('projectInternalId', [$project->getSequence()]),
|
||||
Query::equal('deploymentResourceInternalId', [$resource->getSequence()]),
|
||||
Query::equal('deploymentResourceType', [$resourceType]),
|
||||
Query::equal('deploymentId', ['']),
|
||||
Query::equal('type', ['deployment']),
|
||||
Query::equal('trigger', ['manual']),
|
||||
];
|
||||
$dbForPlatform->forEach('rules', function (Document $rule) use ($deployment, $dbForPlatform) {
|
||||
Authorization::skip(fn () => $dbForPlatform->updateDocument('rules', $rule->getId(), new Document([
|
||||
'deploymentId' => $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->getSequence(),
|
||||
])));
|
||||
}, $queries);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace Appwrite\Platform\Modules\Functions\Http\Deployments;
|
|||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
|
|
@ -32,7 +31,7 @@ use Utopia\Validator\Boolean;
|
|||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Create extends Base
|
||||
class Create extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
|
|
@ -83,7 +82,6 @@ class Create extends Base
|
|||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForEvents')
|
||||
->inject('project')
|
||||
->inject('deviceForFunctions')
|
||||
|
|
@ -102,7 +100,6 @@ class Create extends Base
|
|||
Request $request,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Document $project,
|
||||
Device $deviceForFunctions,
|
||||
|
|
@ -304,8 +301,6 @@ class Create extends Base
|
|||
}
|
||||
}
|
||||
|
||||
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
|
||||
|
||||
$metadata = null;
|
||||
|
||||
$queueForEvents
|
||||
|
|
|
|||
|
|
@ -124,7 +124,6 @@ class Create extends Base
|
|||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
|
|
@ -171,9 +170,6 @@ class Create extends Base
|
|||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('functions', $function->getId(), $function);
|
||||
|
||||
|
||||
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,6 @@ class Create extends Base
|
|||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
|
|
|
|||
|
|
@ -305,14 +305,12 @@ class Create extends Base
|
|||
$template = new Document();
|
||||
|
||||
$installation = $dbForPlatform->getDocument('installations', $function->getAttribute('installationId'));
|
||||
// TODO: Is this still needed? Can this be removed?
|
||||
$deployment = $this->redeployVcsFunction(
|
||||
request: $request,
|
||||
function: $function,
|
||||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class Update extends Base
|
|||
|
||||
// Redeploy logic
|
||||
if (!$isConnected && !empty($providerRepositoryId)) {
|
||||
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, new Document(), $github, true);
|
||||
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
|
||||
}
|
||||
|
||||
// Inform scheduler if function is still active
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace Appwrite\Platform\Modules\Sites\Http\Deployments;
|
|||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
|
|
@ -33,7 +32,7 @@ use Utopia\Validator\Boolean;
|
|||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class Create extends Base
|
||||
class Create extends Action
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
|
|
@ -366,8 +365,6 @@ class Create extends Base
|
|||
}
|
||||
}
|
||||
|
||||
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
|
||||
|
||||
$metadata = null;
|
||||
|
||||
$queueForEvents
|
||||
|
|
|
|||
|
|
@ -208,8 +208,6 @@ class Create extends Base
|
|||
]))
|
||||
);
|
||||
|
||||
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ class Update extends Base
|
|||
|
||||
// Redeploy logic
|
||||
if (!$isConnected && !empty($providerRepositoryId)) {
|
||||
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, new Document(), $github, true);
|
||||
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('siteId', $site->getId());
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class ResourceToken extends Model
|
|||
$expire = $document->getAttribute('expire');
|
||||
|
||||
// Use a large but reasonable maxAge to avoid auto-exp when we set explicit exp
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400 * 365 * 10, 10); // 10 years
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), RESOURCE_TOKEN_ALGORITHM, RESOURCE_TOKEN_MAX_AGE, RESOURCE_TOKEN_LEEWAY); // 10 years
|
||||
|
||||
$payload = [
|
||||
'tokenId' => $document->getId(),
|
||||
|
|
@ -73,13 +73,13 @@ class ResourceToken extends Model
|
|||
'resourceInternalId' => $document->getAttribute('resourceInternalId'),
|
||||
];
|
||||
|
||||
$createdDate = new \DateTime($document->getCreatedAt());
|
||||
$payload['iat'] = $createdDate->getTimestamp();
|
||||
|
||||
// Set explicit expiration in JWT payload if we have an expiry date
|
||||
if ($expire !== null) {
|
||||
$expiryDate = new \DateTime($expire);
|
||||
$payload['exp'] = $expiryDate->getTimestamp();
|
||||
} else {
|
||||
// For infinite expiry, set 'iat' to prevent JWT library from auto-adding 'exp'
|
||||
$payload['iat'] = time();
|
||||
}
|
||||
|
||||
$secret = $jwt->encode($payload);
|
||||
|
|
|
|||
|
|
@ -432,27 +432,4 @@ trait FunctionsBase
|
|||
|
||||
return $specifications;
|
||||
}
|
||||
|
||||
protected function createFunctionRule(string $functionId, string $domain): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/function', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'functionId' => $functionId,
|
||||
'domain' => $domain,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function getFunctionRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
return $rule;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use Utopia\Database\Helpers\ID;
|
|||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\System\System;
|
||||
|
||||
class FunctionsCustomServerTest extends Scope
|
||||
{
|
||||
|
|
@ -393,10 +392,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
|
||||
$rule = $this->createFunctionRule($functionId, $domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
|
||||
$deployment = $this->createTemplateDeployment(
|
||||
$functionId,
|
||||
[
|
||||
|
|
@ -413,20 +408,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
|
||||
$rule = $this->getFunctionRule($rule['body']['$id']);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Deployment is still building", $response['body']);
|
||||
$this->assertStringContainsString("The page will update after the build completes.", $response['body']);
|
||||
|
||||
$deployment = $this->getDeployment($functionId, $deployment['body']['$id']);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
// Wait for deployment to be ready
|
||||
$deploymentId = $deployment['body']['$id'];
|
||||
$this->assertEventually(function () use ($functionId, $deploymentId) {
|
||||
|
|
@ -436,6 +417,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
// Verify deployment sizes
|
||||
$deployment = $this->getDeployment($functionId, $deploymentId);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $deployment['body']['sourceSize']);
|
||||
$this->assertGreaterThan(0, $deployment['body']['buildSize']);
|
||||
$totalSize = $deployment['body']['sourceSize'] + $deployment['body']['buildSize'];
|
||||
|
|
@ -680,10 +662,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
*/
|
||||
$functionId = $data['functionId'];
|
||||
|
||||
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_FUNCTIONS', '');
|
||||
$rule = $this->createFunctionRule($functionId, $domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
|
|
@ -695,18 +673,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.js', $deployment['body']['entrypoint']);
|
||||
|
||||
$rule = $this->getFunctionRule($rule['body']['$id']);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Deployment is still building", $response['body']);
|
||||
$this->assertStringContainsString('The page will update after the build completes.', $response['body']);
|
||||
|
||||
$deploymentIdActive = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEventually(function () use ($functionId, $deploymentIdActive) {
|
||||
|
|
@ -2426,12 +2392,6 @@ class FunctionsCustomServerTest extends Scope
|
|||
$domain = $this->setupFunctionDomain($functionId);
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('No active deployments', $response['body']);
|
||||
$this->assertStringContainsString('View deployments', $response['body']);
|
||||
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
|
|
@ -2444,22 +2404,11 @@ class FunctionsCustomServerTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
]));
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Deployment is still building', $response['body']);
|
||||
$this->assertStringContainsString('The page will update after the build completes.', $response['body']);
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('No active deployments', $response['body']);
|
||||
$this->assertStringContainsString('View deployments', $response['body']);
|
||||
|
||||
// canceled deployment
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test Error Pages',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'timeout' => 15,
|
||||
'commands' => 'cd non-existing-directory',
|
||||
'execute' => ['any']
|
||||
]);
|
||||
$domain = $this->setupFunctionDomain($functionId);
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
$deployment = $this->createDeployment($functionId, [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
'activate' => true
|
||||
|
|
@ -2477,9 +2426,9 @@ class FunctionsCustomServerTest extends Scope
|
|||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
]));
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Deployment build canceled', $response['body']);
|
||||
$this->assertStringContainsString('This build was canceled and won\'t be deployed.', $response['body']);
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('No active deployments', $response['body']);
|
||||
$this->assertStringContainsString('View deployments', $response['body']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,27 +474,4 @@ trait SitesBase
|
|||
|
||||
return $specifications;
|
||||
}
|
||||
|
||||
protected function createSiteRule(string $siteId, string $domain): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_POST, '/proxy/rules/site', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'siteId' => $siteId,
|
||||
'domain' => $domain,
|
||||
]);
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
protected function getSiteRule(string $ruleId): mixed
|
||||
{
|
||||
$rule = $this->client->call(Client::METHOD_GET, '/proxy/rules/' . $ruleId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
return $rule;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -861,10 +861,6 @@ class SitesCustomServerTest extends Scope
|
|||
|
||||
$this->assertNotNull($siteId);
|
||||
|
||||
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$rule = $this->createSiteRule($siteId, $domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
|
||||
$deployment = $this->createDeployment($siteId, [
|
||||
'siteId' => $siteId,
|
||||
'code' => $this->packageSite('static-single-file'),
|
||||
|
|
@ -876,18 +872,6 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertEquals('waiting', $deployment['body']['status']);
|
||||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
|
||||
$rule = $this->getSiteRule($rule['body']['$id']);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Deployment is still building", $response['body']);
|
||||
$this->assertStringContainsString('The page will update after the build completes.', $response['body']);
|
||||
|
||||
$deploymentIdActive = $deployment['body']['$id'] ?? '';
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentIdActive) {
|
||||
|
|
@ -1579,10 +1563,6 @@ class SitesCustomServerTest extends Scope
|
|||
|
||||
$this->assertNotEmpty($siteId);
|
||||
|
||||
$domain = ID::unique() . '.' . System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$rule = $this->createSiteRule($siteId, $domain);
|
||||
$this->assertEquals(201, $rule['headers']['status-code']);
|
||||
|
||||
$deployment = $this->createTemplateDeployment($siteId, [
|
||||
'repository' => $template['providerRepositoryId'],
|
||||
'owner' => $template['providerOwner'],
|
||||
|
|
@ -1595,18 +1575,6 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
$this->assertNotEmpty($deployment['body']['$id']);
|
||||
|
||||
$rule = $this->getSiteRule($rule['body']['$id']);
|
||||
$this->assertEquals(200, $rule['headers']['status-code']);
|
||||
$this->assertEquals($deployment['body']['$id'], $rule['body']['deploymentId']);
|
||||
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Deployment is still building", $response['body']);
|
||||
$this->assertStringContainsString('The page will update after the build completes.', $response['body']);
|
||||
|
||||
$deployment = $this->getDeployment($siteId, $deployment['body']['$id']);
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals(0, $deployment['body']['sourceSize']);
|
||||
|
|
@ -1618,6 +1586,10 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertNotEmpty($site['body']['deploymentId']);
|
||||
}, 50000, 500);
|
||||
|
||||
$domain = $this->setupSiteDomain($siteId);
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
|
|
@ -2612,8 +2584,7 @@ class SitesCustomServerTest extends Scope
|
|||
}, 100000, 500);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('Deployment build failed', $response['body']);
|
||||
$this->assertStringContainsString('This page is empty, activate a deployment to make it live.', $response['body']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
|
@ -2708,12 +2679,6 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertNotEmpty($siteId);
|
||||
|
||||
$domain = $this->setupSiteDomain($siteId);
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('No active deployments', $response['body']);
|
||||
$this->assertStringContainsString('View deployments', $response['body']);
|
||||
|
||||
// test canceled deployment error page
|
||||
$deployment = $this->createDeployment($siteId, [
|
||||
|
|
@ -2749,6 +2714,13 @@ class SitesCustomServerTest extends Scope
|
|||
$this->assertStringContainsString("Deployment build canceled", $response['body']);
|
||||
$this->assertStringContainsString("View deployments", $response['body']);
|
||||
|
||||
// check site domain for no active deployments
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(404, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString('No active deployments', $response['body']);
|
||||
$this->assertStringContainsString('View deployments', $response['body']);
|
||||
|
||||
$deployment = $this->createDeployment($siteId, [
|
||||
'code' => $this->packageSite('static-single-file'),
|
||||
'activate' => 'true'
|
||||
|
|
|
|||
|
|
@ -72,37 +72,45 @@ class TokensConsoleClientTest extends Scope
|
|||
$this->assertEquals(400, $token['headers']['status-code']);
|
||||
$this->assertStringContainsString('Value must be valid date in the future', $token['body']['message']);
|
||||
|
||||
// Success case: No expire date
|
||||
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'expire' => null,
|
||||
]);
|
||||
// Success cases: With & without expiry
|
||||
$expireList = [null, date('Y-m-d', strtotime("tomorrow"))];
|
||||
foreach ($expireList as $expire) {
|
||||
$token = $this->client->call(Client::METHOD_POST, '/tokens/buckets/' . $bucketId . '/files/' . $fileId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id']
|
||||
], $this->getHeaders()), [
|
||||
'expire' => $expire,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $token['headers']['status-code']);
|
||||
$this->assertEquals('files', $token['body']['resourceType']);
|
||||
$this->assertNotEmpty($token['body']['$id']);
|
||||
$this->assertNotEmpty($token['body']['secret']);
|
||||
$this->assertEquals(201, $token['headers']['status-code']);
|
||||
$this->assertEquals('files', $token['body']['resourceType']);
|
||||
$this->assertNotEmpty($token['body']['$id']);
|
||||
$this->assertNotEmpty($token['body']['secret']);
|
||||
|
||||
// Verify the generated token JWT contains correct resource information
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400 * 365 * 10, 10); // 10 years maxAge
|
||||
try {
|
||||
$payload = $jwt->decode($token['body']['secret']);
|
||||
$this->assertIsArray($payload, 'JWT payload should decode to an array');
|
||||
$this->assertArrayHasKey('tokenId', $payload, 'JWT payload should contain tokenId');
|
||||
$this->assertArrayHasKey('resourceId', $payload, 'JWT payload should contain resourceId');
|
||||
$this->assertArrayHasKey('resourceType', $payload, 'JWT payload should contain resourceType');
|
||||
$this->assertArrayHasKey('resourceInternalId', $payload, 'JWT payload should contain resourceInternalId');
|
||||
// Verify the generated token JWT contains correct resource information
|
||||
$jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', 86400 * 365 * 10, 10); // 10 years maxAge
|
||||
try {
|
||||
$payload = $jwt->decode($token['body']['secret']);
|
||||
$this->assertIsArray($payload, 'JWT payload should decode to an array');
|
||||
$this->assertArrayHasKey('tokenId', $payload, 'JWT payload should contain tokenId');
|
||||
$this->assertArrayHasKey('resourceId', $payload, 'JWT payload should contain resourceId');
|
||||
$this->assertArrayHasKey('resourceType', $payload, 'JWT payload should contain resourceType');
|
||||
$this->assertArrayHasKey('resourceInternalId', $payload, 'JWT payload should contain resourceInternalId');
|
||||
$this->assertArrayHasKey('iat', $payload, 'JWT payload should contain iat');
|
||||
|
||||
$this->assertEquals($token['body']['$id'], $payload['tokenId'], 'JWT tokenId should match token ID');
|
||||
$this->assertEquals($bucketId . ':' . $fileId, $payload['resourceId'], 'JWT resourceId should match bucketId:fileId format');
|
||||
$this->assertEquals('files', $payload['resourceType'], 'JWT resourceType should be files');
|
||||
if (!empty($expire)) {
|
||||
$this->assertArrayHasKey('exp', $payload, 'JWT payload should contain exp');
|
||||
} else {
|
||||
$this->assertArrayNotHasKey('exp', $payload, 'JWT payload should not contain exp field for tokens without expiry');
|
||||
}
|
||||
|
||||
// For newly created tokens without expiry, should not have exp field
|
||||
$this->assertArrayNotHasKey('exp', $payload, 'JWT payload should not contain exp field for tokens without expiry');
|
||||
} catch (JWTException $e) {
|
||||
$this->fail('Failed to decode JWT: ' . $e->getMessage());
|
||||
$this->assertEquals($token['body']['$id'], $payload['tokenId'], 'JWT tokenId should match token ID');
|
||||
$this->assertEquals($bucketId . ':' . $fileId, $payload['resourceId'], 'JWT resourceId should match bucketId:fileId format');
|
||||
$this->assertEquals('files', $payload['resourceType'], 'JWT resourceType should be files');
|
||||
|
||||
} catch (JWTException $e) {
|
||||
$this->fail('Failed to decode JWT: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
|
|
@ -218,6 +226,11 @@ class TokensConsoleClientTest extends Scope
|
|||
$this->assertArrayHasKey('resourceId', $payload, 'JWT payload should contain resourceId');
|
||||
$this->assertArrayHasKey('resourceType', $payload, 'JWT payload should contain resourceType');
|
||||
$this->assertArrayHasKey('resourceInternalId', $payload, 'JWT payload should contain resourceInternalId');
|
||||
$this->assertArrayHasKey('iat', $payload, 'JWT payload should contain iat');
|
||||
|
||||
if (!empty($token['expire'])) {
|
||||
$this->assertArrayHasKey('exp', $payload, 'JWT payload should contain exp');
|
||||
}
|
||||
|
||||
$this->assertEquals($token['$id'], $payload['tokenId'], 'JWT tokenId should match token ID');
|
||||
$this->assertEquals($data['bucketId'] . ':' . $data['fileId'], $payload['resourceId'], 'JWT resourceId should match bucketId:fileId format');
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use Utopia\Cache\Adapter\None;
|
|||
use Utopia\Cache\Cache;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\System\System;
|
||||
use Utopia\VCS\Adapter\Git\GitHub;
|
||||
|
||||
|
|
@ -316,6 +317,43 @@ class VCSConsoleClientTest extends Scope
|
|||
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['name'], 'appwrite');
|
||||
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['runtime'], 'other');
|
||||
|
||||
// with limit and offset
|
||||
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'type' => 'runtime',
|
||||
'limit' => Query::limit(1)->toString(),
|
||||
'offset' => Query::offset(0)->toString()
|
||||
]);
|
||||
$this->assertSame(200, $repositories['headers']['status-code']);
|
||||
$this->assertSame(4, $repositories['body']['total']);
|
||||
$this->assertCount(1, $repositories['body']['runtimeProviderRepositories']);
|
||||
$this->assertSame('starter-for-svelte', $repositories['body']['runtimeProviderRepositories'][0]['name']);
|
||||
|
||||
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'type' => 'runtime',
|
||||
'limit' => Query::limit(2)->toString(),
|
||||
'offset' => Query::offset(2)->toString()
|
||||
]);
|
||||
$this->assertSame(200, $repositories['headers']['status-code']);
|
||||
$this->assertSame(4, $repositories['body']['total']);
|
||||
$this->assertCount(2, $repositories['body']['runtimeProviderRepositories']);
|
||||
$this->assertSame('appwrite', $repositories['body']['runtimeProviderRepositories'][0]['name']);
|
||||
$this->assertSame('ruby-starter', $repositories['body']['runtimeProviderRepositories'][1]['name']);
|
||||
|
||||
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'type' => 'runtime',
|
||||
'limit' => Query::limit(2)->toString(),
|
||||
'offset' => Query::offset(100)->toString()
|
||||
]);
|
||||
$this->assertSame(200, $repositories['headers']['status-code']);
|
||||
$this->assertSame(4, $repositories['body']['total']);
|
||||
$this->assertCount(0, $repositories['body']['runtimeProviderRepositories']);
|
||||
|
||||
// TODO: If you are about to add another check, rewrite this to @provideScenarios
|
||||
|
||||
/**
|
||||
|
|
@ -338,6 +376,17 @@ class VCSConsoleClientTest extends Scope
|
|||
|
||||
$this->assertEquals(400, $repositories['headers']['status-code']);
|
||||
|
||||
// invalid offset
|
||||
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'type' => 'runtime',
|
||||
'limit' => Query::limit(2)->toString(),
|
||||
'offset' => Query::offset(1)->toString()
|
||||
]);
|
||||
$this->assertEquals(400, $repositories['headers']['status-code']);
|
||||
$this->assertEquals('offset must be a multiple of the limit', $repositories['body']['message']);
|
||||
|
||||
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
|
|
|
|||
Loading…
Reference in a new issue