From f8fb2e8c2d226813f02e7e8b389646e4b246c8eb Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 10 Feb 2026 00:01:40 +0000 Subject: [PATCH 01/40] Chore: test group --- tests/e2e/General/HTTPTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 4012745682..56f3cb7fb0 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -18,6 +18,11 @@ class HTTPTest extends Scope $this->client->setEndpoint('http://appwrite.test'); } + /** + * @group ci-ignore + * + * @return void + */ public function testOptions() { /** From bb76becf81ce76926d2bf88edf0e5ca511d6714b Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Tue, 10 Feb 2026 10:52:53 +0000 Subject: [PATCH 02/40] Add CORS configuration and refactor CORS resource handling --- app/config/cors.php | 53 +++++++++++++++++++++++++++++++++++++ app/init/configs.php | 1 + app/init/resources.php | 59 ++++++++---------------------------------- 3 files changed, 65 insertions(+), 48 deletions(-) create mode 100644 app/config/cors.php diff --git a/app/config/cors.php b/app/config/cors.php new file mode 100644 index 0000000000..ef1adeb998 --- /dev/null +++ b/app/config/cors.php @@ -0,0 +1,53 @@ + ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], + 'allowedHeaders' => [ + 'Accept', + 'Origin', + 'Cookie', + 'Set-Cookie', + // Content + 'Content-Type', + 'Content-Range', + // Appwrite + 'X-Appwrite-Project', + 'X-Appwrite-Key', + 'X-Appwrite-Dev-Key', + 'X-Appwrite-Locale', + 'X-Appwrite-Mode', + 'X-Appwrite-JWT', + 'X-Appwrite-Response-Format', + 'X-Appwrite-Timeout', + 'X-Appwrite-ID', + 'X-Appwrite-Timestamp', + 'X-Appwrite-Session', + 'X-Appwrite-Platform', + // SDK generator + 'X-SDK-Version', + 'X-SDK-Name', + 'X-SDK-Language', + 'X-SDK-Platform', + 'X-SDK-GraphQL', + 'X-SDK-Profile', + // Caching + 'Range', + 'Cache-Control', + 'Expires', + 'Pragma', + // Server to server + 'X-Fallback-Cookies', + 'X-Requested-With', + 'X-Forwarded-For', + 'X-Forwarded-User-Agent', + ], + 'exposedHeaders' => [ + 'X-Appwrite-Session', + 'X-Fallback-Cookies', + ], +]; diff --git a/app/init/configs.php b/app/init/configs.php index d5748707cf..35c8e3899d 100644 --- a/app/init/configs.php +++ b/app/init/configs.php @@ -46,3 +46,4 @@ Config::load('storage-outputs', __DIR__ . '/../config/storage/outputs.php', $con Config::load('specifications', __DIR__ . '/../config/specifications.php', $configAdapter); Config::load('templates-function', __DIR__ . '/../config/templates/function.php', $configAdapter); Config::load('templates-site', __DIR__ . '/../config/templates/site.php', $configAdapter); +Config::load('cors', __DIR__ . '/../config/cors.php', $configAdapter); diff --git a/app/init/resources.php b/app/init/resources.php index 8f78df1573..792efce4f7 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -296,54 +296,17 @@ Http::setResource('rule', function (Request $request, Database $dbForPlatform, D /** * CORS service */ -Http::setResource('cors', fn (array $allowedHostnames) => new Cors( - $allowedHostnames, - allowedMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], - allowedHeaders: [ - 'Accept', - 'Origin', - 'Cookie', - 'Set-Cookie', - // Content - 'Content-Type', - 'Content-Range', - // Appwrite - 'X-Appwrite-Project', - 'X-Appwrite-Key', - 'X-Appwrite-Dev-Key', - 'X-Appwrite-Locale', - 'X-Appwrite-Mode', - 'X-Appwrite-JWT', - 'X-Appwrite-Response-Format', - 'X-Appwrite-Timeout', - 'X-Appwrite-ID', - 'X-Appwrite-Timestamp', - 'X-Appwrite-Session', - 'X-Appwrite-Platform', // for `$platform` injection and SDK generator - // SDK generator - 'X-SDK-Version', - 'X-SDK-Name', - 'X-SDK-Language', - 'X-SDK-Platform', - 'X-SDK-GraphQL', - 'X-SDK-Profile', - // Caching - 'Range', - 'Cache-Control', - 'Expires', - 'Pragma', - // Server to server - 'X-Fallback-Cookies', - 'X-Requested-With', - 'X-Forwarded-For', - 'X-Forwarded-User-Agent', - ], - allowCredentials: true, - exposedHeaders: [ - 'X-Appwrite-Session', - 'X-Fallback-Cookies', - ], -), ['allowedHostnames']); +Http::setResource('cors', function (array $allowedHostnames) { + $corsConfig = Config::getParam('cors'); + + return new Cors( + $allowedHostnames, + allowedMethods: $corsConfig['allowedMethods'], + allowedHeaders: $corsConfig['allowedHeaders'], + allowCredentials: true, + exposedHeaders: $corsConfig['exposedHeaders'], + ); +}, ['allowedHostnames']); Http::setResource('originValidator', function (Document $devKey, array $allowedHostnames, array $allowedSchemes) { if (!$devKey->isEmpty()) { From ac35e7c7ad8f366097368f0900886cf057c9ac24 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 11 Feb 2026 01:59:09 +0000 Subject: [PATCH 03/40] update test to use the config --- tests/e2e/General/HTTPTest.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 56f3cb7fb0..743b7169a8 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -6,6 +6,7 @@ use Tests\E2E\Client; use Tests\E2E\Scopes\ProjectNone; use Tests\E2E\Scopes\Scope; use Tests\E2E\Scopes\SideNone; +use Utopia\Config\Config; class HTTPTest extends Scope { @@ -33,11 +34,16 @@ class HTTPTest extends Scope 'content-type' => 'application/json', ]), []); + $corsConfig = Config::getParam('cors'); + $allowedMethods = \implode(', ', $corsConfig['allowedMethods']); + $allowedHeaders = \implode(', ', $corsConfig['allowedHeaders']); + $exposedHeaders = \implode(', ', $corsConfig['exposedHeaders']); + $this->assertEquals(204, $response['headers']['status-code']); $this->assertEquals('Appwrite', $response['headers']['server']); - $this->assertEquals('GET, POST, PUT, PATCH, DELETE', $response['headers']['access-control-allow-methods']); - $this->assertEquals('Accept, Origin, Cookie, Set-Cookie, Content-Type, Content-Range, X-Appwrite-Project, X-Appwrite-Key, X-Appwrite-Dev-Key, X-Appwrite-Locale, X-Appwrite-Mode, X-Appwrite-JWT, X-Appwrite-Response-Format, X-Appwrite-Timeout, X-Appwrite-ID, X-Appwrite-Timestamp, X-Appwrite-Session, X-Appwrite-Platform, X-SDK-Version, X-SDK-Name, X-SDK-Language, X-SDK-Platform, X-SDK-GraphQL, X-SDK-Profile, Range, Cache-Control, Expires, Pragma, X-Fallback-Cookies, X-Requested-With, X-Forwarded-For, X-Forwarded-User-Agent', $response['headers']['access-control-allow-headers']); - $this->assertEquals('X-Appwrite-Session, X-Fallback-Cookies', $response['headers']['access-control-expose-headers']); + $this->assertEquals($allowedMethods, $response['headers']['access-control-allow-methods']); + $this->assertEquals($allowedHeaders, $response['headers']['access-control-allow-headers']); + $this->assertEquals($exposedHeaders, $response['headers']['access-control-expose-headers']); $this->assertEquals('http://localhost', $response['headers']['access-control-allow-origin']); $this->assertEquals('true', $response['headers']['access-control-allow-credentials']); $this->assertEmpty($response['body']); From 6b8b11e1675e22c31120814c64e4c6d0d570d201 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Wed, 11 Feb 2026 02:00:38 +0000 Subject: [PATCH 04/40] no longer ignore --- tests/e2e/General/HTTPTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/e2e/General/HTTPTest.php b/tests/e2e/General/HTTPTest.php index 743b7169a8..261bab9348 100644 --- a/tests/e2e/General/HTTPTest.php +++ b/tests/e2e/General/HTTPTest.php @@ -19,11 +19,6 @@ class HTTPTest extends Scope $this->client->setEndpoint('http://appwrite.test'); } - /** - * @group ci-ignore - * - * @return void - */ public function testOptions() { /** From 2db6f7e72f7b4ff1f587c1eb26f06f861663e1f1 Mon Sep 17 00:00:00 2001 From: fogelito Date: Thu, 12 Feb 2026 07:54:30 +0200 Subject: [PATCH 05/40] check $ruleType --- src/Appwrite/Utopia/Response.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index fd518e4a9a..3fc043725d 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -456,6 +456,8 @@ class Response extends SwooleResponse foreach ($data[$key] as $index => $item) { if ($item instanceof Document) { + $ruleType = null; + if (\is_array($rule['type'])) { foreach ($rule['type'] as $type) { $condition = false; @@ -474,7 +476,7 @@ class Response extends SwooleResponse $ruleType = $rule['type']; } - if (!self::hasModel($ruleType)) { + if ($ruleType === null || !self::hasModel($ruleType)) { throw new Exception('Missing model for rule: ' . $ruleType); } From 5d5fd370c680bd4a0a5d986e1325555651e1d978 Mon Sep 17 00:00:00 2001 From: Damodar Lohani Date: Fri, 13 Feb 2026 11:32:46 +0000 Subject: [PATCH 06/40] fix: cast Redis ping response to boolean --- src/Appwrite/PubSub/Adapter/Redis.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/PubSub/Adapter/Redis.php b/src/Appwrite/PubSub/Adapter/Redis.php index 187eb9cd95..f5218df93c 100644 --- a/src/Appwrite/PubSub/Adapter/Redis.php +++ b/src/Appwrite/PubSub/Adapter/Redis.php @@ -16,7 +16,7 @@ class Redis implements Adapter public function ping($message = null): bool { - return $this->client->ping($message); + return (bool) $this->client->ping($message); } public function subscribe($channels, $callback) From a44a22ce048f70ea48e66b56d1468f48698ab433 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 13 Feb 2026 13:29:54 +0000 Subject: [PATCH 07/40] Update utopia-php/span to 1.1.* with pretty exporter and instrument HTTP lifecycle - Add utopia-php/span 1.1.* direct dependency, bump utopia-php/dns to 1.6.* - Create shared app/init/span.php for span storage and pretty exporter setup - Instrument HTTP request lifecycle with spans (method, path, response code) - Add database.setup and http.server.start spans - Replace old Console error logs with Span::error() in general controller Co-Authored-By: Claude Opus 4.6 --- app/cli.php | 6 +--- app/controllers/general.php | 13 ++------ app/http.php | 64 ++++++++++++++++++++++--------------- app/init/span.php | 8 +++++ app/worker.php | 6 +--- composer.json | 3 +- composer.lock | 31 +++++++++--------- 7 files changed, 69 insertions(+), 62 deletions(-) create mode 100644 app/init/span.php diff --git a/app/cli.php b/app/cli.php index 14ebea6e1c..0f8426afd9 100644 --- a/app/cli.php +++ b/app/cli.php @@ -30,9 +30,6 @@ use Utopia\Pools\Group; use Utopia\Queue\Broker\Pool as BrokerPool; use Utopia\Queue\Publisher; use Utopia\Registry\Registry; -use Utopia\Span\Exporter; -use Utopia\Span\Span; -use Utopia\Span\Storage; use Utopia\System\System; use Utopia\Telemetry\Adapter\None as NoTelemetry; @@ -340,6 +337,5 @@ $cli $cli->shutdown()->action(fn () => Timer::clearAll()); Runtime::enableCoroutine(SWOOLE_HOOK_ALL); -Span::setStorage(new Storage\Coroutine()); -Span::addExporter(new Exporter\Stdout()); +require_once __DIR__ . '/init/span.php'; run($cli->run(...)); diff --git a/app/controllers/general.php b/app/controllers/general.php index a4f364485e..2d3bde69d6 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -52,6 +52,7 @@ use Utopia\Logger\Log; use Utopia\Logger\Log\User; use Utopia\Logger\Logger; use Utopia\Platform\Service; +use Utopia\Span\Span; use Utopia\System\System; use Utopia\Validator; use Utopia\Validator\Text; @@ -1245,17 +1246,7 @@ Http::error() $trace = $error->getTrace(); if (php_sapi_name() === 'cli') { - Console::error('[Error] Timestamp: ' . date('c', time())); - - if ($route) { - Console::error('[Error] Method: ' . $route->getMethod()); - Console::error('[Error] URL: ' . $route->getPath()); - } - - Console::error('[Error] Type: ' . get_class($error)); - Console::error('[Error] Message: ' . $message); - Console::error('[Error] File: ' . $file); - Console::error('[Error] Line: ' . $line); + Span::error($error); } switch ($class) { diff --git a/app/http.php b/app/http.php index d5af8eacea..1d7949da86 100644 --- a/app/http.php +++ b/app/http.php @@ -1,6 +1,7 @@ on(Constant::EVENT_WORKER_START, function ($server, $workerId) use (&$fil $files = new Files(); $files->load(__DIR__ . '/../public'); } - Console::success('Worker ' . ++$workerId . ' started successfully'); }); $http->on(Constant::EVENT_WORKER_STOP, function ($server, $workerId) { @@ -207,17 +208,18 @@ function createDatabase(Http $app, string $resourceKey, string $dbName, array $c } } - Console::success("[Setup] - $dbName database init started..."); + Span::init("database.setup"); + Span::add('database.name', $dbName); // Attempt to create the database try { - Console::info(" └── Creating database: $dbName..."); $database->create(); } catch (\Exception $e) { - Console::info(" └── Skip: metadata table already exists"); + Span::add('database.exists', true); } // Process collections + $collectionsCreated = 0; foreach ($collections as $key => $collection) { if (($collection['$collection'] ?? '') !== Database::METADATA) { continue; @@ -227,8 +229,6 @@ function createDatabase(Http $app, string $resourceKey, string $dbName, array $c continue; } - Console::info(" └── Creating collection: {$collection['$id']}..."); - $attributes = array_map(fn ($attr) => new Document([ '$id' => ID::custom($attr['$id']), 'type' => $attr['type'], @@ -250,14 +250,19 @@ function createDatabase(Http $app, string $resourceKey, string $dbName, array $c ]), $collection['indexes']); $database->createCollection($key, $attributes, $indexes); + $collectionsCreated++; } + Span::add('database.collections_created', $collectionsCreated); + if ($extraSetup) { $extraSetup($database); } + + Span::current()?->finish(); } -$http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $register) { +$http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $totalWorkers, $register) { $app = new Http('UTC'); go(function () use ($register, $app) { @@ -282,7 +287,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg } if ($dbForPlatform->getDocument('buckets', 'default')->isEmpty()) { - Console::info(" └── Creating default bucket..."); $dbForPlatform->createDocument('buckets', new Document([ '$id' => ID::custom('default'), '$collection' => ID::custom('buckets'), @@ -305,7 +309,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $bucket = $dbForPlatform->getDocument('buckets', 'default'); - Console::info(" └── Creating files collection for default bucket..."); $files = $collections['buckets']['files'] ?? []; if (empty($files)) { throw new Exception('Files collection is not configured.'); @@ -335,7 +338,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg } if ($authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')->isEmpty())) { - Console::info(" └── Creating screenshots bucket..."); $authorization->skip(fn () => $dbForPlatform->createDocument('buckets', new Document([ '$id' => ID::custom('screenshots'), '$collection' => ID::custom('buckets'), @@ -353,7 +355,6 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $bucket = $authorization->skip(fn () => $dbForPlatform->getDocument('buckets', 'screenshots')); - Console::info(" └── Creating files collection for screenshots bucket..."); $files = $collections['buckets']['files'] ?? []; if (empty($files)) { throw new Exception('Files collection is not configured.'); @@ -391,6 +392,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $cache = $app->getResource('cache'); foreach ($sharedTablesV2 as $hostname) { + Span::init('database.setup'); + Span::add('database.hostname', $hostname); + $adapter = new DatabasePool($pools->get($hostname)); $dbForProject = (new Database($adapter, $cache)) ->setDatabase('appwrite') @@ -399,10 +403,9 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg ->setNamespace(System::getEnv('_APP_DATABASE_SHARED_NAMESPACE', '')); try { - Console::success('[Setup] - Creating project database: ' . $hostname . '...'); $dbForProject->create(); } catch (DuplicateException) { - Console::success('[Setup] - Skip: metadata table already exists'); + Span::add('database.exists', true); } if ($dbForProject->getCollection(AuditAdapterSQL::COLLECTION)->isEmpty()) { @@ -411,6 +414,7 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $audit->setup(); } + $collectionsCreated = 0; foreach ($projectCollections as $key => $collection) { if (($collection['$collection'] ?? '') !== Database::METADATA) { continue; @@ -422,17 +426,21 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg $attributes = \array_map(fn ($attribute) => new Document($attribute), $collection['attributes']); $indexes = \array_map(fn (array $index) => new Document($index), $collection['indexes']); - Console::success('[Setup] - Creating project collection: ' . $collection['$id'] . '...'); - $dbForProject->createCollection($key, $attributes, $indexes); + $collectionsCreated++; } - } - Console::success('[Setup] - Server database init completed...'); + Span::add('database.collections_created', $collectionsCreated); + Span::current()?->finish(); + } }); - Console::success('Server started successfully (max payload is ' . number_format($payloadSize) . ' bytes)'); - Console::info("Master pid {$http->master_pid}, manager pid {$http->manager_pid}"); + Span::init('http.server.start'); + Span::add('server.workers', $totalWorkers); + Span::add('server.payload_size', $payloadSize); + Span::add('server.master_pid', $http->master_pid); + Span::add('server.manager_pid', $http->manager_pid); + Span::current()?->finish(); // Start the task that starts fetching custom domains $http->task([], 0); @@ -445,12 +453,16 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $reg }); $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, SwooleResponse $swooleResponse) use ($register, &$files) { + Span::init('http.request'); + Http::setResource('swooleRequest', fn () => $swooleRequest); Http::setResource('swooleResponse', fn () => $swooleResponse); $request = new Request($swooleRequest); $response = new Response($swooleResponse); + Span::add('http.method', $request->getMethod()); + if ($files instanceof Files && $files->isFileLoaded($request->getURI())) { $time = (60 * 60 * 24 * 45); // 45 days cache @@ -479,7 +491,12 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool $authorization->addRole(Role::any()->toString()); $app->run($request, $response); + + $route = $app->getRoute(); + Span::add('http.path', $route?->getPath() ?? 'unknown'); } catch (\Throwable $th) { + Span::error($th); + $version = System::getEnv('_APP_VERSION', 'UNKNOWN'); $logger = $app->getResource("logger"); @@ -542,12 +559,6 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool } } - Console::error('[Error] Type: ' . get_class($th)); - Console::error('[Error] Message: ' . $th->getMessage()); - Console::error('[Error] File: ' . $th->getFile()); - Console::error('[Error] Line: ' . $th->getLine()); - Console::error('[Error] Trace: ' . $th->getTraceAsString()); - $swooleResponse->setStatusCode(500); $output = ((Http::isDevelopment())) ? [ @@ -564,6 +575,9 @@ $http->on(Constant::EVENT_REQUEST, function (SwooleRequest $swooleRequest, Swool ]; $swooleResponse->end(\json_encode($output)); + } finally { + Span::add('http.response.code', $response->getStatusCode()); + Span::current()?->finish(); } }); diff --git a/app/init/span.php b/app/init/span.php new file mode 100644 index 0000000000..76f37f5300 --- /dev/null +++ b/app/init/span.php @@ -0,0 +1,8 @@ + $register); diff --git a/composer.json b/composer.json index 354762e90b..15346eb169 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,7 @@ "utopia-php/detector": "0.2.*", "utopia-php/domains": "1.*", "utopia-php/emails": "0.6.*", - "utopia-php/dns": "1.5.*", + "utopia-php/dns": "1.6.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", "utopia-php/fetch": "0.5.*", @@ -68,6 +68,7 @@ "utopia-php/migration": "1.5.*", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", + "utopia-php/span": "1.1.*", "utopia-php/preloader": "0.2.*", "utopia-php/queue": "0.15.*", "utopia-php/registry": "0.5.*", diff --git a/composer.lock b/composer.lock index 58179608ab..f522fc29ca 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": "bc64aa37fc3ab6fa2acf7ac8f5456e9f", + "content-hash": "9397ae16877660a3ea485cfdcaab906c", "packages": [ { "name": "adhocore/jwt", @@ -3948,22 +3948,22 @@ }, { "name": "utopia-php/dns", - "version": "1.5.4", + "version": "1.6.2", "source": { "type": "git", "url": "https://github.com/utopia-php/dns.git", - "reference": "ee831a6f2ceb28babb042ea65539c26ea4530bf6" + "reference": "98c70520213a41e2fe1867e5b110273c06bf1cab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dns/zipball/ee831a6f2ceb28babb042ea65539c26ea4530bf6", - "reference": "ee831a6f2ceb28babb042ea65539c26ea4530bf6", + "url": "https://api.github.com/repos/utopia-php/dns/zipball/98c70520213a41e2fe1867e5b110273c06bf1cab", + "reference": "98c70520213a41e2fe1867e5b110273c06bf1cab", "shasum": "" }, "require": { "php": ">=8.3", "utopia-php/domains": "1.0.*", - "utopia-php/span": "1.0.*", + "utopia-php/span": "1.1.*", "utopia-php/telemetry": "*", "utopia-php/validators": "0.*" }, @@ -3999,9 +3999,9 @@ ], "support": { "issues": "https://github.com/utopia-php/dns/issues", - "source": "https://github.com/utopia-php/dns/tree/1.5.4" + "source": "https://github.com/utopia-php/dns/tree/1.6.2" }, - "time": "2026-02-02T10:40:38+00:00" + "time": "2026-02-13T12:29:08+00:00" }, { "name": "utopia-php/domains", @@ -4909,25 +4909,26 @@ }, { "name": "utopia-php/span", - "version": "1.0.0", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "f2f6c499ded3a776e8019902e83d140ff0f89693" + "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/f2f6c499ded3a776e8019902e83d140ff0f89693", - "reference": "f2f6c499ded3a776e8019902e83d140ff0f89693", + "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { "laravel/pint": "^1.0", "phpstan/phpstan": "^2.0", "phpunit/phpunit": "^10.0", + "rector/rector": "^2.3", "swoole/ide-helper": "^5.0" }, "suggest": { @@ -4946,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.0.0" + "source": "https://github.com/utopia-php/span/tree/1.1.4" }, - "time": "2026-01-12T20:05:10+00:00" + "time": "2026-02-13T10:58:12+00:00" }, { "name": "utopia-php/storage", From 9dc000d0c5be3f870330391069579fa16603c461 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:40:47 +0000 Subject: [PATCH 08/40] Replace region check with project ID check for execution logging Switch from checking _APP_REGION !== 'nyc' to checking project ID to disable execution logging for a specific project. Co-Authored-By: Claude Opus 4.6 --- .../Platform/Modules/Functions/Http/Executions/Create.php | 6 +++--- src/Appwrite/Platform/Workers/Executions.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php index 0c497df6ea..4f1c7822ec 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Executions/Create.php @@ -301,7 +301,7 @@ class Create extends Base if ($async) { if (is_null($scheduledAt)) { - if (System::getEnv('_APP_REGION') !== 'nyc') { // TODO: Remove region check + if ($project->getId() != '6862e6a6000cce69f9da') { $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); } $queueForFunctions @@ -344,7 +344,7 @@ class Create extends Base ->setAttribute('scheduleInternalId', $schedule->getSequence()) ->setAttribute('scheduledAt', $scheduledAt); - if (System::getEnv('_APP_REGION') !== 'nyc') { // TODO: Remove region check + if ($project->getId() != '6862e6a6000cce69f9da') { $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); } } @@ -505,7 +505,7 @@ class Create extends Base ->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_FUNCTIONS, $function->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS), (int)(($spec['memory'] ?? APP_COMPUTE_MEMORY_DEFAULT) * $execution->getAttribute('duration', 0) * ($spec['cpus'] ?? APP_COMPUTE_CPUS_DEFAULT))) ; - if (System::getEnv('_APP_REGION') !== 'nyc') { // TODO: Remove region check + if ($project->getId() != '6862e6a6000cce69f9da') { $execution = $authorization->skip(fn () => $dbForProject->createDocument('executions', $execution)); } } diff --git a/src/Appwrite/Platform/Workers/Executions.php b/src/Appwrite/Platform/Workers/Executions.php index 300a84162c..d874e26267 100644 --- a/src/Appwrite/Platform/Workers/Executions.php +++ b/src/Appwrite/Platform/Workers/Executions.php @@ -7,7 +7,6 @@ use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Platform\Action; use Utopia\Queue\Message; -use Utopia\System\System; class Executions extends Action { @@ -45,7 +44,8 @@ class Executions extends Action throw new Exception('Missing execution'); } - if (System::getEnv('_APP_REGION') !== 'nyc') { // TODO: Remove region check + $project = new Document($payload['project'] ?? []); + if ($project->getId() != '6862e6a6000cce69f9da') { $dbForProject->upsertDocument('executions', $execution); } } From baa6599cef049fe51690c3ac34cb6cbe0bf4b49f Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:53:56 +0000 Subject: [PATCH 09/40] ci: upgrade docker/login-action from v2 to v3 Co-Authored-By: Claude Opus 4.6 --- .github/workflows/publish.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 180eb5428d..5579317e90 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -24,7 +24,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5426f53583..cf09663a06 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} From 3a07a4b1331b5b8794704e197127552d624295e6 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 13:40:42 +0200 Subject: [PATCH 10/40] attributes types --- composer.json | 2 +- composer.lock | 65 +++++++++++-------- .../Services/Migrations/MigrationsBase.php | 41 +++++++++++- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/composer.json b/composer.json index 15346eb169..2ff5e46cf3 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", - "utopia-php/migration": "1.5.*", + "utopia-php/migration": "dev-text-attributes as 1.5.2", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", "utopia-php/span": "1.1.*", diff --git a/composer.lock b/composer.lock index f522fc29ca..4cad22d4c1 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": "9397ae16877660a3ea485cfdcaab906c", + "content-hash": "dff51ff51a89f58125ee9a59c860a92a", "packages": [ { "name": "adhocore/jwt", @@ -3797,16 +3797,16 @@ }, { "name": "utopia-php/database", - "version": "5.1.1", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "94815bfa605282096272625827d0314f9ed99066" + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/94815bfa605282096272625827d0314f9ed99066", - "reference": "94815bfa605282096272625827d0314f9ed99066", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5c89b39de00f2b3126d0fbbdea36786341293df7", + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7", "shasum": "" }, "require": { @@ -3849,9 +3849,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/5.1.1" + "source": "https://github.com/utopia-php/database/tree/5.2.0" }, - "time": "2026-02-12T11:44:58+00:00" + "time": "2026-02-14T09:37:28+00:00" }, { "name": "utopia-php/detector", @@ -4464,16 +4464,16 @@ }, { "name": "utopia-php/migration", - "version": "1.5.2", + "version": "dev-text-attributes", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "93904948f6dd07491821615fd9b9acbcaadec12e" + "reference": "481539d4fcf998f8d5f1ed3871c42318058c4b40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/93904948f6dd07491821615fd9b9acbcaadec12e", - "reference": "93904948f6dd07491821615fd9b9acbcaadec12e", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/481539d4fcf998f8d5f1ed3871c42318058c4b40", + "reference": "481539d4fcf998f8d5f1ed3871c42318058c4b40", "shasum": "" }, "require": { @@ -4513,9 +4513,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.5.2" + "source": "https://github.com/utopia-php/migration/tree/text-attributes" }, - "time": "2026-02-11T06:19:35+00:00" + "time": "2026-02-15T11:19:13+00:00" }, { "name": "utopia-php/mongo", @@ -4909,16 +4909,16 @@ }, { "name": "utopia-php/span", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "url": "https://api.github.com/repos/utopia-php/span/zipball/028406940ca92bdc88099f0b1a123a3b2cbdd4e5", + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5", "shasum": "" }, "require": { @@ -4947,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.1.4" + "source": "https://github.com/utopia-php/span/tree/1.1.5" }, - "time": "2026-02-13T10:58:12+00:00" + "time": "2026-02-13T18:00:11+00:00" }, { "name": "utopia-php/storage", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0" + "reference": "02587e667091df7fb9a0f79fb080b28cada92706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/02587e667091df7fb9a0f79fb080b28cada92706", + "reference": "02587e667091df7fb9a0f79fb080b28cada92706", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.1" }, - "time": "2026-02-12T12:08:13+00:00" + "time": "2026-02-13T16:33:55+00:00" }, { "name": "doctrine/annotations", @@ -8888,9 +8888,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/migration", + "version": "dev-text-attributes", + "alias": "1.5.2", + "alias_normalized": "1.5.2.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/migration": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8914,5 +8923,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index aad0b73aa9..2bcfd11059 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1250,9 +1250,38 @@ trait MigrationsBase 'size' => 255, 'required' => false, ]); - $this->assertEquals(202, $email['headers']['status-code']); + $text = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/text', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'regulartext', + 'required' => false, + ]); + $this->assertEquals(202, $text['headers']['status-code']); + + $mediumtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'mediumtext', + 'required' => false, + ]); + $this->assertEquals(202, $mediumtext['headers']['status-code']); + + $longtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'longtext', + 'required' => false, + ]); + $this->assertEquals(202, $longtext['headers']['status-code']); + \sleep(3); // Create sample documents @@ -1265,7 +1294,10 @@ trait MigrationsBase 'documentId' => ID::unique(), 'data' => [ 'name' => 'Test User ' . $i, - 'email' => 'user' . $i . '@appwrite.io' + 'email' => 'user' . $i . '@appwrite.io', + 'regulartext' => 'regularText', + 'mediumtext' => 'mediumText', + 'longtext' => 'longText', ] ]); @@ -1344,11 +1376,16 @@ trait MigrationsBase // Verify the downloaded content is valid CSV $csvData = $downloadWithJwt['body']; + var_dump($csvData); $this->assertNotEmpty($csvData, 'CSV export should not be empty'); $this->assertStringContainsString('name', $csvData, 'CSV should contain the name column header'); $this->assertStringContainsString('email', $csvData, 'CSV should contain the email column header'); $this->assertStringContainsString('Test User 1', $csvData, 'CSV should contain test data'); + $this->assertStringContainsString('regularText', $csvData, 'CSV should contain the text column header'); + $this->assertStringContainsString('mediumText', $csvData, 'CSV should contain the medium column header'); + $this->assertStringContainsString('longText', $csvData, 'CSV should contain the long text column header'); + // Cleanup $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [ 'x-appwrite-project' => $this->getProject()['$id'], From d754b8a56195382a4044363389875998e114f2f0 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 13:44:13 +0200 Subject: [PATCH 11/40] lock --- composer.json | 2 +- composer.lock | 65 ++++++++++++++++++++++----------------------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/composer.json b/composer.json index 2ff5e46cf3..15346eb169 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", - "utopia-php/migration": "dev-text-attributes as 1.5.2", + "utopia-php/migration": "1.5.*", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", "utopia-php/span": "1.1.*", diff --git a/composer.lock b/composer.lock index 4cad22d4c1..f522fc29ca 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": "dff51ff51a89f58125ee9a59c860a92a", + "content-hash": "9397ae16877660a3ea485cfdcaab906c", "packages": [ { "name": "adhocore/jwt", @@ -3797,16 +3797,16 @@ }, { "name": "utopia-php/database", - "version": "5.2.0", + "version": "5.1.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7" + "reference": "94815bfa605282096272625827d0314f9ed99066" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/5c89b39de00f2b3126d0fbbdea36786341293df7", - "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7", + "url": "https://api.github.com/repos/utopia-php/database/zipball/94815bfa605282096272625827d0314f9ed99066", + "reference": "94815bfa605282096272625827d0314f9ed99066", "shasum": "" }, "require": { @@ -3849,9 +3849,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/5.2.0" + "source": "https://github.com/utopia-php/database/tree/5.1.1" }, - "time": "2026-02-14T09:37:28+00:00" + "time": "2026-02-12T11:44:58+00:00" }, { "name": "utopia-php/detector", @@ -4464,16 +4464,16 @@ }, { "name": "utopia-php/migration", - "version": "dev-text-attributes", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "481539d4fcf998f8d5f1ed3871c42318058c4b40" + "reference": "93904948f6dd07491821615fd9b9acbcaadec12e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/481539d4fcf998f8d5f1ed3871c42318058c4b40", - "reference": "481539d4fcf998f8d5f1ed3871c42318058c4b40", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/93904948f6dd07491821615fd9b9acbcaadec12e", + "reference": "93904948f6dd07491821615fd9b9acbcaadec12e", "shasum": "" }, "require": { @@ -4513,9 +4513,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/text-attributes" + "source": "https://github.com/utopia-php/migration/tree/1.5.2" }, - "time": "2026-02-15T11:19:13+00:00" + "time": "2026-02-11T06:19:35+00:00" }, { "name": "utopia-php/mongo", @@ -4909,16 +4909,16 @@ }, { "name": "utopia-php/span", - "version": "1.1.5", + "version": "1.1.4", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5" + "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/028406940ca92bdc88099f0b1a123a3b2cbdd4e5", - "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5", + "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", "shasum": "" }, "require": { @@ -4947,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.1.5" + "source": "https://github.com/utopia-php/span/tree/1.1.4" }, - "time": "2026-02-13T18:00:11+00:00" + "time": "2026-02-13T10:58:12+00:00" }, { "name": "utopia-php/storage", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.1", + "version": "1.9.0", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "02587e667091df7fb9a0f79fb080b28cada92706" + "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/02587e667091df7fb9a0f79fb080b28cada92706", - "reference": "02587e667091df7fb9a0f79fb080b28cada92706", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", + "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.1" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.0" }, - "time": "2026-02-13T16:33:55+00:00" + "time": "2026-02-12T12:08:13+00:00" }, { "name": "doctrine/annotations", @@ -8888,18 +8888,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/migration", - "version": "dev-text-attributes", - "alias": "1.5.2", - "alias_normalized": "1.5.2.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/migration": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8923,5 +8914,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } From 38a816bb58b22603d9959902563d6e0c848ddfc2 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 13:47:15 +0200 Subject: [PATCH 12/40] Remove var_dump --- tests/e2e/Services/Migrations/MigrationsBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 2bcfd11059..4dd5d4b00b 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1376,7 +1376,7 @@ trait MigrationsBase // Verify the downloaded content is valid CSV $csvData = $downloadWithJwt['body']; - var_dump($csvData); + $this->assertNotEmpty($csvData, 'CSV export should not be empty'); $this->assertStringContainsString('name', $csvData, 'CSV should contain the name column header'); $this->assertStringContainsString('email', $csvData, 'CSV should contain the email column header'); From 3a1f4f439aa047d86dbd78945ec54871f6b8e30d Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 13:48:50 +0200 Subject: [PATCH 13/40] lines --- tests/e2e/Services/Migrations/MigrationsBase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 4dd5d4b00b..f067b2a8f4 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1250,6 +1250,7 @@ trait MigrationsBase 'size' => 255, 'required' => false, ]); + $this->assertEquals(202, $email['headers']['status-code']); $text = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/text', [ @@ -1260,6 +1261,7 @@ trait MigrationsBase 'key' => 'regulartext', 'required' => false, ]); + $this->assertEquals(202, $text['headers']['status-code']); $mediumtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ @@ -1270,6 +1272,7 @@ trait MigrationsBase 'key' => 'mediumtext', 'required' => false, ]); + $this->assertEquals(202, $mediumtext['headers']['status-code']); $longtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ @@ -1280,6 +1283,7 @@ trait MigrationsBase 'key' => 'longtext', 'required' => false, ]); + $this->assertEquals(202, $longtext['headers']['status-code']); \sleep(3); From 52c4eb419aec156b929ab26af3140ef7f0249060 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 13:49:45 +0200 Subject: [PATCH 14/40] typo longtext --- tests/e2e/Services/Migrations/MigrationsBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index f067b2a8f4..876062fe72 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1275,7 +1275,7 @@ trait MigrationsBase $this->assertEquals(202, $mediumtext['headers']['status-code']); - $longtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ + $longtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/longtext', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] From 4b705d5505e0a5c95357661f69b63b96441ffa82 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 15:21:05 +0200 Subject: [PATCH 15/40] lock --- composer.json | 2 +- composer.lock | 65 +++++++++++++++++++++++++++++---------------------- 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/composer.json b/composer.json index 15346eb169..2ff5e46cf3 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", - "utopia-php/migration": "1.5.*", + "utopia-php/migration": "dev-text-attributes as 1.5.2", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", "utopia-php/span": "1.1.*", diff --git a/composer.lock b/composer.lock index f522fc29ca..894aa4ccee 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": "9397ae16877660a3ea485cfdcaab906c", + "content-hash": "dff51ff51a89f58125ee9a59c860a92a", "packages": [ { "name": "adhocore/jwt", @@ -3797,16 +3797,16 @@ }, { "name": "utopia-php/database", - "version": "5.1.1", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "94815bfa605282096272625827d0314f9ed99066" + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/94815bfa605282096272625827d0314f9ed99066", - "reference": "94815bfa605282096272625827d0314f9ed99066", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5c89b39de00f2b3126d0fbbdea36786341293df7", + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7", "shasum": "" }, "require": { @@ -3849,9 +3849,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/5.1.1" + "source": "https://github.com/utopia-php/database/tree/5.2.0" }, - "time": "2026-02-12T11:44:58+00:00" + "time": "2026-02-14T09:37:28+00:00" }, { "name": "utopia-php/detector", @@ -4464,16 +4464,16 @@ }, { "name": "utopia-php/migration", - "version": "1.5.2", + "version": "dev-text-attributes", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "93904948f6dd07491821615fd9b9acbcaadec12e" + "reference": "bf3074ef3bb39916b077d75b9b9f28630f05f98d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/93904948f6dd07491821615fd9b9acbcaadec12e", - "reference": "93904948f6dd07491821615fd9b9acbcaadec12e", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/bf3074ef3bb39916b077d75b9b9f28630f05f98d", + "reference": "bf3074ef3bb39916b077d75b9b9f28630f05f98d", "shasum": "" }, "require": { @@ -4513,9 +4513,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/1.5.2" + "source": "https://github.com/utopia-php/migration/tree/text-attributes" }, - "time": "2026-02-11T06:19:35+00:00" + "time": "2026-02-15T11:51:21+00:00" }, { "name": "utopia-php/mongo", @@ -4909,16 +4909,16 @@ }, { "name": "utopia-php/span", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "url": "https://api.github.com/repos/utopia-php/span/zipball/028406940ca92bdc88099f0b1a123a3b2cbdd4e5", + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5", "shasum": "" }, "require": { @@ -4947,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.1.4" + "source": "https://github.com/utopia-php/span/tree/1.1.5" }, - "time": "2026-02-13T10:58:12+00:00" + "time": "2026-02-13T18:00:11+00:00" }, { "name": "utopia-php/storage", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.0", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0" + "reference": "02587e667091df7fb9a0f79fb080b28cada92706" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/02587e667091df7fb9a0f79fb080b28cada92706", + "reference": "02587e667091df7fb9a0f79fb080b28cada92706", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.1" }, - "time": "2026-02-12T12:08:13+00:00" + "time": "2026-02-13T16:33:55+00:00" }, { "name": "doctrine/annotations", @@ -8888,9 +8888,18 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/migration", + "version": "dev-text-attributes", + "alias": "1.5.2", + "alias_normalized": "1.5.2.0" + } + ], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "utopia-php/migration": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8914,5 +8923,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } From a67aaa6a53b88d05ee65c447cb3889bf85dd438f Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 15 Feb 2026 16:27:26 +0200 Subject: [PATCH 16/40] Update --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 894aa4ccee..dff5fff933 100644 --- a/composer.lock +++ b/composer.lock @@ -4468,12 +4468,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "bf3074ef3bb39916b077d75b9b9f28630f05f98d" + "reference": "6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/bf3074ef3bb39916b077d75b9b9f28630f05f98d", - "reference": "bf3074ef3bb39916b077d75b9b9f28630f05f98d", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573", + "reference": "6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573", "shasum": "" }, "require": { @@ -4515,7 +4515,7 @@ "issues": "https://github.com/utopia-php/migration/issues", "source": "https://github.com/utopia-php/migration/tree/text-attributes" }, - "time": "2026-02-15T11:51:21+00:00" + "time": "2026-02-15T14:25:53+00:00" }, { "name": "utopia-php/mongo", From 9d83d39b16d4cf55b1929342624d5dd77fa37466 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 16 Feb 2026 13:11:33 +0530 Subject: [PATCH 17/40] chore: fix readme in agent skills sdk --- composer.lock | 38 +++++++++++------------ docs/sdks/agent-skills/GETTING_STARTED.md | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/composer.lock b/composer.lock index f522fc29ca..1b7b675045 100644 --- a/composer.lock +++ b/composer.lock @@ -3797,16 +3797,16 @@ }, { "name": "utopia-php/database", - "version": "5.1.1", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "94815bfa605282096272625827d0314f9ed99066" + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/94815bfa605282096272625827d0314f9ed99066", - "reference": "94815bfa605282096272625827d0314f9ed99066", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5c89b39de00f2b3126d0fbbdea36786341293df7", + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7", "shasum": "" }, "require": { @@ -3849,9 +3849,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/5.1.1" + "source": "https://github.com/utopia-php/database/tree/5.2.0" }, - "time": "2026-02-12T11:44:58+00:00" + "time": "2026-02-14T09:37:28+00:00" }, { "name": "utopia-php/detector", @@ -4909,16 +4909,16 @@ }, { "name": "utopia-php/span", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "url": "https://api.github.com/repos/utopia-php/span/zipball/028406940ca92bdc88099f0b1a123a3b2cbdd4e5", + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5", "shasum": "" }, "require": { @@ -4947,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.1.4" + "source": "https://github.com/utopia-php/span/tree/1.1.5" }, - "time": "2026-02-13T10:58:12+00:00" + "time": "2026-02-13T18:00:11+00:00" }, { "name": "utopia-php/storage", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.0", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0" + "reference": "74de906ea5051030c5299a5d4aa74d963a531130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/74de906ea5051030c5299a5d4aa74d963a531130", + "reference": "74de906ea5051030c5299a5d4aa74d963a531130", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.2" }, - "time": "2026-02-12T12:08:13+00:00" + "time": "2026-02-16T06:59:54+00:00" }, { "name": "doctrine/annotations", @@ -8914,5 +8914,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/docs/sdks/agent-skills/GETTING_STARTED.md b/docs/sdks/agent-skills/GETTING_STARTED.md index 4dcfd9447e..4bbeccc015 100644 --- a/docs/sdks/agent-skills/GETTING_STARTED.md +++ b/docs/sdks/agent-skills/GETTING_STARTED.md @@ -9,7 +9,7 @@ These skills follow the Agent Skills Open Standard: https://agentskills.io/home Install directly with the Skills CLI: ```bash -npx skills add chiragagg5k/appwrite-agent-skills +npx skills add appwrite/agent-skills ``` This installs the packaged `appwrite-*` skills into your local skills directory. From 05fd8197b9394016b2c8c4cb1139a0716197ef2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 08:27:35 +0000 Subject: [PATCH 18/40] Initial plan From b58ebdbd15566d598e9d67ffb642f858fd6a88a9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 08:38:00 +0000 Subject: [PATCH 19/40] Add encrypt param to varchar, text, mediumtext, longtext attribute and column create routes - Add encrypt parameter to Varchar, Text, Mediumtext, Longtext attribute create routes - Add encrypt parameter to Varchar, Text, Mediumtext, Longtext column create routes - Add encrypt rule to AttributeVarchar, AttributeText, AttributeMediumtext, AttributeLongtext response models - Add encrypt rule to ColumnVarchar, ColumnText, ColumnMediumtext, ColumnLongtext response models - Add plan injection and validation for encrypt feature in all routes - Add size validation for encrypt on varchar route (variable size) - Add encrypt filter handling in all routes Co-authored-by: abnegate <5857008+abnegate@users.noreply.github.com> --- .../Attributes/Longtext/Create.php | 18 ++++++++++++++ .../Attributes/Mediumtext/Create.php | 18 ++++++++++++++ .../Collections/Attributes/Text/Create.php | 18 ++++++++++++++ .../Collections/Attributes/Varchar/Create.php | 24 +++++++++++++++++++ .../Tables/Columns/Longtext/Create.php | 2 ++ .../Tables/Columns/Mediumtext/Create.php | 2 ++ .../TablesDB/Tables/Columns/Text/Create.php | 2 ++ .../Tables/Columns/Varchar/Create.php | 2 ++ .../Response/Model/AttributeLongtext.php | 7 ++++++ .../Response/Model/AttributeMediumtext.php | 7 ++++++ .../Utopia/Response/Model/AttributeText.php | 7 ++++++ .../Response/Model/AttributeVarchar.php | 7 ++++++ .../Utopia/Response/Model/ColumnLongtext.php | 7 ++++++ .../Response/Model/ColumnMediumtext.php | 7 ++++++ .../Utopia/Response/Model/ColumnText.php | 7 ++++++ .../Utopia/Response/Model/ColumnVarchar.php | 7 ++++++ 16 files changed, 142 insertions(+) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php index 7ec249de28..1fe0c58fc0 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php @@ -4,6 +4,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attribu use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; +use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attributes\Action; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; @@ -15,6 +16,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Response as SwooleResponse; +use Utopia\Http\Http; use Utopia\Validator\Boolean; use Utopia\Validator\Nullable; use Utopia\Validator\Text; @@ -62,10 +64,12 @@ class Create extends Action ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } @@ -77,12 +81,23 @@ class Create extends Action ?bool $required, ?string $default, bool $array, + bool $encrypt, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, + array $plan, Authorization $authorization ): void { + if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + } + + $filters = []; + if ($encrypt) { + $filters[] = 'encrypt'; + } + $attribute = $this->createAttribute( $databaseId, $collectionId, @@ -93,6 +108,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, + 'filters' => $filters, ]), $response, $dbForProject, @@ -101,6 +117,8 @@ class Create extends Action $authorization ); + $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) ->dynamic($attribute, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php index 918379d2a0..1a9227a1cb 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php @@ -4,6 +4,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attribu use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; +use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attributes\Action; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; @@ -15,6 +16,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Response as SwooleResponse; +use Utopia\Http\Http; use Utopia\Validator\Boolean; use Utopia\Validator\Nullable; use Utopia\Validator\Text; @@ -62,10 +64,12 @@ class Create extends Action ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } @@ -77,12 +81,23 @@ class Create extends Action ?bool $required, ?string $default, bool $array, + bool $encrypt, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, + array $plan, Authorization $authorization ): void { + if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + } + + $filters = []; + if ($encrypt) { + $filters[] = 'encrypt'; + } + $attribute = $this->createAttribute( $databaseId, $collectionId, @@ -93,6 +108,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, + 'filters' => $filters, ]), $response, $dbForProject, @@ -101,6 +117,8 @@ class Create extends Action $authorization ); + $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) ->dynamic($attribute, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php index bc9b853d0f..8d6df34aa1 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php @@ -4,6 +4,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attribu use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; +use Appwrite\Extend\Exception; use Appwrite\Platform\Modules\Databases\Http\Databases\Collections\Attributes\Action; use Appwrite\SDK\AuthType; use Appwrite\SDK\Method; @@ -15,6 +16,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Response as SwooleResponse; +use Utopia\Http\Http; use Utopia\Validator\Boolean; use Utopia\Validator\Nullable; use Utopia\Validator\Text; @@ -62,10 +64,12 @@ class Create extends Action ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } @@ -77,12 +81,23 @@ class Create extends Action ?bool $required, ?string $default, bool $array, + bool $encrypt, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, + array $plan, Authorization $authorization ): void { + if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + } + + $filters = []; + if ($encrypt) { + $filters[] = 'encrypt'; + } + $attribute = $this->createAttribute( $databaseId, $collectionId, @@ -93,6 +108,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, + 'filters' => $filters, ]), $response, $dbForProject, @@ -101,6 +117,8 @@ class Create extends Action $authorization ); + $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) ->dynamic($attribute, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php index c35ad518ab..9ed5a3c755 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php @@ -16,6 +16,7 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Http\Adapter\Swoole\Response as SwooleResponse; +use Utopia\Http\Http; use Utopia\Validator; use Utopia\Validator\Boolean; use Utopia\Validator\Nullable; @@ -66,10 +67,12 @@ class Create extends Action ->param('required', null, new Boolean(), 'Is attribute required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for attribute when not provided. Cannot be set when attribute is required.', true) ->param('array', false, new Boolean(), 'Is attribute an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } @@ -82,18 +85,36 @@ class Create extends Action ?bool $required, ?string $default, bool $array, + bool $encrypt, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, + array $plan, Authorization $authorization ): void { + if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + } + + if ($encrypt && $size < APP_DATABASE_ENCRYPT_SIZE_MIN) { + throw new Exception( + Exception::GENERAL_BAD_REQUEST, + "Size too small. Encrypted strings require a minimum size of " . APP_DATABASE_ENCRYPT_SIZE_MIN . " characters." + ); + } + // Ensure default fits in the given size $validator = new Text($size, 0); if (!is_null($default) && !$validator->isValid($default)) { throw new Exception($this->getInvalidValueException(), $validator->getDescription()); } + $filters = []; + if ($encrypt) { + $filters[] = 'encrypt'; + } + $attribute = $this->createAttribute( $databaseId, $collectionId, @@ -104,6 +125,7 @@ class Create extends Action 'required' => $required, 'default' => $default, 'array' => $array, + 'filters' => $filters, ]), $response, $dbForProject, @@ -112,6 +134,8 @@ class Create extends Action $authorization ); + $attribute->setAttribute('encrypt', $encrypt); + $response ->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED) ->dynamic($attribute, $this->getResponseModel()); diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Longtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Longtext/Create.php index fa06fb3ab3..da9471f37c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Longtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Longtext/Create.php @@ -57,10 +57,12 @@ class Create extends LongtextCreate ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for column when not provided. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Mediumtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Mediumtext/Create.php index 6b5eba648e..585856cab9 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Mediumtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Mediumtext/Create.php @@ -57,10 +57,12 @@ class Create extends MediumtextCreate ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for column when not provided. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Text/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Text/Create.php index 4024537c2d..2c68431d8c 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Text/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Text/Create.php @@ -57,10 +57,12 @@ class Create extends TextCreate ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for column when not provided. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Varchar/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Varchar/Create.php index fada172d2a..0ee04f5f63 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Varchar/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Varchar/Create.php @@ -60,10 +60,12 @@ class Create extends VarcharCreate ->param('required', null, new Boolean(), 'Is column required?') ->param('default', null, new Nullable(new Text(0, 0)), 'Default value for column when not provided. Cannot be set when column is required.', true) ->param('array', false, new Boolean(), 'Is column an array?', true) + ->param('encrypt', false, new Boolean(), 'Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') + ->inject('plan') ->inject('authorization') ->callback($this->action(...)); } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeLongtext.php b/src/Appwrite/Utopia/Response/Model/AttributeLongtext.php index 02e2f637e4..f0ab1b267c 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeLongtext.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeLongtext.php @@ -18,6 +18,13 @@ class AttributeLongtext extends Attribute 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this attribute is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeMediumtext.php b/src/Appwrite/Utopia/Response/Model/AttributeMediumtext.php index de9316ff03..4f8b9a8392 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeMediumtext.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeMediumtext.php @@ -18,6 +18,13 @@ class AttributeMediumtext extends Attribute 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this attribute is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeText.php b/src/Appwrite/Utopia/Response/Model/AttributeText.php index 64a8c8316b..4424db88b6 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeText.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeText.php @@ -18,6 +18,13 @@ class AttributeText extends Attribute 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this attribute is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/AttributeVarchar.php b/src/Appwrite/Utopia/Response/Model/AttributeVarchar.php index 21741b7ca3..aa464a013e 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeVarchar.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeVarchar.php @@ -24,6 +24,13 @@ class AttributeVarchar extends Attribute 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this attribute is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/ColumnLongtext.php b/src/Appwrite/Utopia/Response/Model/ColumnLongtext.php index 86361596fe..9ce4599eee 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnLongtext.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnLongtext.php @@ -18,6 +18,13 @@ class ColumnLongtext extends Column 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this column is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/ColumnMediumtext.php b/src/Appwrite/Utopia/Response/Model/ColumnMediumtext.php index c060dcbc60..a97c642fe9 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnMediumtext.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnMediumtext.php @@ -18,6 +18,13 @@ class ColumnMediumtext extends Column 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this column is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/ColumnText.php b/src/Appwrite/Utopia/Response/Model/ColumnText.php index acd997d18c..e0db0c47cc 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnText.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnText.php @@ -18,6 +18,13 @@ class ColumnText extends Column 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this column is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } diff --git a/src/Appwrite/Utopia/Response/Model/ColumnVarchar.php b/src/Appwrite/Utopia/Response/Model/ColumnVarchar.php index eba0fbd973..5c57e8be13 100644 --- a/src/Appwrite/Utopia/Response/Model/ColumnVarchar.php +++ b/src/Appwrite/Utopia/Response/Model/ColumnVarchar.php @@ -24,6 +24,13 @@ class ColumnVarchar extends Column 'required' => false, 'example' => 'default', ]) + ->addRule('encrypt', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Defines whether this column is encrypted or not.', + 'default' => false, + 'required' => false, + 'example' => false, + ]) ; } From ef826ca122ffb8e44de3278346154c27a0661718 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 08:38:53 +0000 Subject: [PATCH 20/40] Fix error messages to not use 'string' in non-string type routes Co-authored-by: abnegate <5857008+abnegate@users.noreply.github.com> --- .../Http/Databases/Collections/Attributes/Longtext/Create.php | 2 +- .../Http/Databases/Collections/Attributes/Mediumtext/Create.php | 2 +- .../Http/Databases/Collections/Attributes/Text/Create.php | 2 +- .../Http/Databases/Collections/Attributes/Varchar/Create.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php index 1fe0c58fc0..2fc9de8699 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Longtext/Create.php @@ -90,7 +90,7 @@ class Create extends Action Authorization $authorization ): void { if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted ' . $this->getSDKGroup() . '.'); } $filters = []; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php index 1a9227a1cb..5776e51917 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Mediumtext/Create.php @@ -90,7 +90,7 @@ class Create extends Action Authorization $authorization ): void { if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted ' . $this->getSDKGroup() . '.'); } $filters = []; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php index 8d6df34aa1..eb6b2f9691 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Text/Create.php @@ -90,7 +90,7 @@ class Create extends Action Authorization $authorization ): void { if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted ' . $this->getSDKGroup() . '.'); } $filters = []; diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php index 9ed5a3c755..24a36725c8 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Varchar/Create.php @@ -94,7 +94,7 @@ class Create extends Action Authorization $authorization ): void { if (!Http::isDevelopment() && $encrypt && !empty($plan) && !($plan['databasesAllowEncrypt'] ?? false)) { - throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted string ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted string ' . $this->getSDKGroup() . '.'); + throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Encrypted ' . $this->getSDKGroup() . ' are not available on your plan. Please upgrade to create encrypted ' . $this->getSDKGroup() . '.'); } if ($encrypt && $size < APP_DATABASE_ENCRYPT_SIZE_MIN) { From b2f48547b9fcb6273395b7b1c9d72c0724014b3d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:38:25 +0000 Subject: [PATCH 21/40] Add encrypt parameter tests for varchar, text, mediumtext, longtext attribute and column types Co-authored-by: abnegate <5857008+abnegate@users.noreply.github.com> --- .../Legacy/DatabasesStringTypesTest.php | 75 +++++++++++++++++++ .../TablesDB/DatabasesStringTypesTest.php | 75 +++++++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php b/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php index 3a9c7927db..8b7886b864 100644 --- a/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php +++ b/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php @@ -88,6 +88,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(255, $varchar['body']['size']); $this->assertEquals(false, $varchar['body']['required']); $this->assertNull($varchar['body']['default']); + $this->assertFalse($varchar['body']['encrypt']); // Test SUCCESS: Create varchar with default value $varcharWithDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/varchar', [ @@ -147,6 +148,21 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $varcharMin['headers']['status-code']); $this->assertEquals(1, $varcharMin['body']['size']); + // Test SUCCESS: Create encrypted varchar attribute + $varcharEncrypted = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/varchar', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'varchar_encrypted', + 'size' => 256, + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $varcharEncrypted['headers']['status-code']); + $this->assertTrue($varcharEncrypted['body']['encrypt']); + return $data; } @@ -235,6 +251,20 @@ class DatabasesStringTypesTest extends Scope ]); $this->assertEquals(409, $varcharDuplicate['headers']['status-code']); + + // Test FAILURE: Encrypted varchar with size too small + $varcharEncryptTooSmall = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/varchar', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'varchar_encrypt_small', + 'size' => 149, + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(400, $varcharEncryptTooSmall['headers']['status-code']); } /** @@ -259,6 +289,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('text_field', $text['body']['key']); $this->assertEquals('text', $text['body']['type']); $this->assertEquals(false, $text['body']['required']); + $this->assertFalse($text['body']['encrypt']); // Test SUCCESS: Create text with default value $textWithDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/text', [ @@ -301,6 +332,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $textArray['headers']['status-code']); $this->assertEquals(true, $textArray['body']['array']); + // Test SUCCESS: Create encrypted text attribute + $textEncrypted = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/text', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'text_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $textEncrypted['headers']['status-code']); + $this->assertTrue($textEncrypted['body']['encrypt']); + return $data; } @@ -326,6 +371,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('mediumtext_field', $mediumtext['body']['key']); $this->assertEquals('mediumtext', $mediumtext['body']['type']); $this->assertEquals(false, $mediumtext['body']['required']); + $this->assertFalse($mediumtext['body']['encrypt']); // Test SUCCESS: Create mediumtext with default $mediumtextWithDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ @@ -367,6 +413,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $mediumtextArray['headers']['status-code']); $this->assertEquals(true, $mediumtextArray['body']['array']); + // Test SUCCESS: Create encrypted mediumtext attribute + $mediumtextEncrypted = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'mediumtext_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $mediumtextEncrypted['headers']['status-code']); + $this->assertTrue($mediumtextEncrypted['body']['encrypt']); + return $data; } @@ -392,6 +452,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('longtext_field', $longtext['body']['key']); $this->assertEquals('longtext', $longtext['body']['type']); $this->assertEquals(false, $longtext['body']['required']); + $this->assertFalse($longtext['body']['encrypt']); // Test SUCCESS: Create longtext with default $longtextWithDefault = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/longtext', [ @@ -433,6 +494,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $longtextArray['headers']['status-code']); $this->assertEquals(true, $longtextArray['body']['array']); + // Test SUCCESS: Create encrypted longtext attribute + $longtextEncrypted = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/longtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'longtext_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $longtextEncrypted['headers']['status-code']); + $this->assertTrue($longtextEncrypted['body']['encrypt']); + return $data; } diff --git a/tests/e2e/Services/Databases/TablesDB/DatabasesStringTypesTest.php b/tests/e2e/Services/Databases/TablesDB/DatabasesStringTypesTest.php index d38e03ec89..e87e57bf16 100644 --- a/tests/e2e/Services/Databases/TablesDB/DatabasesStringTypesTest.php +++ b/tests/e2e/Services/Databases/TablesDB/DatabasesStringTypesTest.php @@ -88,6 +88,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(255, $varchar['body']['size']); $this->assertEquals(false, $varchar['body']['required']); $this->assertNull($varchar['body']['default']); + $this->assertFalse($varchar['body']['encrypt']); // Test SUCCESS: Create varchar with default value $varcharWithDefault = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/varchar', [ @@ -147,6 +148,21 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $varcharMin['headers']['status-code']); $this->assertEquals(1, $varcharMin['body']['size']); + // Test SUCCESS: Create encrypted varchar column + $varcharEncrypted = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/varchar', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'varchar_encrypted', + 'size' => 256, + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $varcharEncrypted['headers']['status-code']); + $this->assertTrue($varcharEncrypted['body']['encrypt']); + return $data; } @@ -235,6 +251,20 @@ class DatabasesStringTypesTest extends Scope ]); $this->assertEquals(409, $varcharDuplicate['headers']['status-code']); + + // Test FAILURE: Encrypted varchar with size too small + $varcharEncryptTooSmall = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/varchar', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'varchar_encrypt_small', + 'size' => 149, + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(400, $varcharEncryptTooSmall['headers']['status-code']); } /** @@ -259,6 +289,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('text_field', $text['body']['key']); $this->assertEquals('text', $text['body']['type']); $this->assertEquals(false, $text['body']['required']); + $this->assertFalse($text['body']['encrypt']); // Test SUCCESS: Create text with default value $textWithDefault = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/text', [ @@ -301,6 +332,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $textArray['headers']['status-code']); $this->assertEquals(true, $textArray['body']['array']); + // Test SUCCESS: Create encrypted text column + $textEncrypted = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/text', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'text_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $textEncrypted['headers']['status-code']); + $this->assertTrue($textEncrypted['body']['encrypt']); + return $data; } @@ -326,6 +371,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('mediumtext_field', $mediumtext['body']['key']); $this->assertEquals('mediumtext', $mediumtext['body']['type']); $this->assertEquals(false, $mediumtext['body']['required']); + $this->assertFalse($mediumtext['body']['encrypt']); // Test SUCCESS: Create mediumtext with default $mediumtextWithDefault = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/mediumtext', [ @@ -367,6 +413,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $mediumtextArray['headers']['status-code']); $this->assertEquals(true, $mediumtextArray['body']['array']); + // Test SUCCESS: Create encrypted mediumtext column + $mediumtextEncrypted = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/mediumtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'mediumtext_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $mediumtextEncrypted['headers']['status-code']); + $this->assertTrue($mediumtextEncrypted['body']['encrypt']); + return $data; } @@ -392,6 +452,7 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals('longtext_field', $longtext['body']['key']); $this->assertEquals('longtext', $longtext['body']['type']); $this->assertEquals(false, $longtext['body']['required']); + $this->assertFalse($longtext['body']['encrypt']); // Test SUCCESS: Create longtext with default $longtextWithDefault = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/longtext', [ @@ -433,6 +494,20 @@ class DatabasesStringTypesTest extends Scope $this->assertEquals(202, $longtextArray['headers']['status-code']); $this->assertEquals(true, $longtextArray['body']['array']); + // Test SUCCESS: Create encrypted longtext column + $longtextEncrypted = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/longtext', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'longtext_encrypted', + 'required' => false, + 'encrypt' => true, + ]); + + $this->assertEquals(202, $longtextEncrypted['headers']['status-code']); + $this->assertTrue($longtextEncrypted['body']['encrypt']); + return $data; } From cd3dc0c4e472276ddc69dbc5d6477f4cc5b29df5 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 16 Feb 2026 12:03:10 +0200 Subject: [PATCH 22/40] Update migrations --- composer.json | 2 +- composer.lock | 39 +++++++++++++++------------------------ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index 2ff5e46cf3..b7d3bc5483 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "utopia-php/locale": "0.8.*", "utopia-php/logger": "0.6.*", "utopia-php/messaging": "0.20.*", - "utopia-php/migration": "dev-text-attributes as 1.5.2", + "utopia-php/migration": "1.6.*", "utopia-php/platform": "0.7.*", "utopia-php/pools": "1.*", "utopia-php/span": "1.1.*", diff --git a/composer.lock b/composer.lock index dff5fff933..ddc2754e98 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": "dff51ff51a89f58125ee9a59c860a92a", + "content-hash": "fe847eccf6ba73bfca1e08d26e9fc7ab", "packages": [ { "name": "adhocore/jwt", @@ -4464,16 +4464,16 @@ }, { "name": "utopia-php/migration", - "version": "dev-text-attributes", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573" + "reference": "aa07cf9ae8cc4b8df0ab64588e033693b5ad6849" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573", - "reference": "6d92c14ffe289fdb7a5f7a0e1729bc2ed75a8573", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/aa07cf9ae8cc4b8df0ab64588e033693b5ad6849", + "reference": "aa07cf9ae8cc4b8df0ab64588e033693b5ad6849", "shasum": "" }, "require": { @@ -4513,9 +4513,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/text-attributes" + "source": "https://github.com/utopia-php/migration/tree/1.6.0" }, - "time": "2026-02-15T14:25:53+00:00" + "time": "2026-02-16T07:19:27+00:00" }, { "name": "utopia-php/mongo", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.1", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "02587e667091df7fb9a0f79fb080b28cada92706" + "reference": "74de906ea5051030c5299a5d4aa74d963a531130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/02587e667091df7fb9a0f79fb080b28cada92706", - "reference": "02587e667091df7fb9a0f79fb080b28cada92706", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/74de906ea5051030c5299a5d4aa74d963a531130", + "reference": "74de906ea5051030c5299a5d4aa74d963a531130", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.1" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.2" }, - "time": "2026-02-13T16:33:55+00:00" + "time": "2026-02-16T06:59:54+00:00" }, { "name": "doctrine/annotations", @@ -8888,18 +8888,9 @@ "time": "2024-03-07T20:33:40+00:00" } ], - "aliases": [ - { - "package": "utopia-php/migration", - "version": "dev-text-attributes", - "alias": "1.5.2", - "alias_normalized": "1.5.2.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/migration": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 2ce1717d39d4ec6d57e6065b36fc8ef8dbcada85 Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 16 Feb 2026 12:18:19 +0200 Subject: [PATCH 23/40] varchar migration test --- tests/e2e/Services/Migrations/MigrationsBase.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 876062fe72..1d0d030014 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1264,6 +1264,18 @@ trait MigrationsBase $this->assertEquals(202, $text['headers']['status-code']); + $varchar = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/varchar', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'varchar', + 'required' => false, + ]); + + $this->assertEquals(202, $varchar['headers']['status-code']); + + $mediumtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1302,6 +1314,7 @@ trait MigrationsBase 'regulartext' => 'regularText', 'mediumtext' => 'mediumText', 'longtext' => 'longText', + 'varchar' => 'varchar', ] ]); @@ -1389,6 +1402,7 @@ trait MigrationsBase $this->assertStringContainsString('regularText', $csvData, 'CSV should contain the text column header'); $this->assertStringContainsString('mediumText', $csvData, 'CSV should contain the medium column header'); $this->assertStringContainsString('longText', $csvData, 'CSV should contain the long text column header'); + $this->assertStringContainsString('varchar', $csvData, 'CSV should contain the varchar column header'); // Cleanup $this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [ From 3796f55e0d8026dae6c8151f813e4f87ac4d7ecc Mon Sep 17 00:00:00 2001 From: fogelito Date: Mon, 16 Feb 2026 12:23:49 +0200 Subject: [PATCH 24/40] varchar size --- tests/e2e/Services/Migrations/MigrationsBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/Services/Migrations/MigrationsBase.php b/tests/e2e/Services/Migrations/MigrationsBase.php index 1d0d030014..a919974b29 100644 --- a/tests/e2e/Services/Migrations/MigrationsBase.php +++ b/tests/e2e/Services/Migrations/MigrationsBase.php @@ -1270,12 +1270,12 @@ trait MigrationsBase 'x-appwrite-key' => $this->getProject()['apiKey'] ], [ 'key' => 'varchar', + 'size' => 1000, 'required' => false, ]); $this->assertEquals(202, $varchar['headers']['status-code']); - $mediumtext = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/mediumtext', [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], From 9dc11c17159c43f3d1808ad06bada695b0200854 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Mon, 16 Feb 2026 23:53:55 +1300 Subject: [PATCH 25/40] Update specs --- app/config/specs/open-api3-1.8.x-console.json | 112 ++++++++++++++-- app/config/specs/open-api3-1.8.x-server.json | 112 ++++++++++++++-- .../specs/open-api3-latest-console.json | 112 ++++++++++++++-- app/config/specs/open-api3-latest-server.json | 112 ++++++++++++++-- app/config/specs/swagger2-1.8.x-console.json | 120 ++++++++++++++++-- app/config/specs/swagger2-1.8.x-server.json | 120 ++++++++++++++++-- app/config/specs/swagger2-latest-console.json | 120 ++++++++++++++++-- app/config/specs/swagger2-latest-server.json | 120 ++++++++++++++++-- composer.lock | 36 +++--- 9 files changed, 882 insertions(+), 82 deletions(-) diff --git a/app/config/specs/open-api3-1.8.x-console.json b/app/config/specs/open-api3-1.8.x-console.json index 91975d2d2e..b57aea9ddc 100644 --- a/app/config/specs/open-api3-1.8.x-console.json +++ b/app/config/specs/open-api3-1.8.x-console.json @@ -9721,6 +9721,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -9944,6 +9949,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11034,6 +11044,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11496,6 +11511,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -40701,6 +40721,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -40930,6 +40955,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42027,6 +42057,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42493,6 +42528,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -54361,6 +54401,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54383,7 +54429,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -54444,6 +54491,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54464,7 +54517,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -54525,6 +54579,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54545,7 +54605,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -54606,6 +54667,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54626,7 +54693,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -56182,6 +56250,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56204,7 +56278,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -56265,6 +56340,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56285,7 +56366,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -56346,6 +56428,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56366,7 +56454,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -56427,6 +56516,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56447,7 +56542,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/open-api3-1.8.x-server.json b/app/config/specs/open-api3-1.8.x-server.json index 89ad0cb0ff..016d44fbc4 100644 --- a/app/config/specs/open-api3-1.8.x-server.json +++ b/app/config/specs/open-api3-1.8.x-server.json @@ -9217,6 +9217,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -9442,6 +9447,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -10541,6 +10551,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11007,6 +11022,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -30357,6 +30377,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -30588,6 +30613,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -31694,6 +31724,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -32164,6 +32199,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42407,6 +42447,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42429,7 +42475,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -42490,6 +42537,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42510,7 +42563,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -42571,6 +42625,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42591,7 +42651,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -42652,6 +42713,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42672,7 +42739,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -44228,6 +44296,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44250,7 +44324,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -44311,6 +44386,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44331,7 +44412,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -44392,6 +44474,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44412,7 +44500,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -44473,6 +44562,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44493,7 +44588,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index 91975d2d2e..b57aea9ddc 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -9721,6 +9721,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -9944,6 +9949,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11034,6 +11044,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11496,6 +11511,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -40701,6 +40721,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -40930,6 +40955,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42027,6 +42057,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42493,6 +42528,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -54361,6 +54401,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54383,7 +54429,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -54444,6 +54491,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54464,7 +54517,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -54525,6 +54579,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54545,7 +54605,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -54606,6 +54667,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -54626,7 +54693,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -56182,6 +56250,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56204,7 +56278,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -56265,6 +56340,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56285,7 +56366,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -56346,6 +56428,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56366,7 +56454,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -56427,6 +56516,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -56447,7 +56542,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 89ad0cb0ff..016d44fbc4 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -9217,6 +9217,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -9442,6 +9447,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -10541,6 +10551,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -11007,6 +11022,11 @@ "type": "boolean", "description": "Is attribute an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "x-example": false } }, "required": [ @@ -30357,6 +30377,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -30588,6 +30613,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -31694,6 +31724,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -32164,6 +32199,11 @@ "type": "boolean", "description": "Is column an array?", "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "x-example": false } }, "required": [ @@ -42407,6 +42447,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42429,7 +42475,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -42490,6 +42537,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42510,7 +42563,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -42571,6 +42625,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42591,7 +42651,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -42652,6 +42713,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -42672,7 +42739,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -44228,6 +44296,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44250,7 +44324,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -44311,6 +44386,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44331,7 +44412,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -44392,6 +44474,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44412,7 +44500,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -44473,6 +44562,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "nullable": true } }, "required": [ @@ -44493,7 +44588,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/swagger2-1.8.x-console.json b/app/config/specs/swagger2-1.8.x-console.json index 41b48860a1..06673c7ad9 100644 --- a/app/config/specs/swagger2-1.8.x-console.json +++ b/app/config/specs/swagger2-1.8.x-console.json @@ -9803,6 +9803,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -10023,6 +10029,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11076,6 +11088,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11533,6 +11551,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -40692,6 +40716,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -40918,6 +40948,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -41978,6 +42014,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -42439,6 +42481,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -54165,6 +54213,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54187,7 +54241,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -54248,6 +54303,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54268,7 +54329,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -54329,6 +54391,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54349,7 +54417,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -54410,6 +54479,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54430,7 +54505,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -55987,6 +56063,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56009,7 +56091,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -56070,6 +56153,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56090,7 +56179,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -56151,6 +56241,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56171,7 +56267,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -56232,6 +56329,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56252,7 +56355,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/swagger2-1.8.x-server.json b/app/config/specs/swagger2-1.8.x-server.json index 29262b5dd9..d61880e9b8 100644 --- a/app/config/specs/swagger2-1.8.x-server.json +++ b/app/config/specs/swagger2-1.8.x-server.json @@ -9283,6 +9283,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -9505,6 +9511,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -10567,6 +10579,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11028,6 +11046,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -30404,6 +30428,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -30632,6 +30662,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -31701,6 +31737,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -32166,6 +32208,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -42308,6 +42356,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42330,7 +42384,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -42391,6 +42446,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42411,7 +42472,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -42472,6 +42534,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42492,7 +42560,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -42553,6 +42622,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42573,7 +42648,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -44130,6 +44206,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44152,7 +44234,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -44213,6 +44296,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44233,7 +44322,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -44294,6 +44384,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44314,7 +44410,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -44375,6 +44472,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44395,7 +44498,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 41b48860a1..06673c7ad9 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -9803,6 +9803,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -10023,6 +10029,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11076,6 +11088,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11533,6 +11551,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -40692,6 +40716,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -40918,6 +40948,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -41978,6 +42014,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -42439,6 +42481,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -54165,6 +54213,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54187,7 +54241,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -54248,6 +54303,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54268,7 +54329,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -54329,6 +54391,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54349,7 +54417,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -54410,6 +54479,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -54430,7 +54505,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -55987,6 +56063,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56009,7 +56091,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -56070,6 +56153,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56090,7 +56179,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -56151,6 +56241,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56171,7 +56267,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -56232,6 +56329,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -56252,7 +56355,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 29262b5dd9..d61880e9b8 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -9283,6 +9283,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -9505,6 +9511,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -10567,6 +10579,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -11028,6 +11046,12 @@ "description": "Is attribute an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the attribute. Encryption enhances security by not storing any plain text values in the database. However, encrypted attributes cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -30404,6 +30428,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -30632,6 +30662,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -31701,6 +31737,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -32166,6 +32208,12 @@ "description": "Is column an array?", "default": false, "x-example": false + }, + "encrypt": { + "type": "boolean", + "description": "Toggle encryption for the column. Encryption enhances security by not storing any plain text values in the database. However, encrypted columns cannot be queried.", + "default": false, + "x-example": false } }, "required": [ @@ -42308,6 +42356,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42330,7 +42384,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "attributeText": { @@ -42391,6 +42446,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42411,7 +42472,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeMediumtext": { @@ -42472,6 +42534,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42492,7 +42560,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "attributeLongtext": { @@ -42553,6 +42622,12 @@ "description": "Default value for attribute when not provided. Cannot be set when attribute is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this attribute is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -42573,7 +42648,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "table": { @@ -44130,6 +44206,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44152,7 +44234,8 @@ "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", "size": 128, - "default": "default" + "default": "default", + "encrypt": false } }, "columnText": { @@ -44213,6 +44296,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44233,7 +44322,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnMediumtext": { @@ -44294,6 +44384,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44314,7 +44410,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "columnLongtext": { @@ -44375,6 +44472,12 @@ "description": "Default value for column when not provided. Cannot be set when column is required.", "x-example": "default", "x-nullable": true + }, + "encrypt": { + "type": "boolean", + "description": "Defines whether this column is encrypted or not.", + "x-example": false, + "x-nullable": true } }, "required": [ @@ -44395,7 +44498,8 @@ "array": false, "$createdAt": "2020-10-15T06:38:00.000+00:00", "$updatedAt": "2020-10-15T06:38:00.000+00:00", - "default": "default" + "default": "default", + "encrypt": false } }, "index": { diff --git a/composer.lock b/composer.lock index f522fc29ca..6a629fff1e 100644 --- a/composer.lock +++ b/composer.lock @@ -3797,16 +3797,16 @@ }, { "name": "utopia-php/database", - "version": "5.1.1", + "version": "5.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "94815bfa605282096272625827d0314f9ed99066" + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/94815bfa605282096272625827d0314f9ed99066", - "reference": "94815bfa605282096272625827d0314f9ed99066", + "url": "https://api.github.com/repos/utopia-php/database/zipball/5c89b39de00f2b3126d0fbbdea36786341293df7", + "reference": "5c89b39de00f2b3126d0fbbdea36786341293df7", "shasum": "" }, "require": { @@ -3849,9 +3849,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/5.1.1" + "source": "https://github.com/utopia-php/database/tree/5.2.0" }, - "time": "2026-02-12T11:44:58+00:00" + "time": "2026-02-14T09:37:28+00:00" }, { "name": "utopia-php/detector", @@ -4909,16 +4909,16 @@ }, { "name": "utopia-php/span", - "version": "1.1.4", + "version": "1.1.5", "source": { "type": "git", "url": "https://github.com/utopia-php/span.git", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c" + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/span/zipball/49d04aa588a2cdbbc9381ee7a1c129469e0f905c", - "reference": "49d04aa588a2cdbbc9381ee7a1c129469e0f905c", + "url": "https://api.github.com/repos/utopia-php/span/zipball/028406940ca92bdc88099f0b1a123a3b2cbdd4e5", + "reference": "028406940ca92bdc88099f0b1a123a3b2cbdd4e5", "shasum": "" }, "require": { @@ -4947,9 +4947,9 @@ "description": "Simple span tracing library for PHP with coroutine support", "support": { "issues": "https://github.com/utopia-php/span/issues", - "source": "https://github.com/utopia-php/span/tree/1.1.4" + "source": "https://github.com/utopia-php/span/tree/1.1.5" }, - "time": "2026-02-13T10:58:12+00:00" + "time": "2026-02-13T18:00:11+00:00" }, { "name": "utopia-php/storage", @@ -5390,16 +5390,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.9.0", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0" + "reference": "74de906ea5051030c5299a5d4aa74d963a531130" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", - "reference": "94a2d7ef55ea63c6e8afb166d39a82c07d01c8c0", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/74de906ea5051030c5299a5d4aa74d963a531130", + "reference": "74de906ea5051030c5299a5d4aa74d963a531130", "shasum": "" }, "require": { @@ -5435,9 +5435,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.9.0" + "source": "https://github.com/appwrite/sdk-generator/tree/1.9.2" }, - "time": "2026-02-12T12:08:13+00:00" + "time": "2026-02-16T06:59:54+00:00" }, { "name": "doctrine/annotations", From 0eb00934f6e140505d3efdad368fe23c57bb6092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 13:28:40 +0100 Subject: [PATCH 26/40] Fix race condition --- .../Modules/Functions/Workers/Builds.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index aaa5baf3cf..3bbb2924fa 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -932,16 +932,6 @@ class Builds extends Action $this->runGitAction('ready', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform, $queueForRealtime, $platform); } - /** Screenshot site */ - if ($resource->getCollection() === 'sites') { - $queueForScreenshots - ->setDeploymentId($deployment->getId()) - ->setProject($project) - ->trigger(); - - Console::log('Site screenshot queued'); - } - /** Set auto deploy */ $activateBuild = false; if ($deployment->getAttribute('activate') === true) { @@ -1022,6 +1012,16 @@ class Builds extends Action Console::log('Deployment activated'); } + + /** Screenshot site */ + if ($resource->getCollection() === 'sites') { + $queueForScreenshots + ->setDeploymentId($deployment->getId()) + ->setProject($project) + ->trigger(); + + Console::log('Site screenshot queued'); + } $this->afterDeploymentSuccess( $project, From 7bcc27ed07a4dd1ae9bb6223c1fc7c2e8cf463da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 13:31:36 +0100 Subject: [PATCH 27/40] Fix linter --- src/Appwrite/Platform/Modules/Functions/Workers/Builds.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php index 3bbb2924fa..0245084b5e 100644 --- a/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php +++ b/src/Appwrite/Platform/Modules/Functions/Workers/Builds.php @@ -1012,7 +1012,7 @@ class Builds extends Action Console::log('Deployment activated'); } - + /** Screenshot site */ if ($resource->getCollection() === 'sites') { $queueForScreenshots From 79a0b33b92d097e8495378b102a40cd643d9ae30 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 16 Feb 2026 18:46:55 +0530 Subject: [PATCH 28/40] Set project on queueForMails so span logs include project context The Mails worker span logs were missing project.id, project.sequence, project.region, and project.database because setProject was never called on queueForMails. This adds setProject in the shared API controller and in workers (Webhooks, Migrations) that trigger mails. Also injects project into the Mails worker action. --- app/controllers/shared/api.php | 1 + src/Appwrite/Platform/Workers/Mails.php | 4 +++- src/Appwrite/Platform/Workers/Migrations.php | 1 + src/Appwrite/Platform/Workers/Webhooks.php | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index f25f9717ed..378c5d5c9c 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -496,6 +496,7 @@ Http::init() $queueForMessaging->setProject($project); $queueForFunctions->setProject($project); $queueForBuilds->setProject($project); + $queueForMails->setProject($project); /* Auto-set platforms */ $queueForFunctions->setPlatform($platform); diff --git a/src/Appwrite/Platform/Workers/Mails.php b/src/Appwrite/Platform/Workers/Mails.php index b1f17fc648..72f7cddd06 100644 --- a/src/Appwrite/Platform/Workers/Mails.php +++ b/src/Appwrite/Platform/Workers/Mails.php @@ -6,6 +6,7 @@ use Appwrite\Template\Template; use Exception; use PHPMailer\PHPMailer\PHPMailer; use Swoole\Runtime; +use Utopia\Database\Document; use Utopia\Logger\Log; use Utopia\Platform\Action; use Utopia\Queue\Message; @@ -32,6 +33,7 @@ class Mails extends Action $this ->desc('Mails worker') ->inject('message') + ->inject('project') ->inject('register') ->inject('log') ->callback($this->action(...)); @@ -53,7 +55,7 @@ class Mails extends Action * @return void * @throws Exception */ - public function action(Message $message, Registry $register, Log $log): void + public function action(Message $message, Document $project, Registry $register, Log $log): void { Runtime::setHookFlags(SWOOLE_HOOK_ALL ^ SWOOLE_HOOK_TCP); $payload = $message->getPayload() ?? []; diff --git a/src/Appwrite/Platform/Workers/Migrations.php b/src/Appwrite/Platform/Workers/Migrations.php index c6b005c334..94cbcf341c 100644 --- a/src/Appwrite/Platform/Workers/Migrations.php +++ b/src/Appwrite/Platform/Workers/Migrations.php @@ -735,6 +735,7 @@ class Migrations extends Action ]; $queueForMails + ->setProject($project) ->setSubject($subject) ->setPreview($preview) ->setBody($emailBody) diff --git a/src/Appwrite/Platform/Workers/Webhooks.php b/src/Appwrite/Platform/Workers/Webhooks.php index dbfbe591a6..56839058de 100644 --- a/src/Appwrite/Platform/Workers/Webhooks.php +++ b/src/Appwrite/Platform/Workers/Webhooks.php @@ -253,6 +253,7 @@ class Webhooks extends Action ->setParam('{{year}}', date("Y")); $queueForMails + ->setProject($project) ->setSubject($subject) ->setPreview($preview) ->setBody($body->render()); From c7bbf6a987a6e5cd39b9e29bf59e7c88197d0afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 16:14:43 +0100 Subject: [PATCH 29/40] fix org keys auth --- app/controllers/shared/api.php | 10 ++++++++-- app/init/resources.php | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 378c5d5c9c..7e4cff32f4 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -169,8 +169,10 @@ Http::init() // Handle special app role case if ($apiKey->getRole() === User::ROLE_APPS) { - // Disable authorization checks for API keys - $authorization->setDefaultStatus(false); + // Disable authorization checks for project API keys + if ($project->getId() !== 'console') { + $authorization->setDefaultStatus(false); + } $user = new User([ '$id' => '', @@ -245,6 +247,10 @@ Http::init() } } + $authorization->addRole(Role::team($team->getId())->toString()); + $authorization->addRole(Role::team($team->getId(), 'owner')->toString()); + $authorization->addRole(Role::member($team->getId())->toString()); + $queueForAudits->setUser($user); } } // Admin User Authentication diff --git a/app/init/resources.php b/app/init/resources.php index cdc2e8a367..b2a7a0189d 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -1304,6 +1304,7 @@ Http::setResource('team', function (Document $project, Database $dbForPlatform, } else { $route = $utopia->match($request); $path = !empty($route) ? $route->getPath() : $request->getURI(); + $orgHeader = $request->getHeader('x-appwrite-organization', ''); if (str_starts_with($path, '/v1/projects/:projectId')) { $uri = $request->getURI(); $pid = explode('/', $uri)[3]; @@ -1318,6 +1319,8 @@ Http::setResource('team', function (Document $project, Database $dbForPlatform, $team = $authorization->skip(fn () => $dbForPlatform->getDocument('teams', $teamId)); return $team; + } elseif (!empty($orgHeader)) { + return $authorization->skip(fn () => $dbForPlatform->getDocument('teams', $orgHeader)); } } From 4b084849206e5f2b637dc5f0ea7c0ea1be5a2311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 16:24:33 +0100 Subject: [PATCH 30/40] Fix tests --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 7e4cff32f4..15cd925f27 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -170,7 +170,7 @@ Http::init() // Handle special app role case if ($apiKey->getRole() === User::ROLE_APPS) { // Disable authorization checks for project API keys - if ($project->getId() !== 'console') { + if ($apiKey->getType() === API_KEY_STANDARD && $apiKey->getProjectId() === $project->getId()) { $authorization->setDefaultStatus(false); } From 57127d40da3c43267a09e49adc4ff57d8f95aeb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 16:47:19 +0100 Subject: [PATCH 31/40] Fix failing tests --- docker-compose.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 5a6367f402..ab33920060 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -750,6 +750,12 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE From 13edcbaf6f257d44b0b83e2d1cf0db51ce88bb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 17:06:11 +0100 Subject: [PATCH 32/40] fix abuse test; fix mail-related tests --- tests/e2e/Services/Projects/ProjectsConsoleClientTest.php | 4 ++-- tests/resources/docker/docker-compose.yml | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 1d15f10971..64556522f5 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -5384,8 +5384,8 @@ class ProjectsConsoleClientTest extends Scope ], [ 'success' => 'https://example.com', 'failure' => 'https://example.com' - ]); - $this->assertEquals(200, $response['headers']['status-code']); + ], followRedirects: false); + $this->assertEquals(301, $response['headers']['status-code']); /** Ensure any hostname is allowed */ $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, [ diff --git a/tests/resources/docker/docker-compose.yml b/tests/resources/docker/docker-compose.yml index 8530df0db6..02593f8123 100644 --- a/tests/resources/docker/docker-compose.yml +++ b/tests/resources/docker/docker-compose.yml @@ -279,6 +279,12 @@ services: - _APP_ENV - _APP_REDIS_HOST - _APP_REDIS_PORT + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_DB_ADAPTER - _APP_SMTP_HOST - _APP_SMTP_PORT From bb26a9f583eb20fca0feaadc8a3a82e48a188a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 17:18:58 +0100 Subject: [PATCH 33/40] improve devkey test for oauth --- docker-compose.yml | 1 + .../Projects/ProjectsConsoleClientTest.php | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ab33920060..635b1cb2cf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -738,6 +738,7 @@ services: depends_on: - redis - maildev + - ${_APP_DB_HOST:-mariadb} # - smtp environment: - _APP_ENV diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 64556522f5..4eccad4966 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -5376,7 +5376,7 @@ class ProjectsConsoleClientTest extends Scope ]); $this->assertEquals(400, $response['headers']['status-code']); - /** Test oauth2 with devKey and now get oauth2 is disabled */ + /** Test oauth2 with devKey and now flow works with untrusted URL too */ $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, @@ -5385,7 +5385,36 @@ class ProjectsConsoleClientTest extends Scope 'success' => 'https://example.com', 'failure' => 'https://example.com' ], followRedirects: false); + $this->assertEquals(301, $response['headers']['status-code']); + $this->assertArrayHasKey('location', $response['headers']); + + $location = $response['headers']['location']; + + + $locationClient = new Client(); + $locationClient->setEndpoint(''); + $locationClient->addHeader('x-appwrite-dev-key', $devKey['secret']); + + $response = $locationClient->call(Client::METHOD_GET, $location, followRedirects: false); + + $this->assertEquals(301, $response['headers']['status-code']); + $this->assertArrayHasKey('location', $response['headers']); + + $location = $response['headers']['location']; + $this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/callback/mock/', $response['headers']['location']); + + $response = $locationClient->call(Client::METHOD_GET, $location, followRedirects: false); + $this->assertEquals(301, $response['headers']['status-code']); + $this->assertArrayHasKey('location', $response['headers']); + + $location = $response['headers']['location']; + $this->assertStringStartsWith('http://appwrite:/v1/account/sessions/oauth2/mock/redirect', $response['headers']['location']); + + $response = $locationClient->call(Client::METHOD_GET, $location, followRedirects: false); + + $this->assertEquals(301, $response['headers']['status-code']); + $this->assertSame('https://example.com/#', $response['headers']['location']); /** Ensure any hostname is allowed */ $response = $this->client->call(Client::METHOD_GET, '/account/sessions/oauth2/' . $provider, [ From 46ed91fe487e45b3a5b8a0ea4303469ff369defb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 17:39:12 +0100 Subject: [PATCH 34/40] Fix migratons with api keys --- app/controllers/shared/api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 15cd925f27..1b9726ded5 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -170,7 +170,7 @@ Http::init() // Handle special app role case if ($apiKey->getRole() === User::ROLE_APPS) { // Disable authorization checks for project API keys - if ($apiKey->getType() === API_KEY_STANDARD && $apiKey->getProjectId() === $project->getId()) { + if (($apiKey->getType() === API_KEY_STANDARD || $apiKey->getType() === API_KEY_DYNAMIC) && $apiKey->getProjectId() === $project->getId()) { $authorization->setDefaultStatus(false); } From 180ac93871f5a3df89c557652d2c2857b11e290a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 17:48:26 +0100 Subject: [PATCH 35/40] Fix accoutn keys permissions --- app/controllers/shared/api.php | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 1b9726ded5..1596607446 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -30,6 +30,7 @@ use Utopia\Database\Document; use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Authorization\Input; +use Utopia\Database\Validator\Roles; use Utopia\Http\Http; use Utopia\System\System; use Utopia\Telemetry\Adapter as Telemetry; @@ -247,11 +248,37 @@ Http::init() } } + $queueForAudits->setUser($user); + } + + // Apply permission + if ($apiKey->getType() === API_KEY_ORGANIZATION) { $authorization->addRole(Role::team($team->getId())->toString()); $authorization->addRole(Role::team($team->getId(), 'owner')->toString()); $authorization->addRole(Role::member($team->getId())->toString()); + } elseif ($apiKey->getType() === API_KEY_ACCOUNT) { + $authorization->addRole(Role::user($user->getId())->toString()); + $authorization->addRole(Role::users()->toString()); - $queueForAudits->setUser($user); + if ($user->getAttribute('emailVerification', false) && $user->getAttribute('phoneVerification', false)) { + $authorization->addRole(Role::user($user->getId(), Roles::DIMENSION_VERIFIED)->toString()); + $authorization->addRole(Role::users(Roles::DIMENSION_VERIFIED)->toString()); + } else { + $authorization->addRole(Role::user($user->getId(), Roles::DIMENSION_UNVERIFIED)->toString()); + $authorization->addRole(Role::users(Roles::DIMENSION_UNVERIFIED)->toString()); + } + + foreach (\array_filter($user->getAttribute('memberships', []), fn ($membership) => !isset($membership['confirm']) || !$membership['confirm']) as $nodeMembership) { + $authorization->addRole(Role::team($nodeMembership['teamId'])->toString()); + $authorization->addRole(Role::member($nodeMembership->getId())->toString()); + foreach (($node['roles'] ?? []) as $nodeRole) { + $authorization->addRole(Role::team($nodeMembership['teamId'], $nodeRole)->toString()); + } + } + + foreach ($user->getAttribute('labels', []) as $nodeLabel) { + $authorization->addRole('label:' . $nodeLabel); + } } } // Admin User Authentication elseif (($project->getId() === 'console' && !$team->isEmpty() && !$user->isEmpty()) || ($project->getId() !== 'console' && !$user->isEmpty() && $mode === APP_MODE_ADMIN)) { From 343bed9b9dbdf22c092565f38f1b7c46d24897cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 17:59:44 +0100 Subject: [PATCH 36/40] PR review fixes --- app/controllers/shared/api.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 1596607446..1c0c7a89dc 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -255,7 +255,6 @@ Http::init() if ($apiKey->getType() === API_KEY_ORGANIZATION) { $authorization->addRole(Role::team($team->getId())->toString()); $authorization->addRole(Role::team($team->getId(), 'owner')->toString()); - $authorization->addRole(Role::member($team->getId())->toString()); } elseif ($apiKey->getType() === API_KEY_ACCOUNT) { $authorization->addRole(Role::user($user->getId())->toString()); $authorization->addRole(Role::users()->toString()); @@ -268,7 +267,7 @@ Http::init() $authorization->addRole(Role::users(Roles::DIMENSION_UNVERIFIED)->toString()); } - foreach (\array_filter($user->getAttribute('memberships', []), fn ($membership) => !isset($membership['confirm']) || !$membership['confirm']) as $nodeMembership) { + foreach (\array_filter($user->getAttribute('memberships', []), fn ($membership) => ($membership['confirm'] ?? false) === true) as $nodeMembership) { $authorization->addRole(Role::team($nodeMembership['teamId'])->toString()); $authorization->addRole(Role::member($nodeMembership->getId())->toString()); foreach (($node['roles'] ?? []) as $nodeRole) { From 9572201863369060cf6bbf86d7148ea6b605c2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 16 Feb 2026 18:08:52 +0100 Subject: [PATCH 37/40] AI review fixes --- app/controllers/shared/api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index 1c0c7a89dc..2c0c61332c 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -259,7 +259,7 @@ Http::init() $authorization->addRole(Role::user($user->getId())->toString()); $authorization->addRole(Role::users()->toString()); - if ($user->getAttribute('emailVerification', false) && $user->getAttribute('phoneVerification', false)) { + if ($user->getAttribute('emailVerification', false) || $user->getAttribute('phoneVerification', false)) { $authorization->addRole(Role::user($user->getId(), Roles::DIMENSION_VERIFIED)->toString()); $authorization->addRole(Role::users(Roles::DIMENSION_VERIFIED)->toString()); } else { @@ -270,7 +270,7 @@ Http::init() foreach (\array_filter($user->getAttribute('memberships', []), fn ($membership) => ($membership['confirm'] ?? false) === true) as $nodeMembership) { $authorization->addRole(Role::team($nodeMembership['teamId'])->toString()); $authorization->addRole(Role::member($nodeMembership->getId())->toString()); - foreach (($node['roles'] ?? []) as $nodeRole) { + foreach (($nodeMembership['roles'] ?? []) as $nodeRole) { $authorization->addRole(Role::team($nodeMembership['teamId'], $nodeRole)->toString()); } } From d8bf3acaeda62846be2f39e8d3e7103b45d33a2b Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:00:23 +0000 Subject: [PATCH 38/40] test: add e2e tests for listing string type attributes Co-Authored-By: Claude Opus 4.6 --- .../Legacy/DatabasesStringTypesTest.php | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php b/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php index 8b7886b864..d1ea6ae921 100644 --- a/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php +++ b/tests/e2e/Services/Databases/Legacy/DatabasesStringTypesTest.php @@ -514,6 +514,63 @@ class DatabasesStringTypesTest extends Scope /** * @depends testCreateLongtextAttribute */ + public function testListStringTypeAttributes(array $data): array + { + $databaseId = $data['databaseId']; + $collectionId = $data['collectionId']; + + // Wait for attributes to be created + sleep(2); + + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $attributes = $response['body']['attributes']; + $types = array_column($attributes, 'type'); + + $this->assertContains('varchar', $types); + $this->assertContains('text', $types); + $this->assertContains('mediumtext', $types); + $this->assertContains('longtext', $types); + + return $data; + } + + /** + * @depends testListStringTypeAttributes + */ + public function testGetCollectionWithStringTypeAttributes(array $data): array + { + $databaseId = $data['databaseId']; + $collectionId = $data['collectionId']; + + $response = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + + $attributes = $response['body']['attributes']; + $types = array_column($attributes, 'type'); + + $this->assertContains('varchar', $types); + $this->assertContains('text', $types); + $this->assertContains('mediumtext', $types); + $this->assertContains('longtext', $types); + + return $data; + } + + /** + * @depends testGetCollectionWithStringTypeAttributes + */ public function testUpdateVarcharAttribute(array $data): array { $this->markTestSkipped('Skipped until utopia-php/database updateAttribute supports VARCHAR type'); From 953c0cd4b4b34ff89db705944da26ac23a110d57 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:29:56 +0000 Subject: [PATCH 39/40] fix: add missing string type models to AttributeList and Collection Co-Authored-By: Claude Opus 4.6 --- src/Appwrite/Utopia/Response/Model/AttributeList.php | 4 ++++ src/Appwrite/Utopia/Response/Model/Collection.php | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index 6b9a7365bd..0b17a655ab 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -30,6 +30,10 @@ class AttributeList extends Model Response::MODEL_ATTRIBUTE_POINT, Response::MODEL_ATTRIBUTE_LINE, Response::MODEL_ATTRIBUTE_POLYGON, + Response::MODEL_ATTRIBUTE_VARCHAR, + Response::MODEL_ATTRIBUTE_TEXT, + Response::MODEL_ATTRIBUTE_MEDIUMTEXT, + Response::MODEL_ATTRIBUTE_LONGTEXT, Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'List of attributes.', diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php index 407db3aea9..4ab7de8e4d 100644 --- a/src/Appwrite/Utopia/Response/Model/Collection.php +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -73,6 +73,10 @@ class Collection extends Model Response::MODEL_ATTRIBUTE_POINT, Response::MODEL_ATTRIBUTE_LINE, Response::MODEL_ATTRIBUTE_POLYGON, + Response::MODEL_ATTRIBUTE_VARCHAR, + Response::MODEL_ATTRIBUTE_TEXT, + Response::MODEL_ATTRIBUTE_MEDIUMTEXT, + Response::MODEL_ATTRIBUTE_LONGTEXT, Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'Collection attributes.', From 9b4eefc72455c5f749c3f77512862edd46ca964e Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Tue, 17 Feb 2026 19:00:26 +1300 Subject: [PATCH 40/40] Allow resourceId/resourceType filtering --- src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php index 436a95534b..c49788872e 100644 --- a/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Migrations.php @@ -10,6 +10,8 @@ class Migrations extends Base 'source', 'destination', 'resources', + 'resourceId', + 'resourceType', 'statusCounters', 'resourceData', 'errors'